Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(1184)

Side by Side Diff: Src/GoogleApis/Apis/Http/ConfigurableMessageHandler.cs

Issue 13412046: Reimplement OAuth2 library - Step 1 (Closed) Base URL: https://google-api-dotnet-client.googlecode.com/hg/
Patch Set: minor Created 10 years, 10 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
OLDNEW
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 11 matching lines...) Expand all
22 using System.Text; 22 using System.Text;
23 using System.Threading; 23 using System.Threading;
24 using System.Threading.Tasks; 24 using System.Threading.Tasks;
25 25
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 num of retires, follow redire ct, 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 // TODO(peleyal): rethink if each execute interceptor should be implemented as DelegateHandler, and·
163 // then remove this execute interceptor!
164 foreach (var interceptor in executeInterceptors) 162 foreach (var interceptor in executeInterceptors)
165 { 163 {
166 interceptor.Intercept(request); 164 await interceptor.InterceptAsync(request, cancellationToken) .ConfigureAwait(false);
167 } 165 }
168 166
169 try 167 try
170 { 168 {
171 // send the request! 169 // Send the request!
172 response = await base.SendAsync(request, cancellationToken). ConfigureAwait(false); 170 response = await base.SendAsync(request, cancellationToken). ConfigureAwait(false);
173 } 171 }
174 catch (Exception ex) 172 catch (Exception ex)
175 { 173 {
176 lastException = ex; 174 lastException = ex;
177 } 175 }
178 176
179 // decrease the number of retries 177 // Decrease the number of retries.
180 triesRemaining--; 178 triesRemaining--;
181 179
182 // exception was thrown , try to handle it 180 // Exception was thrown, try to handle it.
183 if (response == null) 181 if (response == null)
184 { 182 {
185 var exceptionHandled = false; 183 var exceptionHandled = false;
186 184
187 // try to handle the exception with each handler 185 // Try to handle the exception with each handler.
188 foreach (var handler in exceptionHandlers) 186 foreach (var handler in exceptionHandlers)
189 { 187 {
190 exceptionHandled |= handler.HandleException(new HandleEx ceptionArgs 188 exceptionHandled |= await handler.HandleExceptionAsync(n ew HandleExceptionArgs
191 { 189 {
192 Request = request, 190 Request = request,
193 Exception = lastException, 191 Exception = lastException,
194 TotalTries = NumTries, 192 TotalTries = NumTries,
195 CurrentFailedTry = NumTries - triesRemaining, 193 CurrentFailedTry = NumTries - triesRemaining,
196 CancellationToken = cancellationToken 194 CancellationToken = cancellationToken
197 }); 195 }).ConfigureAwait(false);
198 } 196 }
199 197
200 if (!exceptionHandled) 198 if (!exceptionHandled)
201 { 199 {
202 Logger.Error(lastException, 200 Logger.Error(lastException,
203 "Exception was thrown while executing an Http reques t and it wasn't handled"); 201 "Exception was thrown while executing a HTTP request and it wasn't handled");
204 throw lastException; 202 throw lastException;
205 } 203 }
206 else if (loggable) 204 else if (loggable)
207 { 205 {
208 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",
209 lastException.Message); 207 lastException.Message);
210 } 208 }
211 } 209 }
212 else 210 else
213 { 211 {
214 if (response.IsSuccessStatusCode) 212 if (response.IsSuccessStatusCode)
215 { 213 {
216 // no need to retry, the response was successful 214 // No need to retry, the response was successful.
217 triesRemaining = 0; 215 triesRemaining = 0;
218 } 216 }
219 else 217 else
220 { 218 {
221 bool errorHandled = false; 219 bool errorHandled = false;
222 220
223 // try to handle the abnormal Http response with each ha ndler 221 // Try to handle the abnormal HTTP response with each ha ndler.
224 foreach (var handler in unsuccessfulResponseHandlers) 222 foreach (var handler in unsuccessfulResponseHandlers)
225 { 223 {
226 errorHandled |= handler.HandleResponse(new HandleUns uccessfulResponseArgs 224 errorHandled |= await handler.HandleResponseAsync(ne w HandleUnsuccessfulResponseArgs
227 { 225 {
228 Request = request, 226 Request = request,
229 Response = response, 227 Response = response,
230 TotalTries = NumTries, 228 TotalTries = NumTries,
231 CurrentFailedTry = NumTries - triesRemaining , 229 CurrentFailedTry = NumTries - triesRemaining ,
232 CancellationToken = cancellationToken 230 CancellationToken = cancellationToken
233 }); 231 }).ConfigureAwait(false);
234 } 232 }
235 233
236 if (!errorHandled) 234 if (!errorHandled)
237 { 235 {
238 if (HandleRedirect(response)) 236 if (HandleRedirect(response))
239 { 237 {
240 errorHandled = true; 238 errorHandled = true;
241 if (loggable) 239 if (loggable)
242 { 240 {
243 Logger.Debug("Redirect response was handled successfully. Redirect to {0}", 241 Logger.Debug("Redirect response was handled successfully. Redirect to {0}",
244 response.Headers.Location); 242 response.Headers.Location);
245 } 243 }
246 } 244 }
247 else 245 else
248 { 246 {
249 if (loggable) 247 if (loggable)
250 { 248 {
251 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}",
252 response.StatusCode); 250 response.StatusCode);
253 } 251 }
254 252
255 // no need to retry, because no handler handled the abnormal response 253 // No need to retry, because no handler handled the abnormal response.
256 triesRemaining = 0; 254 triesRemaining = 0;
257 } 255 }
258 } 256 }
259 else if (loggable) 257 else if (loggable)
260 { 258 {
261 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. "
262 "Status Code is {0}", response.StatusCode); 260 "Status Code is {0}", response.StatusCode);
263 } 261 }
264 } 262 }
265 } 263 }
266 } 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.
267 265
268 // if the response is null, we should throw the last exception 266 // If the response is null, we should throw the last exception.
269 if (response == null) 267 if (response == null)
270 { 268 {
271 Logger.Error(lastException, "Exception was thrown while executin g an Http request"); 269 Logger.Error(lastException, "Exception was thrown while executin g a HTTP request");
272 throw lastException; 270 throw lastException;
273 } 271 }
274 else if (!response.IsSuccessStatusCode) 272 else if (!response.IsSuccessStatusCode)
275 { 273 {
276 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);
277 } 275 }
278 276
279 return response; 277 return response;
280 } 278 }
281 279
(...skipping 13 matching lines...) Expand all
295 return false; 293 return false;
296 } 294 }
297 295
298 var request = message.RequestMessage; 296 var request = message.RequestMessage;
299 request.RequestUri = new Uri(request.RequestUri, uri); 297 request.RequestUri = new Uri(request.RequestUri, uri);
300 // 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.
301 if (message.StatusCode == HttpStatusCode.SeeOther) 299 if (message.StatusCode == HttpStatusCode.SeeOther)
302 { 300 {
303 request.Method = HttpMethod.Get; 301 request.Method = HttpMethod.Get;
304 } 302 }
305 // clear Authorization and If-* headers 303 // Clear Authorization and If-* headers.
306 request.Headers.Remove("Authorization"); 304 request.Headers.Remove("Authorization");
307 request.Headers.IfMatch.Clear(); 305 request.Headers.IfMatch.Clear();
308 request.Headers.IfNoneMatch.Clear(); 306 request.Headers.IfNoneMatch.Clear();
309 request.Headers.IfModifiedSince = null; 307 request.Headers.IfModifiedSince = null;
310 request.Headers.IfUnmodifiedSince = null; 308 request.Headers.IfUnmodifiedSince = null;
311 request.Headers.Remove("If-Range"); 309 request.Headers.Remove("If-Range");
312 return true; 310 return true;
313 } 311 }
314 } 312 }
315 } 313 }
OLDNEW

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b