aliyun-net-sdk-dybaseapi/Dybaseapi/MNS/Runtime/Pipeline/HttpHandler/HttpWebRequestFactory.cs (232 lines of code) (raw):
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Net;
using Aliyun.Acs.Dybaseapi.MNS.Runtime.Internal.Transform;
using Aliyun.Acs.Dybaseapi.MNS.Runtime.Internal.Util;
using Aliyun.Acs.Dybaseapi.MNS.Util;
namespace Aliyun.Acs.Dybaseapi.MNS.Runtime.Pipeline.HttpHandler
{
/// <summary>
/// The request factory for System.Net.HttpWebRequest.
/// </summary>
public class HttpWebRequestFactory : IHttpRequestFactory<Stream>
{
/// <summary>
/// Creates an HTTP request for the given URI.
/// </summary>
/// <param name="requestUri">The request URI.</param>
/// <returns>An HTTP request.</returns>
public IHttpRequest<Stream> CreateHttpRequest(Uri requestUri)
{
return new HttpRequest(requestUri);
}
/// <summary>
/// Disposes the HttpWebRequestFactory.
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
}
}
/// <summary>
/// HTTP request wrapper for System.Net.HttpWebRequest.
/// </summary>
public class HttpRequest : IHttpRequest<Stream>
{
private bool _isAborted = false;
private HttpWebRequest _request;
/// <summary>
/// Constructor for HttpRequest.
/// </summary>
/// <param name="requestUri">The request URI.</param>
public HttpRequest(Uri requestUri)
{
_request = WebRequest.Create(requestUri) as HttpWebRequest;
}
/// <summary>
/// The underlying HTTP web request.
/// </summary>
public HttpWebRequest Request
{
get { return _request; }
}
/// <summary>
/// The HTTP method or verb.
/// </summary>
public string Method
{
get { return _request.Method; }
set { _request.Method = value; }
}
/// <summary>
/// The request URI.
/// </summary>
public Uri RequestUri
{
get { return _request.RequestUri; }
}
/// <summary>
/// Returns the HTTP response.
/// </summary>
/// <returns>The HTTP response.</returns>
public virtual IWebResponseData GetResponse()
{
try
{
var response = _request.GetResponse() as HttpWebResponse;
return new HttpWebRequestResponseData(response);
}
catch(WebException webException)
{
var errorResponse = webException.Response as HttpWebResponse;
if (errorResponse != null)
{
throw new HttpErrorResponseException(webException.Message,
webException,
new HttpWebRequestResponseData(errorResponse));
}
throw;
}
}
/// <summary>
/// Gets a handle to the request content.
/// </summary>
/// <returns>The request content.</returns>
public Stream GetRequestContent()
{
return _request.GetRequestStream();
}
/// <summary>
/// Writes a stream to the request body.
/// </summary>
/// <param name="requestContent">The destination where the content stream is written.</param>
/// <param name="contentStream">The content stream to be written.</param>
/// <param name="contentHeaders">HTTP content headers.</param>
/// <param name="requestContext">The request context.</param>
public void WriteToRequestBody(Stream requestContent, Stream contentStream,
IDictionary<string, string> contentHeaders, IRequestContext requestContext)
{
bool gotException = false;
try
{
var buffer = new byte[requestContext.ClientConfig.BufferSize];
int bytesRead = 0;
int bytesToRead = buffer.Length;
while ((bytesRead = contentStream.Read(buffer, 0, bytesToRead)) > 0)
{
requestContent.Write(buffer, 0, bytesRead);
}
}
catch(Exception)
{
gotException = true;
// If an exception occured while reading the input stream,
// Abort the request to signal failure to the server and prevent
// potentially writing an incomplete stream to the server.
this.Abort();
throw;
}
finally
{
// Only bubble up exception from the close method if we haven't already got an exception
// reading and writing from the streams.
try
{
requestContent.Close();
}
catch(Exception)
{
if (!gotException)
throw;
}
}
}
/// <summary>
/// Writes a byte array to the request body.
/// </summary>
/// <param name="requestContent">The destination where the content stream is written.</param>
/// <param name="content">The content stream to be written.</param>
/// <param name="contentHeaders">HTTP content headers.</param>
public void WriteToRequestBody(Stream requestContent, byte[] content, IDictionary<string, string> contentHeaders)
{
using (requestContent)
{
requestContent.Write(content, 0, content.Length);
}
}
/// <summary>
/// Aborts the HTTP request.
/// </summary>
public void Abort()
{
if (!_isAborted)
{
_request.Abort();
_isAborted = true;
}
}
/// <summary>
/// Initiates the operation to gets a handle to the request content.
/// </summary>
/// <param name="callback">The async callback invoked when the operation completes.</param>
/// <param name="state">The state object to be passed to the async callback.</param>
/// <returns>IAsyncResult that represents an async operation.</returns>
public IAsyncResult BeginGetRequestContent(AsyncCallback callback, object state)
{
return _request.BeginGetRequestStream(callback, state);
}
/// <summary>
/// Ends the operation to gets a handle to the request content.
/// </summary>
/// <param name="asyncResult">IAsyncResult that represents an async operation.</param>
/// <returns>The request content.</returns>
public Stream EndGetRequestContent(IAsyncResult asyncResult)
{
return _request.EndGetRequestStream(asyncResult);
}
/// <summary>
/// Initiates the operation to Returns the HTTP response.
/// </summary>
/// <param name="callback">The async callback invoked when the operation completes.</param>
/// <param name="state">The state object to be passed to the async callback.</param>
/// <returns>IAsyncResult that represents an async operation.</returns>
public IAsyncResult BeginGetResponse(AsyncCallback callback, object state)
{
return _request.BeginGetResponse(callback, state);
}
/// <summary>
/// Ends the operation to Returns the HTTP response.
/// </summary>
/// <param name="asyncResult">IAsyncResult that represents an async operation.</param>
/// <returns>The HTTP response.</returns>
public virtual IWebResponseData EndGetResponse(IAsyncResult asyncResult)
{
try
{
var response = _request.EndGetResponse(asyncResult) as HttpWebResponse;
return new HttpWebRequestResponseData(response);
}
catch (WebException webException)
{
var errorResponse = webException.Response as HttpWebResponse;
if (errorResponse != null)
{
throw new HttpErrorResponseException(webException.Message,
webException,
new HttpWebRequestResponseData(errorResponse));
}
throw;
}
}
/// <summary>
/// Configures a request as per the request context.
/// </summary>
/// <param name="requestContext">The request context.</param>
public virtual void ConfigureRequest(IRequestContext requestContext)
{
var clientConfig = requestContext.ClientConfig;
var originalRequest = requestContext.OriginalRequest;
// If System.Net.WebRequest.AllowAutoRedirect is set to true (default value),
// redirects for GET requests are automatically followed and redirects for POST
// requests are thrown back as exceptions.
// If System.Net.WebRequest.AllowAutoRedirect is set to false,
// redirects are returned as responses.
_request.AllowAutoRedirect = clientConfig.AllowAutoRedirect;
// Configure timeouts.
if (requestContext.Request.ContentStream != null)
{
_request.Timeout = int.MaxValue;
_request.ReadWriteTimeout = int.MaxValue;
_request.AllowWriteStreamBuffering = false;
}
// Override the Timeout and ReadWriteTimeout values if set at the request or config level.
// Public Timeout and ReadWriteTimeout properties are present on client config objects.
var timeout = ClientConfig.GetTimeoutValue(clientConfig.Timeout,
originalRequest.TimeoutInternal);
var readWriteTimeout = ClientConfig.GetTimeoutValue(clientConfig.ReadWriteTimeout,
originalRequest.ReadWriteTimeoutInternal);
if (timeout != null)
{
_request.Timeout = (int)timeout.Value.TotalMilliseconds;
}
if (readWriteTimeout != null)
{
_request.ReadWriteTimeout = (int)readWriteTimeout.Value.TotalMilliseconds;
}
_request.KeepAlive = originalRequest.KeepAlive;
// Set proxy related properties
if (!string.IsNullOrEmpty(requestContext.ClientConfig.ProxyHost) && requestContext.ClientConfig.ProxyPort > 0)
{
WebProxy proxy = new WebProxy(requestContext.ClientConfig.ProxyHost, requestContext.ClientConfig.ProxyPort);
requestContext.Metrics.AddProperty(Metric.ProxyHost, requestContext.ClientConfig.ProxyHost);
requestContext.Metrics.AddProperty(Metric.ProxyHost, requestContext.ClientConfig.ProxyPort);
_request.Proxy = proxy;
if (requestContext.ClientConfig.ProxyCredentials != null)
{
_request.Proxy.Credentials = requestContext.ClientConfig.ProxyCredentials;
}
}
else
{
_request.Proxy = null;
}
// Set service point properties.
//_request.ServicePoint.Expect100Continue = originalRequest.Expect100Continue;
}
/// <summary>
/// Sets the headers on the request.
/// </summary>
/// <param name="headers">A dictionary of header names and values.</param>
public void SetRequestHeaders(IDictionary<string, string> headers)
{
AddHeaders(_request, headers);
}
private static System.Reflection.MethodInfo _addWithoutValidateHeadersMethod =
typeof(WebHeaderCollection).GetMethod("AddWithoutValidate", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
internal static void AddHeaders(HttpWebRequest request, IDictionary<string, string> headersToAdd)
{
var headers = request.Headers;
foreach (var kvp in headersToAdd)
{
if (WebHeaderCollection.IsRestricted(kvp.Key))
{
if (string.Equals(kvp.Key, HttpHeader.AcceptHeader, StringComparison.OrdinalIgnoreCase))
request.Accept = kvp.Value;
else if (string.Equals(kvp.Key, HttpHeader.ContentTypeHeader, StringComparison.OrdinalIgnoreCase))
request.ContentType = kvp.Value;
else if (string.Equals(kvp.Key, HttpHeader.ContentLengthHeader, StringComparison.OrdinalIgnoreCase))
request.ContentLength = long.Parse(kvp.Value, CultureInfo.InvariantCulture);
else if (string.Equals(kvp.Key, HttpHeader.UserAgentHeader, StringComparison.OrdinalIgnoreCase))
request.UserAgent = kvp.Value;
else if (string.Equals(kvp.Key, HttpHeader.DateHeader, StringComparison.OrdinalIgnoreCase))
_addWithoutValidateHeadersMethod.Invoke(request.Headers, new[] { HttpHeader.DateHeader, kvp.Value });
else if (string.Equals(kvp.Key, HttpHeader.HostHeader, StringComparison.OrdinalIgnoreCase))
_addWithoutValidateHeadersMethod.Invoke(request.Headers, new[] { HttpHeader.HostHeader, kvp.Value });
else
throw new NotSupportedException("Header with name " + kvp.Key + " is not suppored");
}
else
{
headers[kvp.Key] = kvp.Value;
}
}
}
/// <summary>
/// Disposes the HttpRequest.
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
}
}
}