Left: | ||
Right: |
LEFT | RIGHT |
---|---|
1 /* | 1 /* |
2 Copyright 2013 Google Inc | 2 Copyright 2013 Google Inc |
3 | 3 |
4 Licensed under the Apache License, Version 2.0 (the "License"); | 4 Licensed under the Apache License, Version 2.0 (the "License"); |
5 you may not use this file except in compliance with the License. | 5 you may not use this file except in compliance with the License. |
6 You may obtain a copy of the License at | 6 You may obtain a copy of the License at |
7 | 7 |
8 http://www.apache.org/licenses/LICENSE-2.0 | 8 http://www.apache.org/licenses/LICENSE-2.0 |
9 | 9 |
10 Unless required by applicable law or agreed to in writing, software | 10 Unless required by applicable law or agreed to in writing, software |
(...skipping 15 matching lines...) Expand all Loading... | |
26 using Google.Apis.Logging; | 26 using Google.Apis.Logging; |
27 using Google.Apis.Testing; | 27 using Google.Apis.Testing; |
28 | 28 |
29 namespace Google.Apis.Http | 29 namespace Google.Apis.Http |
30 { | 30 { |
31 /// <summary> | 31 /// <summary> |
32 /// This message handler contains the main logic of our HTTP requests. It co ntains a list of· | 32 /// This message handler contains the main logic of our HTTP requests. It co ntains a list of· |
33 /// <see cref="IHttpUnsuccessfulResponseHandler"/>s for handling abnormal re sponses, a list of· | 33 /// <see cref="IHttpUnsuccessfulResponseHandler"/>s for handling abnormal re sponses, a list of· |
34 /// <see cref="IHttpExceptionHandler"/>s for handling exception in a request and a list of· | 34 /// <see cref="IHttpExceptionHandler"/>s for handling exception in a request and a list of· |
35 /// <see cref="IHttpExecuteInterceptor"/>s for intercepting a request before it has been sent to the server. | 35 /// <see cref="IHttpExecuteInterceptor"/>s for intercepting a request before it has been sent to the server. |
36 /// It also contains important properties like number of tires, follow redir ect, etc. | 36 /// It also contains important properties like number of tires, follow redir ect, etc. |
class
2013/09/21 03:12:10
Should this be number of retries?
peleyal
2013/09/23 12:01:16
tries
The property is NumTries.
On 2013/09/21 03
| |
37 /// </summary> | 37 /// </summary> |
38 public class ConfigurableMessageHandler : DelegatingHandler | 38 public class ConfigurableMessageHandler : DelegatingHandler |
39 { | 39 { |
40 /// <summary> The class logger. </summary> | 40 /// <summary>The class logger.</summary> |
41 private static readonly ILogger Logger = ApplicationContext.Logger.ForTy pe<ConfigurableMessageHandler>(); | 41 private static readonly ILogger Logger = ApplicationContext.Logger.ForTy pe<ConfigurableMessageHandler>(); |
42 | 42 |
43 /// <summary> Maximum allowed number of tries. </summary> | 43 /// <summary>Maximum allowed number of tries.</summary> |
44 [VisibleForTestOnly] | 44 [VisibleForTestOnly] |
45 internal const int MaxAllowedNumTries = 20; | 45 internal const int MaxAllowedNumTries = 20; |
46 | 46 |
47 /// <summary> The current API version of this client library. </summary> | 47 /// <summary>The current API version of this client library.</summary> |
48 private static readonly string ApiVersion = Google.Apis.Util.Utilities.G etLibraryVersion(); | 48 private static readonly string ApiVersion = Google.Apis.Util.Utilities.G etLibraryVersion(); |
49 | 49 |
50 /// <summary> The User-Agent suffix header which contains the <seealso c ref="ApiVersion"/>. </summary> | 50 /// <summary>The User-Agent suffix header which contains the <seealso cr ef="ApiVersion"/>.</summary> |
51 private static readonly string UserAgentSuffix = "google-api-dotnet-clie nt/" ApiVersion " (gzip)"; | 51 private static readonly string UserAgentSuffix = "google-api-dotnet-clie nt/" ApiVersion " (gzip)"; |
52 | 52 |
53 #region IHttpUnsuccessfulResponseHandler, IHttpExceptionHandler and IHtt pExecuteInterceptor lists | 53 #region IHttpUnsuccessfulResponseHandler, IHttpExceptionHandler and IHtt pExecuteInterceptor lists |
54 | 54 |
55 /// <summary> A list of <see cref="IHttpUnsuccessfulResponseHandler"/>. </summary> | 55 /// <summary>A list of <see cref="IHttpUnsuccessfulResponseHandler"/>.</ summary> |
56 private readonly IList<IHttpUnsuccessfulResponseHandler> unsuccessfulRes ponseHandlers = | 56 private readonly IList<IHttpUnsuccessfulResponseHandler> unsuccessfulRes ponseHandlers = |
57 new List<IHttpUnsuccessfulResponseHandler>(); | 57 new List<IHttpUnsuccessfulResponseHandler>(); |
58 | 58 |
59 /// <summary> A list of <see cref="IHttpExceptionHandler"/>. </summary> | 59 /// <summary>A list of <see cref="IHttpExceptionHandler"/>.</summary> |
60 private readonly IList<IHttpExceptionHandler> exceptionHandlers = | 60 private readonly IList<IHttpExceptionHandler> exceptionHandlers = |
61 new List<IHttpExceptionHandler>(); | 61 new List<IHttpExceptionHandler>(); |
62 | 62 |
63 /// <summary> A list of <see cref="IHttpExecuteInterceptor"/>. </summary > | 63 /// <summary>A list of <see cref="IHttpExecuteInterceptor"/>.</summary> |
64 private readonly IList<IHttpExecuteInterceptor> executeInterceptors = | 64 private readonly IList<IHttpExecuteInterceptor> executeInterceptors = |
65 new List<IHttpExecuteInterceptor>(); | 65 new List<IHttpExecuteInterceptor>(); |
66 | 66 |
67 /// <summary> Gets a list of <see cref="IHttpUnsuccessfulResponseHandler "/>. </summary> | 67 /// <summary>Gets a list of <see cref="IHttpUnsuccessfulResponseHandler" />.</summary> |
68 public IList<IHttpUnsuccessfulResponseHandler> UnsuccessfulResponseHandl ers | 68 public IList<IHttpUnsuccessfulResponseHandler> UnsuccessfulResponseHandl ers |
69 { | 69 { |
70 get { return unsuccessfulResponseHandlers; } | 70 get { return unsuccessfulResponseHandlers; } |
71 } | 71 } |
72 | 72 |
73 /// <summary> Gets a list of <see cref="IHttpExceptionHandler"/>. </summ ary> | 73 /// <summary>Gets a list of <see cref="IHttpExceptionHandler"/>.</summar y> |
74 public IList<IHttpExceptionHandler> ExceptionHandlers | 74 public IList<IHttpExceptionHandler> ExceptionHandlers |
75 { | 75 { |
76 get { return exceptionHandlers; } | 76 get { return exceptionHandlers; } |
77 } | 77 } |
78 | 78 |
79 /// <summary> Gets a list of <see cref="IHttpExecuteInterceptor"/>. </su mmary> | 79 /// <summary>Gets a list of <see cref="IHttpExecuteInterceptor"/>.</summ ary> |
80 public IList<IHttpExecuteInterceptor> ExecuteInterceptors | 80 public IList<IHttpExecuteInterceptor> ExecuteInterceptors |
81 { | 81 { |
82 get { return executeInterceptors; } | 82 get { return executeInterceptors; } |
83 } | 83 } |
84 | 84 |
85 #endregion | 85 #endregion |
86 | 86 |
87 /// <summary> Number of tries. Default is <c>3</c>. </summary> | 87 /// <summary>Number of tries. Default is <c>3</c>.</summary> |
88 private int numTries = 3; | 88 private int numTries = 3; |
89 | 89 |
90 /// <summary> | 90 /// <summary> |
91 /// Gets or sets the number of tries that will be allowed to execute. Re tries occur as a result of either | 91 /// Gets or sets the number of tries that will be allowed to execute. Re tries occur as a result of either |
92 /// <see cref="IHttpUnsuccessfulResponseHandler"/> or <see cref="IHttpEx ceptionHandler"/> which handles the | 92 /// <see cref="IHttpUnsuccessfulResponseHandler"/> or <see cref="IHttpEx ceptionHandler"/> which handles the |
93 /// abnormal Http response or exception, before being terminated.· | 93 /// abnormal HTTP response or exception, before being terminated.· |
94 /// Set <c>1</c> for not retrying requests. The default value is <c>3</c >". | 94 /// Set <c>1</c> for not retrying requests. The default value is <c>3</c >". |
95 /// </summary> | 95 /// </summary> |
96 public int NumTries | 96 public int NumTries |
97 { | 97 { |
98 get { return numTries; } | 98 get { return numTries; } |
99 set | 99 set |
100 { | 100 { |
101 if (value > MaxAllowedNumTries || value < 1) | 101 if (value > MaxAllowedNumTries || value < 1) |
102 { | 102 { |
103 throw new ArgumentOutOfRangeException("NumTries"); | 103 throw new ArgumentOutOfRangeException("NumTries"); |
104 } | 104 } |
105 numTries = value; | 105 numTries = value; |
106 } | 106 } |
107 } | 107 } |
108 | 108 |
109 /// <summary> | 109 /// <summary> |
110 /// Gets or sets whether the handler should follow a redirect when a red irect response is received. Default· | 110 /// Gets or sets whether the handler should follow a redirect when a red irect response is received. Default· |
111 /// value is <c>true</c>. | 111 /// value is <c>true</c>. |
112 /// </summary> | 112 /// </summary> |
113 public bool FollowRedirect { get; set; } | 113 public bool FollowRedirect { get; set; } |
114 | 114 |
115 /// <summary> Gets or sets whether logging is enabled. Default value is <c>true</c>. </summary> | 115 /// <summary>Gets or sets whether logging is enabled. Default value is < c>true</c>.</summary> |
116 public bool IsLoggingEnabled { get; set; } | 116 public bool IsLoggingEnabled { get; set; } |
117 | 117 |
118 /// <summary> Gets or sets the application name which will be used on th e User-Agent header. </summary> | 118 /// <summary>Gets or sets the application name which will be used on the User-Agent header.</summary> |
119 public string ApplicationName { get; set; } | 119 public string ApplicationName { get; set; } |
120 | 120 |
121 /// <summary> Constructs a new configurable message handler </summary> | 121 /// <summary>Constructs a new configurable message handler </summary> |
122 public ConfigurableMessageHandler(HttpMessageHandler httpMessageHandler) | 122 public ConfigurableMessageHandler(HttpMessageHandler httpMessageHandler) |
123 : base(httpMessageHandler) | 123 : base(httpMessageHandler) |
124 { | 124 { |
125 // set default values | 125 // set default values |
126 FollowRedirect = true; | 126 FollowRedirect = true; |
127 IsLoggingEnabled = true; | 127 IsLoggingEnabled = true; |
128 } | 128 } |
129 | 129 |
130 /// <summary> | 130 /// <summary> |
131 /// The main logic of sending a request to the server. This send method adds the User-Agent header to a request | 131 /// The main logic of sending a request to the server. This send method adds the User-Agent header to a request |
132 /// with <see cref="ApplicationName"/> and the library version. It also calls interceptors before each attempt, | 132 /// with <see cref="ApplicationName"/> and the library version. It also calls interceptors before each attempt, |
133 /// and unsuccessful response handler or exception handlers when abnorma l response or exception occurred. | 133 /// and unsuccessful response handler or exception handlers when abnorma l response or exception occurred. |
134 /// </summary> | 134 /// </summary> |
135 protected override async Task<HttpResponseMessage> SendAsync(HttpRequest Message request, | 135 protected override async Task<HttpResponseMessage> SendAsync(HttpRequest Message request, |
136 CancellationToken cancellationToken) | 136 CancellationToken cancellationToken) |
137 { | 137 { |
138 var loggable = IsLoggingEnabled && Logger.IsDebugEnabled; | 138 var loggable = IsLoggingEnabled && Logger.IsDebugEnabled; |
139 | 139 |
140 int triesRemaining = NumTries; | 140 int triesRemaining = NumTries; |
141 Exception lastException = null; | 141 Exception lastException = null; |
142 | 142 |
143 // set User-Agent header | 143 // Set User-Agent header. |
144 var userAgent = (ApplicationName == null ? "" : ApplicationName " ") UserAgentSuffix; | 144 var userAgent = (ApplicationName == null ? "" : ApplicationName " ") UserAgentSuffix; |
145 // TODO: setting the User-Agent won't work on Silverlight. We may ne ed to create a special callback here to· | 145 // TODO: setting the User-Agent won't work on Silverlight. We may ne ed to create a special callback here to· |
146 // set it correctly. Also check what happen in WP? | 146 // set it correctly. |
147 request.Headers.Add("User-Agent", userAgent); | 147 request.Headers.Add("User-Agent", userAgent); |
148 | 148 |
149 HttpResponseMessage response = null; | 149 HttpResponseMessage response = null; |
150 do // while (triesRemaining > 0) | 150 do // While (triesRemaining > 0) |
151 { | 151 { |
152 cancellationToken.ThrowIfCancellationRequested(); | 152 cancellationToken.ThrowIfCancellationRequested(); |
153 | 153 |
154 if (response != null) | 154 if (response != null) |
155 { | 155 { |
156 response.Dispose(); | 156 response.Dispose(); |
157 response = null; | 157 response = null; |
158 } | 158 } |
159 lastException = null; | 159 lastException = null; |
160 | 160 |
161 // intercept the request | 161 // Intercept the request. |
162 foreach (var interceptor in executeInterceptors) | 162 foreach (var interceptor in executeInterceptors) |
163 { | 163 { |
164 await interceptor.InterceptAsync(request, cancellationToken) .ConfigureAwait(false); | 164 await interceptor.InterceptAsync(request, cancellationToken) .ConfigureAwait(false); |
165 } | 165 } |
166 | 166 |
167 try | 167 try |
168 { | 168 { |
169 // send the request! | 169 // Send the request! |
170 response = await base.SendAsync(request, cancellationToken). ConfigureAwait(false); | 170 response = await base.SendAsync(request, cancellationToken). ConfigureAwait(false); |
171 } | 171 } |
172 catch (Exception ex) | 172 catch (Exception ex) |
173 { | 173 { |
174 lastException = ex; | 174 lastException = ex; |
175 } | 175 } |
176 | 176 |
177 // decrease the number of retries | 177 // Decrease the number of retries. |
178 triesRemaining--; | 178 triesRemaining--; |
179 | 179 |
180 // exception was thrown , try to handle it | 180 // Exception was thrown, try to handle it. |
181 if (response == null) | 181 if (response == null) |
182 { | 182 { |
183 var exceptionHandled = false; | 183 var exceptionHandled = false; |
184 | 184 |
185 // try to handle the exception with each handler | 185 // Try to handle the exception with each handler. |
186 foreach (var handler in exceptionHandlers) | 186 foreach (var handler in exceptionHandlers) |
187 { | 187 { |
188 exceptionHandled |= await handler.HandleExceptionAsync(n ew HandleExceptionArgs | 188 exceptionHandled |= await handler.HandleExceptionAsync(n ew HandleExceptionArgs |
189 { | 189 { |
190 Request = request, | 190 Request = request, |
191 Exception = lastException, | 191 Exception = lastException, |
192 TotalTries = NumTries, | 192 TotalTries = NumTries, |
193 CurrentFailedTry = NumTries - triesRemaining, | 193 CurrentFailedTry = NumTries - triesRemaining, |
194 CancellationToken = cancellationToken | 194 CancellationToken = cancellationToken |
195 }).ConfigureAwait(false); | 195 }).ConfigureAwait(false); |
196 } | 196 } |
197 | 197 |
198 if (!exceptionHandled) | 198 if (!exceptionHandled) |
199 { | 199 { |
200 Logger.Error(lastException, | 200 Logger.Error(lastException, |
201 "Exception was thrown while executing a HTTP request and it wasn't handled"); | 201 "Exception was thrown while executing a HTTP request and it wasn't handled"); |
202 throw lastException; | 202 throw lastException; |
203 } | 203 } |
204 else if (loggable) | 204 else if (loggable) |
205 { | 205 { |
206 Logger.Debug("Exception {0} was thrown, but it was handl ed by an exception handler", | 206 Logger.Debug("Exception {0} was thrown, but it was handl ed by an exception handler", |
207 lastException.Message); | 207 lastException.Message); |
208 } | 208 } |
209 } | 209 } |
210 else | 210 else |
211 { | 211 { |
212 if (response.IsSuccessStatusCode) | 212 if (response.IsSuccessStatusCode) |
213 { | 213 { |
214 // no need to retry, the response was successful | 214 // No need to retry, the response was successful. |
215 triesRemaining = 0; | 215 triesRemaining = 0; |
216 } | 216 } |
217 else | 217 else |
218 { | 218 { |
219 bool errorHandled = false; | 219 bool errorHandled = false; |
220 | 220 |
221 // try to handle the abnormal HTTP response with each ha ndler | 221 // Try to handle the abnormal HTTP response with each ha ndler. |
222 foreach (var handler in unsuccessfulResponseHandlers) | 222 foreach (var handler in unsuccessfulResponseHandlers) |
223 { | 223 { |
224 errorHandled |= await handler.HandleResponseAsync(ne w HandleUnsuccessfulResponseArgs | 224 errorHandled |= await handler.HandleResponseAsync(ne w HandleUnsuccessfulResponseArgs |
225 { | 225 { |
226 Request = request, | 226 Request = request, |
227 Response = response, | 227 Response = response, |
228 TotalTries = NumTries, | 228 TotalTries = NumTries, |
229 CurrentFailedTry = NumTries - triesRemaining , | 229 CurrentFailedTry = NumTries - triesRemaining , |
230 CancellationToken = cancellationToken | 230 CancellationToken = cancellationToken |
231 }).ConfigureAwait(false); | 231 }).ConfigureAwait(false); |
(...skipping 11 matching lines...) Expand all Loading... | |
243 } | 243 } |
244 } | 244 } |
245 else | 245 else |
246 { | 246 { |
247 if (loggable) | 247 if (loggable) |
248 { | 248 { |
249 Logger.Debug("An abnormal response wasn't ha ndled. Status code is {0}", | 249 Logger.Debug("An abnormal response wasn't ha ndled. Status code is {0}", |
250 response.StatusCode); | 250 response.StatusCode); |
251 } | 251 } |
252 | 252 |
253 // no need to retry, because no handler handled the abnormal response | 253 // No need to retry, because no handler handled the abnormal response. |
254 triesRemaining = 0; | 254 triesRemaining = 0; |
255 } | 255 } |
256 } | 256 } |
257 else if (loggable) | 257 else if (loggable) |
258 { | 258 { |
259 Logger.Debug("An abnormal response was handled by an unsuccessful response handler. " | 259 Logger.Debug("An abnormal response was handled by an unsuccessful response handler. " |
260 "Status Code is {0}", response.StatusCode); | 260 "Status Code is {0}", response.StatusCode); |
261 } | 261 } |
262 } | 262 } |
263 } | 263 } |
264 } while (triesRemaining > 0); // not a success status code but it wa s handled | 264 } while (triesRemaining > 0); // Not a successful status code but it was handled. |
265 | 265 |
266 // if the response is null, we should throw the last exception | 266 // If the response is null, we should throw the last exception. |
267 if (response == null) | 267 if (response == null) |
268 { | 268 { |
269 Logger.Error(lastException, "Exception was thrown while executin g a HTTP request"); | 269 Logger.Error(lastException, "Exception was thrown while executin g a HTTP request"); |
270 throw lastException; | 270 throw lastException; |
271 } | 271 } |
272 else if (!response.IsSuccessStatusCode) | 272 else if (!response.IsSuccessStatusCode) |
273 { | 273 { |
274 Logger.Debug("Abnormal response is being returned. Status Code i s {0}", response.StatusCode); | 274 Logger.Debug("Abnormal response is being returned. Status Code i s {0}", response.StatusCode); |
275 } | 275 } |
276 | 276 |
(...skipping 16 matching lines...) Expand all Loading... | |
293 return false; | 293 return false; |
294 } | 294 } |
295 | 295 |
296 var request = message.RequestMessage; | 296 var request = message.RequestMessage; |
297 request.RequestUri = new Uri(request.RequestUri, uri); | 297 request.RequestUri = new Uri(request.RequestUri, uri); |
298 // Status code for a resource that has moved to a new URI and should be retrieved using GET. | 298 // Status code for a resource that has moved to a new URI and should be retrieved using GET. |
299 if (message.StatusCode == HttpStatusCode.SeeOther) | 299 if (message.StatusCode == HttpStatusCode.SeeOther) |
300 { | 300 { |
301 request.Method = HttpMethod.Get; | 301 request.Method = HttpMethod.Get; |
302 } | 302 } |
303 // clear Authorization and If-* headers | 303 // Clear Authorization and If-* headers. |
304 request.Headers.Remove("Authorization"); | 304 request.Headers.Remove("Authorization"); |
305 request.Headers.IfMatch.Clear(); | 305 request.Headers.IfMatch.Clear(); |
306 request.Headers.IfNoneMatch.Clear(); | 306 request.Headers.IfNoneMatch.Clear(); |
307 request.Headers.IfModifiedSince = null; | 307 request.Headers.IfModifiedSince = null; |
308 request.Headers.IfUnmodifiedSince = null; | 308 request.Headers.IfUnmodifiedSince = null; |
309 request.Headers.Remove("If-Range"); | 309 request.Headers.Remove("If-Range"); |
310 return true; | 310 return true; |
311 } | 311 } |
312 } | 312 } |
313 } | 313 } |
LEFT | RIGHT |