/AWSSDK_DotNet35/Amazon.Runtime/AmazonWebServiceClient.cs

https://github.com/FireflyLogic/aws-sdk-net · C# · 690 lines · 580 code · 72 blank · 38 comment · 155 complexity · 700ccd80186bc03e33a13698033fd01d MD5 · raw file

  1. /*
  2. * Copyright 2010-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License").
  5. * You may not use this file except in compliance with the License.
  6. * A copy of the License is located at
  7. *
  8. * http://aws.amazon.com/apache2.0
  9. *
  10. * or in the "license" file accompanying this file. This file is distributed
  11. * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
  12. * express or implied. See the License for the specific language governing
  13. * permissions and limitations under the License.
  14. */
  15. using System;
  16. using System.Collections.Generic;
  17. using System.Globalization;
  18. using System.IO;
  19. using System.Net;
  20. using Amazon.Runtime.Internal;
  21. using Amazon.Runtime.Internal.Auth;
  22. using Amazon.Runtime.Internal.Transform;
  23. using Amazon.Util;
  24. using Amazon.Runtime.Internal.Util;
  25. namespace Amazon.Runtime
  26. {
  27. /// <summary>
  28. /// A base class for service clients that handles making the actual requests
  29. /// and possibly retries if needed.
  30. /// </summary>
  31. public abstract class AmazonWebServiceClient : AbstractWebServiceClient
  32. {
  33. #region Constructors
  34. internal AmazonWebServiceClient(AWSCredentials credentials, ClientConfig config, AuthenticationTypes authenticationType)
  35. : base(credentials, config, authenticationType)
  36. {
  37. }
  38. internal AmazonWebServiceClient(string awsAccessKeyId, string awsSecretAccessKey, ClientConfig config, AuthenticationTypes authenticationType)
  39. : this((AWSCredentials)new BasicAWSCredentials(awsAccessKeyId, awsSecretAccessKey),
  40. config, authenticationType)
  41. {
  42. }
  43. internal AmazonWebServiceClient(string awsAccessKeyId, string awsSecretAccessKey, string awsSessionToken, ClientConfig config, AuthenticationTypes authenticationType)
  44. : this(new SessionAWSCredentials(awsAccessKeyId, awsSecretAccessKey, awsSessionToken), config, authenticationType)
  45. {
  46. }
  47. internal AmazonWebServiceClient(string awsAccessKeyId, string awsSecretAccessKey, ClientConfig config)
  48. : this(new BasicAWSCredentials(awsAccessKeyId, awsSecretAccessKey), config, AuthenticationTypes.User)
  49. {
  50. }
  51. internal AmazonWebServiceClient(string awsAccessKeyId, string awsSecretAccessKey, string awsSessionToken, ClientConfig config)
  52. : this(new SessionAWSCredentials(awsAccessKeyId, awsSecretAccessKey, awsSessionToken), config, AuthenticationTypes.User)
  53. {
  54. }
  55. #endregion
  56. protected IAsyncResult Invoke<T, R>(R request, AsyncCallback callback, object state, bool synchronized, IMarshaller<T, R> marshaller, ResponseUnmarshaller unmarshaller, AbstractAWSSigner signer)
  57. where T : IRequest
  58. where R : AmazonWebServiceRequest
  59. {
  60. ProcessPreRequestHandlers(request);
  61. IRequest irequest = marshaller.Marshall(request);
  62. AsyncResult result = new AsyncResult(irequest, callback, state, synchronized, signer, unmarshaller);
  63. Invoke(result);
  64. return result;
  65. }
  66. protected void Invoke(AsyncResult asyncResult)
  67. {
  68. asyncResult.Metrics.StartEvent(Metric.ClientExecuteTime);
  69. asyncResult.Request.Endpoint = DetermineEndpoint(asyncResult.Request);
  70. if (Config.LogMetrics)
  71. {
  72. asyncResult.Metrics.IsEnabled = true;
  73. asyncResult.Metrics.AddProperty(Metric.ServiceName, asyncResult.Request.ServiceName);
  74. asyncResult.Metrics.AddProperty(Metric.ServiceEndpoint, asyncResult.Request.Endpoint);
  75. asyncResult.Metrics.AddProperty(Metric.MethodName, asyncResult.RequestName);
  76. asyncResult.Metrics.AddProperty(Metric.AsyncCall, !asyncResult.CompletedSynchronously);
  77. }
  78. ConfigureRequest(asyncResult);
  79. InvokeHelper(asyncResult);
  80. }
  81. protected Uri DetermineEndpoint(IRequest request)
  82. {
  83. Uri endpoint;
  84. if (request.AlternateEndpoint != null)
  85. endpoint = new Uri(ClientConfig.GetUrl(request.AlternateEndpoint, Config.RegionEndpointServiceName, Config.UseHttp));
  86. else
  87. endpoint = new Uri(this.Config.DetermineServiceURL());
  88. return endpoint;
  89. }
  90. private void InvokeHelper(AsyncResult asyncResult)
  91. {
  92. if (asyncResult.RetriesAttempt == 0 || Config.ResignRetries)
  93. {
  94. SignRequest(asyncResult);
  95. }
  96. if (asyncResult.RetriesAttempt > 0)
  97. HandleRetry(asyncResult);
  98. InvokeConfiguredRequest(asyncResult);
  99. }
  100. private void InvokeConfiguredRequest(AsyncResult asyncResult)
  101. {
  102. HttpWebRequest webRequest = ConfigureWebRequest(asyncResult);
  103. asyncResult.RequestState = new AsyncResult.AsyncRequestState(webRequest, GetRequestData(asyncResult.Request), asyncResult.Request.ContentStream);
  104. asyncResult.Metrics.StartEvent(Metric.HttpRequestTime);
  105. if (asyncResult.CompletedSynchronously)
  106. {
  107. this.getRequestStreamCallback(asyncResult);
  108. }
  109. else
  110. {
  111. IAsyncResult httpResult;
  112. if (asyncResult != null
  113. && asyncResult.RequestState != null
  114. && (asyncResult.RequestState.WebRequest.Method == "POST" || asyncResult.RequestState.WebRequest.Method == "PUT"))
  115. {
  116. httpResult = webRequest.BeginGetRequestStream(new AsyncCallback(this.getRequestStreamCallback), asyncResult);
  117. }
  118. else
  119. {
  120. httpResult = webRequest.BeginGetResponse(new AsyncCallback(this.getResponseCallback), asyncResult);
  121. }
  122. if (httpResult.CompletedSynchronously)
  123. {
  124. if (!asyncResult.RequestState.GetRequestStreamCallbackCalled)
  125. {
  126. getRequestStreamCallback(httpResult);
  127. }
  128. asyncResult.SetCompletedSynchronously(true);
  129. }
  130. }
  131. }
  132. void getRequestStreamCallback(IAsyncResult result)
  133. {
  134. AsyncResult asyncResult = result as AsyncResult;
  135. if (asyncResult == null)
  136. asyncResult = result.AsyncState as AsyncResult;
  137. asyncResult.RequestState.GetRequestStreamCallbackCalled = true;
  138. try
  139. {
  140. try
  141. {
  142. AsyncResult.AsyncRequestState state = asyncResult.RequestState;
  143. if (asyncResult != null
  144. && asyncResult.RequestState != null
  145. && ((asyncResult.RequestState.RequestData != null && asyncResult.RequestState.RequestData.Length > 0) || asyncResult.RequestState.RequestStream != null)
  146. && (!asyncResult.Request.UseQueryString && (asyncResult.RequestState.WebRequest.Method == "POST" || asyncResult.RequestState.WebRequest.Method == "PUT")))
  147. {
  148. Stream requestStream;
  149. if (asyncResult.CompletedSynchronously)
  150. requestStream = state.WebRequest.GetRequestStream();
  151. else
  152. requestStream = state.WebRequest.EndGetRequestStream(result);
  153. using (requestStream)
  154. {
  155. if (asyncResult.RequestState.RequestStream == null)
  156. {
  157. byte[] requestData = asyncResult.RequestState.RequestData;
  158. asyncResult.Metrics.AddProperty(Metric.RequestSize, requestData.Length);
  159. requestStream.Write(requestData, 0, requestData.Length);
  160. }
  161. else
  162. {
  163. var originalStream = asyncResult.RequestState.RequestStream;
  164. var callback = asyncResult.Request.OriginalRequest.StreamUploadProgressCallback;
  165. if(callback != null)
  166. {
  167. var eventStream = new EventStream(originalStream, true);
  168. var tracker = new StreamReadTracker(this, callback, originalStream.Length);
  169. eventStream.OnRead += tracker.ReadProgress;
  170. originalStream = eventStream;
  171. }
  172. var buffer = new byte[this.Config.BufferSize];
  173. var inputStream = asyncResult.Request.UseChunkEncoding && asyncResult.Request.AWS4SignerResult != null
  174. ? new ChunkedUploadWrapperStream(originalStream,
  175. Config.BufferSize,
  176. asyncResult.Request.AWS4SignerResult)
  177. : originalStream;
  178. int bytesRead = 0;
  179. int bytesToRead = buffer.Length;
  180. while ((bytesRead = inputStream.Read(buffer, 0, bytesToRead)) > 0)
  181. {
  182. requestStream.Write(buffer, 0, bytesRead);
  183. }
  184. }
  185. }
  186. }
  187. if (asyncResult.CompletedSynchronously)
  188. {
  189. this.getResponseCallback(asyncResult);
  190. }
  191. else
  192. {
  193. IAsyncResult httpResult = state.WebRequest.BeginGetResponse(new AsyncCallback(this.getResponseCallback), asyncResult);
  194. if (httpResult.CompletedSynchronously)
  195. {
  196. if (!asyncResult.RequestState.GetResponseCallbackCalled)
  197. {
  198. getResponseCallback(httpResult);
  199. }
  200. asyncResult.SetCompletedSynchronously(true);
  201. }
  202. }
  203. }
  204. catch (WebException e)
  205. {
  206. asyncResult.RequestState.WebRequest.Abort();
  207. HandleHttpWebErrorResponse(asyncResult, e);
  208. asyncResult.RetriesAttempt++;
  209. InvokeHelper(asyncResult);
  210. }
  211. catch (IOException ioe)
  212. {
  213. if (HandleIOException(asyncResult, null, ioe))
  214. {
  215. asyncResult.RetriesAttempt++;
  216. InvokeHelper(asyncResult);
  217. }
  218. else { throw; }
  219. }
  220. catch (Exception e)
  221. {
  222. asyncResult.RequestState.WebRequest.Abort();
  223. asyncResult.Metrics.AddProperty(Metric.Exception, e);
  224. asyncResult.HandleException(e);
  225. }
  226. }
  227. catch (Exception exception)
  228. {
  229. ProcessExceptionHandlers(exception, asyncResult.Request);
  230. // Handle WebException/IOExceptionexceptions/AmazonServiceException
  231. // thrown after retry limit is reached.
  232. asyncResult.HandleException(exception);
  233. }
  234. }
  235. void getResponseCallback(IAsyncResult result)
  236. {
  237. AsyncResult asyncResult = result as AsyncResult;
  238. if (asyncResult == null)
  239. asyncResult = result.AsyncState as AsyncResult;
  240. UnmarshallerContext context = null;
  241. asyncResult.RequestState.GetResponseCallbackCalled = true;
  242. bool shouldRetry = false;
  243. AmazonWebServiceResponse response = null;
  244. try
  245. {
  246. AsyncResult.AsyncRequestState state = asyncResult.RequestState;
  247. HttpWebResponse httpResponse = null;
  248. try
  249. {
  250. if (asyncResult.CompletedSynchronously)
  251. httpResponse = state.WebRequest.GetResponse() as HttpWebResponse;
  252. else
  253. httpResponse = state.WebRequest.EndGetResponse(result) as HttpWebResponse;
  254. using (asyncResult.Metrics.StartEvent(Metric.ResponseProcessingTime))
  255. {
  256. var unmarshaller = asyncResult.Unmarshaller;
  257. LogResponse(asyncResult.Metrics, asyncResult.Request, httpResponse.StatusCode);
  258. try
  259. {
  260. var httpResponseData = new HttpWebRequestResponseData(httpResponse);
  261. context = unmarshaller.CreateContext(httpResponseData,
  262. this.SupportResponseLogging &&
  263. (Config.LogResponse || Config.ReadEntireResponse || AWSConfigs.ResponseLogging != ResponseLoggingOption.Never),
  264. httpResponseData.OpenResponse(),
  265. asyncResult.Metrics);
  266. using (asyncResult.Metrics.StartEvent(Metric.ResponseUnmarshallTime))
  267. {
  268. response = unmarshaller.Unmarshall(context);
  269. }
  270. context.ValidateCRC32IfAvailable();
  271. response.ContentLength = httpResponse.ContentLength;
  272. response.HttpStatusCode = httpResponse.StatusCode;
  273. asyncResult.FinalResponse = response;
  274. if (response.ResponseMetadata != null)
  275. {
  276. asyncResult.Metrics.AddProperty(Metric.AWSRequestID, response.ResponseMetadata.RequestId);
  277. }
  278. LogFinishedResponse(asyncResult.Metrics, context, httpResponse.ContentLength);
  279. }
  280. finally
  281. {
  282. if (!unmarshaller.HasStreamingProperty)
  283. httpResponse.Close();
  284. }
  285. }
  286. }
  287. catch (WebException we)
  288. {
  289. HttpWebResponse exceptionHttpResponse = we.Response as HttpWebResponse;
  290. // If the error is a 404 and the request is configured to supress it. Then unmarshall as much as we can.
  291. if (exceptionHttpResponse != null &&
  292. exceptionHttpResponse.StatusCode == HttpStatusCode.NotFound &&
  293. asyncResult.Request.Suppress404Exceptions)
  294. {
  295. var unmarshaller = asyncResult.Unmarshaller;
  296. var httpResponseData = new HttpWebRequestResponseData(exceptionHttpResponse);
  297. UnmarshallerContext errorContext = unmarshaller.CreateContext(
  298. httpResponseData,
  299. Config.LogResponse || Config.ReadEntireResponse || AWSConfigs.ResponseLogging != ResponseLoggingOption.Never,
  300. httpResponseData.OpenResponse(),
  301. asyncResult.Metrics);
  302. try
  303. {
  304. response = unmarshaller.Unmarshall(errorContext);
  305. response.ContentLength = exceptionHttpResponse.ContentLength;
  306. response.HttpStatusCode = exceptionHttpResponse.StatusCode;
  307. }
  308. catch (Exception e)
  309. {
  310. logger.Debug(e, "Failed to unmarshall 404 response when it was being supressed");
  311. }
  312. asyncResult.FinalResponse = response;
  313. }
  314. else
  315. {
  316. if (exceptionHttpResponse != null)
  317. {
  318. LogResponse(asyncResult.Metrics, asyncResult.Request, exceptionHttpResponse.StatusCode);
  319. }
  320. else
  321. {
  322. asyncResult.Metrics.StopEvent(Metric.HttpRequestTime);
  323. }
  324. shouldRetry = HandleHttpWebErrorResponse(asyncResult, we);
  325. }
  326. }
  327. catch (IOException ioe)
  328. {
  329. LogResponse(asyncResult.Metrics, asyncResult.Request, HttpStatusCode.Unused);
  330. shouldRetry = HandleIOException(asyncResult, httpResponse, ioe);
  331. if (!shouldRetry)
  332. asyncResult.Exception = ioe;
  333. }
  334. if (shouldRetry)
  335. {
  336. asyncResult.RequestState.WebRequest.Abort();
  337. asyncResult.RetriesAttempt++;
  338. InvokeHelper(asyncResult);
  339. }
  340. else
  341. {
  342. LogFinalMetrics(asyncResult.Metrics);
  343. }
  344. }
  345. catch (Exception e)
  346. {
  347. if (context != null && AWSConfigs.ResponseLogging == ResponseLoggingOption.OnError)
  348. this.logger.Error(e, "Received response: [{0}]", context.ResponseBody);
  349. asyncResult.RequestState.WebRequest.Abort();
  350. asyncResult.Exception = e;
  351. asyncResult.Metrics.AddProperty(Metric.Exception, e);
  352. asyncResult.Metrics.StopEvent(Metric.ClientExecuteTime);
  353. shouldRetry = false;
  354. if (Config.LogMetrics)
  355. logger.InfoFormat("Request metrics: {0}", asyncResult.Metrics);
  356. ProcessExceptionHandlers(e, asyncResult.Request);
  357. logger.Error(e, "Error configuring web request {0} to {1}.", asyncResult.RequestName, asyncResult.Request.Endpoint.ToString());
  358. }
  359. finally
  360. {
  361. if (!shouldRetry)
  362. {
  363. var responseData = context == null ? null : context.ResponseData;
  364. ProcessResponseHandlers(response, asyncResult.Request, responseData);
  365. asyncResult.InvokeCallback();
  366. }
  367. }
  368. }
  369. internal static T endOperation<T>(IAsyncResult result)
  370. where T : AmazonWebServiceResponse, new()
  371. {
  372. AsyncResult asyncResult = result as AsyncResult;
  373. if (asyncResult == null)
  374. return default(T);
  375. using (asyncResult)
  376. {
  377. if (!asyncResult.IsCompleted)
  378. {
  379. asyncResult.AsyncWaitHandle.WaitOne();
  380. }
  381. if (asyncResult.Exception != null)
  382. {
  383. AWSSDKUtils.PreserveStackTrace(asyncResult.Exception);
  384. throw asyncResult.Exception;
  385. }
  386. return asyncResult.FinalResponse as T;
  387. }
  388. }
  389. private bool HandleIOException(AsyncResult asyncResult, HttpWebResponse httpResponse, IOException e)
  390. {
  391. asyncResult.Metrics.AddProperty(Metric.Exception, e);
  392. if (IsInnerExceptionThreadAbort(e))
  393. throw e;
  394. this.logger.Error(e, "IOException making request {0} to {1}.", asyncResult.RequestName, asyncResult.Request.Endpoint.ToString());
  395. if (httpResponse != null)
  396. {
  397. httpResponse.Close();
  398. httpResponse = null;
  399. }
  400. // Abort the unsuccessful request
  401. asyncResult.RequestState.WebRequest.Abort();
  402. if (CanRetry(asyncResult) && asyncResult.RetriesAttempt < Config.MaxErrorRetry)
  403. {
  404. this.logger.Error(e, "IOException making request {0} to {1}. Attempting retry {2}.",
  405. asyncResult.RequestName,
  406. asyncResult.Request.Endpoint.ToString(),
  407. asyncResult.RetriesAttempt);
  408. return true;
  409. }
  410. else
  411. {
  412. return false;
  413. }
  414. }
  415. private bool HandleHttpWebErrorResponse(AsyncResult asyncResult, WebException we)
  416. {
  417. asyncResult.Metrics.AddProperty(Metric.Exception, we);
  418. HttpStatusCode statusCode;
  419. AmazonServiceException errorResponseException = null;
  420. using (HttpWebResponse httpErrorResponse = we.Response as HttpWebResponse)
  421. {
  422. if (we != null && WebExceptionStatusesToThrowOn.Contains(we.Status))
  423. {
  424. throw new AmazonServiceException("Encountered a non retryable WebException : " + we.Status, we);
  425. }
  426. if (httpErrorResponse == null ||
  427. (we != null && WebExceptionStatusesToRetryOn.Contains(we.Status)))
  428. {
  429. // Abort the unsuccessful request
  430. asyncResult.RequestState.WebRequest.Abort();
  431. if (CanRetry(asyncResult) && asyncResult.RetriesAttempt < Config.MaxErrorRetry)
  432. {
  433. pauseExponentially(asyncResult);
  434. return true;
  435. }
  436. var errorMessage = string.Format(CultureInfo.InvariantCulture,
  437. "Encountered a WebException ({0}), the request cannot be retried. Either the maximum number of retries has been exceeded ({1}/{2}) or the request is using a non-seekable stream.",
  438. we.Status, asyncResult.RetriesAttempt, Config.MaxErrorRetry);
  439. throw new AmazonServiceException(errorMessage, we);
  440. }
  441. statusCode = httpErrorResponse.StatusCode;
  442. asyncResult.Metrics.AddProperty(Metric.StatusCode, statusCode);
  443. string redirectedLocation = httpErrorResponse.Headers["location"];
  444. asyncResult.Metrics.AddProperty(Metric.RedirectLocation, redirectedLocation);
  445. using (httpErrorResponse)
  446. {
  447. var unmarshaller = asyncResult.Unmarshaller;
  448. var httpResponseData = new HttpWebRequestResponseData(httpErrorResponse);
  449. UnmarshallerContext errorContext = unmarshaller.CreateContext(httpResponseData,
  450. Config.LogResponse || Config.ReadEntireResponse || AWSConfigs.ResponseLogging != ResponseLoggingOption.Never,
  451. httpResponseData.OpenResponse(),
  452. asyncResult.Metrics);
  453. errorResponseException = unmarshaller.UnmarshallException(errorContext, we, statusCode);
  454. if (Config.LogResponse || AWSConfigs.ResponseLogging != ResponseLoggingOption.Never)
  455. {
  456. this.logger.Error(errorResponseException, "Received error response: [{0}]", errorContext.ResponseBody);
  457. }
  458. asyncResult.Metrics.AddProperty(Metric.AWSRequestID, errorResponseException.RequestId);
  459. asyncResult.Metrics.AddProperty(Metric.AWSErrorCode, errorResponseException.ErrorCode);
  460. }
  461. asyncResult.RequestState.WebRequest.Abort();
  462. if (CanRetry(asyncResult))
  463. {
  464. if (isTemporaryRedirect(statusCode, redirectedLocation))
  465. {
  466. this.logger.DebugFormat("Request {0} is being redirected to {1}.", asyncResult.RequestName, redirectedLocation);
  467. asyncResult.Request.Endpoint = new Uri(redirectedLocation);
  468. return true;
  469. }
  470. else if (ShouldRetry(statusCode, this.Config, errorResponseException, asyncResult.RetriesAttempt))
  471. {
  472. this.logger.DebugFormat("Retry number {0} for request {1}.", asyncResult.RetriesAttempt, asyncResult.RequestName);
  473. pauseExponentially(asyncResult);
  474. return true;
  475. }
  476. }
  477. }
  478. if (errorResponseException != null)
  479. {
  480. this.logger.Error(errorResponseException, "Error making request {0}.", asyncResult.RequestName);
  481. throw errorResponseException;
  482. }
  483. AmazonServiceException excep = new AmazonServiceException("Unable to make request", we, statusCode);
  484. this.logger.Error(excep, "Error making request {0}.", asyncResult.RequestName);
  485. asyncResult.Metrics.AddProperty(Metric.Exception, excep);
  486. throw excep;
  487. }
  488. /// <summary>
  489. /// Creates the HttpWebRequest and configures the end point, content, user agent and proxy settings.
  490. /// </summary>
  491. /// <param name="asyncResult">The async request.</param>
  492. /// <returns>The web request that actually makes the call.</returns>
  493. protected virtual HttpWebRequest ConfigureWebRequest(AsyncResult asyncResult)//IRequest wrappedRequest, byte[] requestData)
  494. {
  495. IRequest wrappedRequest = asyncResult.Request;
  496. byte[] requestData = GetRequestData(asyncResult.Request);
  497. Uri url = ComposeUrl(wrappedRequest, wrappedRequest.Endpoint);
  498. HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
  499. if (request != null)
  500. {
  501. if (asyncResult.Request.ContentStream != null)
  502. {
  503. request.Timeout = int.MaxValue;
  504. request.ReadWriteTimeout = int.MaxValue;
  505. request.AllowWriteStreamBuffering = false;
  506. }
  507. // Override the Timeout and ReadWriteTimeout values if set at the request or config level.
  508. // Public Timeout and ReadWriteTimeout properties are present on client config objects.
  509. var timeout = ClientConfig.GetTimeoutValue(this.Config.Timeout, wrappedRequest.OriginalRequest.TimeoutInternal);
  510. var readWriteTimeout = ClientConfig.GetTimeoutValue(this.Config.ReadWriteTimeout, wrappedRequest.OriginalRequest.ReadWriteTimeoutInternal);
  511. if (timeout != null)
  512. {
  513. request.Timeout = (int)timeout.Value.TotalMilliseconds;
  514. }
  515. if (readWriteTimeout != null)
  516. {
  517. request.ReadWriteTimeout = (int)readWriteTimeout.Value.TotalMilliseconds;
  518. }
  519. request.ServicePoint.ConnectionLimit = this.Config.ConnectionLimit;
  520. request.ServicePoint.UseNagleAlgorithm = this.Config.UseNagleAlgorithm;
  521. request.ServicePoint.MaxIdleTime = this.Config.MaxIdleTime;
  522. if (this.Config.ProxyHost != null && this.Config.ProxyPort != 0)
  523. {
  524. WebProxy proxy = new WebProxy(this.Config.ProxyHost, this.Config.ProxyPort);
  525. asyncResult.Metrics.AddProperty(Metric.ProxyHost, this.Config.ProxyHost);
  526. request.Proxy = proxy;
  527. }
  528. if (request.Proxy != null && Config.ProxyCredentials != null)
  529. {
  530. request.Proxy.Credentials = Config.ProxyCredentials;
  531. }
  532. // Setting of these properties is moved to before signing
  533. //request.UserAgent = this.config.UserAgent;
  534. //request.ContentType = AWSSDKUtils.UrlEncodedContent;
  535. request.Method = wrappedRequest.HttpMethod;
  536. if (!wrappedRequest.UseQueryString && (request.Method == "POST" || request.Method == "PUT"))
  537. {
  538. if (wrappedRequest.ContentStream != null)
  539. {
  540. if (wrappedRequest.OriginalRequest.IncludeSHA256Header
  541. && !wrappedRequest.Headers.ContainsKey(AWS4Signer.XAmzContentSha256))
  542. {
  543. request.Headers[AWS4Signer.XAmzContentSha256] = wrappedRequest.ComputeContentStreamHash();
  544. }
  545. request.ContentLength = wrappedRequest.ContentStream.Length;
  546. }
  547. else
  548. {
  549. request.ContentLength = requestData.Length;
  550. }
  551. }
  552. else
  553. {
  554. string headerValue;
  555. if (wrappedRequest.Headers.TryGetValue("x-amz-content-length", out headerValue) && headerValue != null)
  556. {
  557. request.ContentLength = long.Parse(headerValue, CultureInfo.InvariantCulture);
  558. }
  559. }
  560. AddHeaders(request, wrappedRequest.Headers);
  561. if (asyncResult.Unmarshaller is JsonResponseUnmarshaller)
  562. {
  563. request.Accept = "application/json";
  564. }
  565. request.ServicePoint.Expect100Continue = wrappedRequest.OriginalRequest.Expect100Continue;
  566. }
  567. return request;
  568. }
  569. private static System.Reflection.MethodInfo _addWithoutValidateHeadersMethod =
  570. typeof(WebHeaderCollection).GetMethod("AddWithoutValidate", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
  571. // As per MSDN documentation (http://msdn.microsoft.com/en-us/library/system.net.webheadercollection%28v=VS.80%29.aspx)
  572. // some headers are restricted, cannot be set through the request.Headers property and must be
  573. // set through properties on the HttpWebRequest
  574. internal static void AddHeaders(HttpWebRequest request, IDictionary<string, string> headersToAdd)
  575. {
  576. var headers = request.Headers;
  577. foreach (var kvp in headersToAdd)
  578. {
  579. if (WebHeaderCollection.IsRestricted(kvp.Key) || string.Equals(kvp.Key, "Range", StringComparison.OrdinalIgnoreCase))
  580. {
  581. if (string.Equals(kvp.Key, "Accept", StringComparison.OrdinalIgnoreCase))
  582. request.Accept = kvp.Value;
  583. else if (string.Equals(kvp.Key, "Connection", StringComparison.OrdinalIgnoreCase))
  584. request.Connection = kvp.Value;
  585. else if (string.Equals(kvp.Key, "Content-Type", StringComparison.OrdinalIgnoreCase))
  586. request.ContentType = kvp.Value;
  587. else if (string.Equals(kvp.Key, "Content-Length", StringComparison.OrdinalIgnoreCase))
  588. request.ContentLength = long.Parse(kvp.Value, CultureInfo.InvariantCulture);
  589. else if (string.Equals(kvp.Key, "Expect", StringComparison.OrdinalIgnoreCase))
  590. request.Expect = kvp.Value;
  591. else if (string.Equals(kvp.Key, "User-Agent", StringComparison.OrdinalIgnoreCase))
  592. request.UserAgent = kvp.Value;
  593. // Date accessor is only present in .NET 4.0, so using reflection
  594. else if (string.Equals(kvp.Key, "Date", StringComparison.OrdinalIgnoreCase))
  595. _addWithoutValidateHeadersMethod.Invoke(request.Headers, new[] { "Date", kvp.Value });
  596. // Host accessor is only present in .NET 4.0, so using reflection
  597. else if (string.Equals(kvp.Key, "Host", StringComparison.OrdinalIgnoreCase))
  598. _addWithoutValidateHeadersMethod.Invoke(request.Headers, new[] { "Host", kvp.Value });
  599. else if (string.Equals(kvp.Key, "Range", StringComparison.OrdinalIgnoreCase))
  600. _addWithoutValidateHeadersMethod.Invoke(request.Headers, new[] { "Range", kvp.Value });
  601. else if (string.Equals(kvp.Key, "If-Modified-Since", StringComparison.OrdinalIgnoreCase))
  602. _addWithoutValidateHeadersMethod.Invoke(request.Headers, new[] { kvp.Key, kvp.Value });
  603. else
  604. throw new NotSupportedException("Header with name " + kvp.Key + " is not suppored");
  605. }
  606. else
  607. {
  608. headers[kvp.Key] = kvp.Value;
  609. }
  610. }
  611. }
  612. protected static void LogResponse(RequestMetrics metrics, IRequest request, HttpStatusCode statusCode)
  613. {
  614. Timing timing = metrics.StopEvent(Metric.HttpRequestTime);
  615. metrics.AddProperty(Metric.StatusCode, statusCode);
  616. }
  617. }
  618. }