22// Licensed under the MIT License.
33
44using System ;
5+ using System . Collections . Generic ;
56using System . Threading ;
67using Azure . Core ;
78using Azure . Core . Pipeline ;
@@ -13,10 +14,14 @@ namespace Azure
1314 /// </summary>
1415 public class RequestOptions
1516 {
17+ private List < HttpMessageClassifier > ? _classifiers ;
18+
1619 /// <summary>
1720 /// Initializes a new instance of the <see cref="RequestOptions"/> class.
1821 /// </summary>
19- public RequestOptions ( ) { }
22+ public RequestOptions ( )
23+ {
24+ }
2025
2126 /// <summary>
2227 /// Initializes a new instance of the <see cref="RequestOptions"/> class using the given <see cref="RequestOptions"/>.
@@ -30,6 +35,48 @@ public RequestOptions() { }
3035 /// <param name="perCall"></param>
3136 public RequestOptions ( Action < HttpMessage > perCall ) => PerCallPolicy = new ActionPolicy ( perCall ) ;
3237
38+ /// <summary>
39+ /// Initializes a new instance of the <see cref="RequestOptions"/> class.
40+ /// </summary>
41+ /// <param name="treatAsSuccess">The status codes to treat as successful.</param>
42+ public RequestOptions ( params int [ ] treatAsSuccess ) : this ( treatAsSuccess , ResponseClassification . Success )
43+ {
44+ }
45+
46+ /// <summary>
47+ /// Initializes a new instance of the <see cref="RequestOptions"/> class.
48+ /// Applying provided classification to a set of status codes.
49+ /// </summary>
50+ /// <param name="statusCodes">The status codes to classify.</param>
51+ /// <param name="classification">The classification.</param>
52+ public RequestOptions ( int [ ] statusCodes , ResponseClassification classification )
53+ {
54+ AddClassifier ( statusCodes , classification ) ;
55+ }
56+
57+ /// <summary>
58+ /// Adds the classification for provided status codes.
59+ /// </summary>
60+ /// <param name="statusCodes">The status codes to classify.</param>
61+ /// <param name="classification">The classification.</param>
62+ public void AddClassifier ( int [ ] statusCodes , ResponseClassification classification )
63+ {
64+ foreach ( var statusCode in statusCodes )
65+ {
66+ AddClassifier ( message => message . Response . Status == statusCode ? classification : null ) ;
67+ }
68+ }
69+
70+ /// <summary>
71+ /// Adds a function that allows to specify how response would be processed by the pipeline.
72+ /// </summary>
73+ /// <param name="classifier"></param>
74+ public void AddClassifier ( Func < HttpMessage , ResponseClassification ? > classifier )
75+ {
76+ _classifiers ??= new ( ) ;
77+ _classifiers . Add ( new FuncHttpMessageClassifier ( classifier ) ) ;
78+ }
79+
3380 /// <summary>
3481 /// Initializes a new instance of the <see cref="RequestOptions"/> class using the given <see cref="ResponseStatusOption"/>.
3582 /// </summary>
@@ -52,6 +99,24 @@ public RequestOptions() { }
5299 /// </summary>
53100 public HttpPipelinePolicy ? PerCallPolicy { get ; set ; }
54101
102+ /// <summary>
103+ /// Applies options from <see cref="RequestOptions"/> instance to a <see cref="HttpMessage"/>.
104+ /// </summary>
105+ /// <param name="requestOptions"></param>
106+ /// <param name="message"></param>
107+ public static void Apply ( RequestOptions requestOptions , HttpMessage message )
108+ {
109+ if ( requestOptions . PerCallPolicy != null )
110+ {
111+ message . SetProperty ( "RequestOptionsPerCallPolicyCallback" , requestOptions . PerCallPolicy ) ;
112+ }
113+
114+ if ( requestOptions . _classifiers != null )
115+ {
116+ message . ResponseClassifier = new PerCallResponseClassifier ( message . ResponseClassifier , requestOptions . _classifiers ) ;
117+ }
118+ }
119+
55120 /// <summary>
56121 /// An <see cref="HttpPipelineSynchronousPolicy"/> which invokes an action when a request is being sent.
57122 /// </summary>
@@ -63,5 +128,112 @@ internal class ActionPolicy : HttpPipelineSynchronousPolicy
63128
64129 public override void OnSendingRequest ( HttpMessage message ) => Action . Invoke ( message ) ;
65130 }
131+
132+ private class PerCallResponseClassifier : ResponseClassifier
133+ {
134+ private readonly ResponseClassifier _inner ;
135+ private readonly List < HttpMessageClassifier > _classifiers ;
136+
137+ public PerCallResponseClassifier ( ResponseClassifier inner , List < HttpMessageClassifier > classifiers )
138+ {
139+ _inner = inner ;
140+ _classifiers = classifiers ;
141+ }
142+
143+ public override bool IsRetriableResponse ( HttpMessage message )
144+ {
145+ if ( Applies ( message , ResponseClassification . DontRetry ) ) return false ;
146+ if ( Applies ( message , ResponseClassification . Retry ) ) return true ;
147+
148+ return _inner . IsRetriableResponse ( message ) ;
149+ }
150+
151+ public override bool IsRetriableException ( Exception exception )
152+ {
153+ return _inner . IsRetriableException ( exception ) ;
154+ }
155+
156+ public override bool IsRetriable ( HttpMessage message , Exception exception )
157+ {
158+ if ( Applies ( message , ResponseClassification . DontRetry ) ) return false ;
159+
160+ return _inner . IsRetriable ( message , exception ) ;
161+ }
162+
163+ public override bool IsErrorResponse ( HttpMessage message )
164+ {
165+ if ( Applies ( message , ResponseClassification . Throw ) ) return true ;
166+ if ( Applies ( message , ResponseClassification . Success ) ) return false ;
167+
168+ return _inner . IsErrorResponse ( message ) ;
169+ }
170+
171+ private bool Applies ( HttpMessage message , ResponseClassification responseClassification )
172+ {
173+ foreach ( var classifier in _classifiers )
174+ {
175+ if ( classifier . TryClassify ( message , null , out var c ) &&
176+ c == responseClassification )
177+ {
178+ return true ;
179+ }
180+ }
181+
182+ return false ;
183+ }
184+ }
185+
186+ private abstract class HttpMessageClassifier
187+ {
188+ public abstract bool TryClassify ( HttpMessage message , Exception ? exception , out ResponseClassification classification ) ;
189+ }
190+
191+ private class FuncHttpMessageClassifier : HttpMessageClassifier
192+ {
193+ private readonly Func < HttpMessage , ResponseClassification ? > _func ;
194+
195+ public FuncHttpMessageClassifier ( Func < HttpMessage , ResponseClassification ? > func )
196+ {
197+ _func = func ;
198+ }
199+
200+ public override bool TryClassify ( HttpMessage message , Exception ? exception , out ResponseClassification classification )
201+ {
202+ if ( _func ( message ) is ResponseClassification c )
203+ {
204+ classification = c ;
205+ return true ;
206+ }
207+
208+ classification = default ;
209+ return false ;
210+ }
211+ }
212+ }
213+
214+ /// <summary>
215+ /// Specifies how response would be processed by the pipeline and the client.
216+ /// </summary>
217+ public enum ResponseClassification
218+ {
219+ /// <summary>
220+ /// The response would be retried.
221+ /// </summary>
222+ Retry ,
223+
224+ /// <summary>
225+ /// The response would be retried.
226+ /// </summary>
227+ DontRetry ,
228+
229+ /// <summary>
230+ /// The client would throw an exception for the response.
231+ /// </summary>
232+ Throw ,
233+
234+ /// <summary>
235+ /// The client would tread the response a successful.
236+ /// </summary>
237+ Success ,
66238 }
67- }
239+ }
0 commit comments