首次推送
This commit is contained in:
554
COSXML/Network/CommandTask.cs
Normal file
554
COSXML/Network/CommandTask.cs
Normal file
@@ -0,0 +1,554 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using System.Text;
|
||||
using System.Net;
|
||||
using System.Net.Security;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using COSXML.Log;
|
||||
using System.Reflection;
|
||||
using System.IO;
|
||||
using System.Net.Cache;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2018 Tencent Cloud. All rights reserved.
|
||||
* 11/7/2018 9:34:42 AM
|
||||
* bradyxiao
|
||||
*/
|
||||
namespace COSXML.Network
|
||||
{
|
||||
/// <summary>
|
||||
/// network request and response
|
||||
/// type1: command request
|
||||
/// type2: upload file
|
||||
/// type3: download file
|
||||
/// difference: body progress
|
||||
/// </summary>
|
||||
public sealed class CommandTask
|
||||
{
|
||||
public const string TAG = "CommandTask";
|
||||
|
||||
/// <summary>
|
||||
/// init connectionLimit and statueCode = 100 action
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
public static void Init(HttpClientConfig config)
|
||||
{
|
||||
ServicePointManager.Expect100Continue = false;
|
||||
ServicePointManager.DefaultConnectionLimit = config.ConnectionLimit;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// sync excute
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="config"></param>
|
||||
/// <returns></returns>
|
||||
public static void Excute(Request request, Response response, HttpClientConfig config)
|
||||
{
|
||||
HttpWebRequest httpWebRequest = null;
|
||||
HttpWebResponse httpWebResponse = null;
|
||||
try
|
||||
{
|
||||
//step1: create HttpWebRequest by request.url
|
||||
httpWebRequest = HttpWebRequest.Create(request.RequestUrlString) as HttpWebRequest;
|
||||
|
||||
httpWebRequest.AllowWriteStreamBuffering = false;
|
||||
|
||||
//bind webRequest
|
||||
request.BindHttpWebRequest(httpWebRequest);
|
||||
|
||||
// handler request
|
||||
HandleHttpWebRequest(httpWebRequest, request, config);
|
||||
|
||||
//final: get response
|
||||
httpWebResponse = httpWebRequest.GetResponse() as HttpWebResponse;
|
||||
|
||||
//notify has been got response
|
||||
request.onNotifyGetResponse();
|
||||
|
||||
//handle response for [100, 300)
|
||||
HandleHttpWebResponse(httpWebResponse, response);
|
||||
}
|
||||
catch (WebException webEx)
|
||||
{
|
||||
if (webEx.Response != null && webEx.Response is HttpWebResponse)
|
||||
{
|
||||
//notify has been got response
|
||||
|
||||
request.onNotifyGetResponse();
|
||||
|
||||
httpWebResponse = (HttpWebResponse)webEx.Response;
|
||||
//handle response for [400, 500]
|
||||
HandleHttpWebResponse(httpWebResponse, response);
|
||||
}
|
||||
else
|
||||
{
|
||||
//QLog.E(TAG, webEx.Message, webEx);
|
||||
throw;
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//QLog.E(TAG, ex.Message, ex);
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (httpWebResponse != null)
|
||||
{
|
||||
// print log
|
||||
PrintResponseInfo(httpWebResponse);
|
||||
httpWebResponse.Close();
|
||||
//QLog.D("XIAO", "response close");
|
||||
}
|
||||
if (httpWebRequest != null)
|
||||
{
|
||||
httpWebRequest.Abort();
|
||||
//QLog.D("XIAO", "request close");
|
||||
}
|
||||
QLog.D(TAG, "close");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// handle request
|
||||
/// </summary>
|
||||
/// <param name="httpWebRequest"></param>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="config"></param>
|
||||
private static void HandleHttpWebRequest(HttpWebRequest httpWebRequest, Request request, HttpClientConfig config)
|
||||
{
|
||||
HandleHttpWebRequestHeaders(request, httpWebRequest, config);
|
||||
//setp5: send request content: body
|
||||
if (request.Body != null)
|
||||
{
|
||||
httpWebRequest.ContentLength = request.Body.ContentLength;
|
||||
request.Body.OnWrite(httpWebRequest.GetRequestStream());
|
||||
}
|
||||
//print request start log
|
||||
PrintReqeustInfo(httpWebRequest);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// handle response
|
||||
/// </summary>
|
||||
/// <param name="httpWebResponse"></param>
|
||||
/// <param name="response"></param>
|
||||
private static void HandleHttpWebResponse(HttpWebResponse httpWebResponse, Response response)
|
||||
{
|
||||
HandleHttpWebResponseHeaders(response, httpWebResponse);
|
||||
|
||||
//handle body
|
||||
response.Body.HandleResponseBody(httpWebResponse.GetResponseStream());
|
||||
|
||||
// close
|
||||
//httpWebResponse.Close();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// async to excute
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="response"></param>
|
||||
/// <param name="config"></param>
|
||||
public static void Schedue(Request request, Response response, HttpClientConfig config)
|
||||
{
|
||||
HttpWebRequest httpWebRequest = null;
|
||||
RequestState requestState = new RequestState();
|
||||
try
|
||||
{
|
||||
requestState.request = request;
|
||||
|
||||
requestState.response = response;
|
||||
|
||||
httpWebRequest = WebRequest.Create(request.RequestUrlString) as HttpWebRequest;
|
||||
|
||||
httpWebRequest.AllowWriteStreamBuffering = false;
|
||||
|
||||
//bind webRequest
|
||||
request.BindHttpWebRequest(httpWebRequest);
|
||||
|
||||
//handle request header
|
||||
HandleHttpWebRequestHeaders(request, httpWebRequest, config);
|
||||
|
||||
requestState.httpWebRequest = httpWebRequest;
|
||||
|
||||
//handle request body
|
||||
if(request.Body != null)
|
||||
{
|
||||
httpWebRequest.ContentLength = request.Body.ContentLength;
|
||||
httpWebRequest.BeginGetRequestStream(new AsyncCallback(AsyncRequestCallback), requestState);
|
||||
}
|
||||
else
|
||||
{
|
||||
//wait for response
|
||||
httpWebRequest.BeginGetResponse(new AsyncCallback(AsyncResponseCallback), requestState);
|
||||
}
|
||||
|
||||
//print log
|
||||
PrintReqeustInfo(httpWebRequest);
|
||||
}
|
||||
catch (WebException webEx)
|
||||
{
|
||||
response.OnFinish(false, webEx);
|
||||
//abort
|
||||
requestState.Clear();
|
||||
QLog.D(TAG, webEx.Message, webEx);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
response.OnFinish(false, ex);
|
||||
//abort
|
||||
requestState.Clear();
|
||||
QLog.E(TAG, ex.Message, ex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void AsyncRequestCallback(IAsyncResult ar)
|
||||
{
|
||||
RequestState requestState = ar.AsyncState as RequestState;
|
||||
Stream requestStream = null;
|
||||
try
|
||||
{
|
||||
HttpWebRequest httpWebRequest = requestState.httpWebRequest;
|
||||
requestStream = httpWebRequest.EndGetRequestStream(ar);
|
||||
|
||||
////开始写入数据
|
||||
//requestState.request.Body.OnWrite(requestStream);
|
||||
|
||||
////wait for response
|
||||
//httpWebRequest.BeginGetResponse(AsyncResponseCallback, requestState);
|
||||
|
||||
requestState.request.Body.StartHandleRequestBody(requestStream, delegate(Exception exception)
|
||||
{
|
||||
if (exception != null)
|
||||
{
|
||||
// handle request body throw exception
|
||||
requestState.response.OnFinish(false, exception);
|
||||
//abort
|
||||
requestState.Clear();
|
||||
QLog.E(TAG, exception.Message, exception);
|
||||
}
|
||||
else
|
||||
{
|
||||
//wait for response
|
||||
httpWebRequest.BeginGetResponse(new AsyncCallback(AsyncResponseCallback), requestState);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
requestState.response.OnFinish(false, ex);
|
||||
//abort
|
||||
requestState.Clear();
|
||||
QLog.E(TAG, ex.Message, ex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void AsyncResponseCallback(IAsyncResult ar)
|
||||
{
|
||||
RequestState requestState = ar.AsyncState as RequestState;
|
||||
HttpWebResponse httpWebResponse = null;
|
||||
try
|
||||
{
|
||||
HttpWebRequest httpWebRequest = requestState.httpWebRequest;
|
||||
httpWebResponse = (HttpWebResponse)httpWebRequest.EndGetResponse(ar);
|
||||
|
||||
//nofity get response
|
||||
requestState.request.onNotifyGetResponse();
|
||||
|
||||
requestState.httpWebResponse = httpWebResponse;
|
||||
//handle response headers
|
||||
HandleHttpWebResponseHeaders(requestState.response, httpWebResponse);
|
||||
|
||||
Stream responseStream = httpWebResponse.GetResponseStream();
|
||||
|
||||
requestState.response.Body.StartHandleResponseBody(responseStream, delegate(bool isSuccess, Exception ex)
|
||||
{
|
||||
PrintResponseInfo(httpWebResponse);
|
||||
requestState.response.OnFinish(isSuccess,ex);
|
||||
requestState.Clear();
|
||||
});
|
||||
}
|
||||
catch (WebException webEx)
|
||||
{
|
||||
if (webEx.Response != null && webEx.Response is HttpWebResponse)
|
||||
{
|
||||
//nofity get response
|
||||
requestState.request.onNotifyGetResponse();
|
||||
|
||||
//handle response for [400, 500]
|
||||
httpWebResponse = (HttpWebResponse)webEx.Response;
|
||||
|
||||
requestState.httpWebResponse = httpWebResponse;
|
||||
|
||||
//handle response headers
|
||||
HandleHttpWebResponseHeaders(requestState.response, httpWebResponse);
|
||||
|
||||
Stream responseStream = httpWebResponse.GetResponseStream();
|
||||
|
||||
requestState.response.Body.StartHandleResponseBody(responseStream, delegate(bool isSuccess, Exception ex)
|
||||
{
|
||||
PrintResponseInfo(httpWebResponse);
|
||||
requestState.response.OnFinish(isSuccess,ex);
|
||||
requestState.Clear();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
requestState.response.OnFinish(false, webEx);
|
||||
//abort
|
||||
requestState.Clear();
|
||||
QLog.E(TAG, webEx.Message, webEx);
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
requestState.response.OnFinish(false, ex);
|
||||
//abort
|
||||
requestState.Clear();
|
||||
QLog.E(TAG, ex.Message, ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// handle request headers
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="httpWebRequest"></param>
|
||||
/// <param name="config"></param>
|
||||
private static void HandleHttpWebRequestHeaders(Request request, HttpWebRequest httpWebRequest, HttpClientConfig config)
|
||||
{
|
||||
// set connect timeout
|
||||
httpWebRequest.Timeout = config.ConnectionTimeoutMs;
|
||||
//set read write timeout
|
||||
httpWebRequest.ReadWriteTimeout = config.ReadWriteTimeoutMs;
|
||||
|
||||
// set request method
|
||||
httpWebRequest.Method = request.Method.ToUpperInvariant();
|
||||
// set user-agent
|
||||
httpWebRequest.UserAgent = request.UserAgent;
|
||||
//set host, net2.0 cannot set;
|
||||
|
||||
// set allow auto redirect
|
||||
httpWebRequest.AllowAutoRedirect = config.AllowAutoRedirect;
|
||||
|
||||
// notice: it is not allowed to set common headers with the WebHeaderCollection.Accept
|
||||
// such as: Connection,Content-Length,Content-Type,Date,Expect. Host,If-Modified-Since,Range, Referer,Transfer-Encoding,User-Agent,Proxy-Connection
|
||||
//step2: set header and connection properity by request.heders
|
||||
foreach (KeyValuePair<string, string> pair in request.Headers)
|
||||
{
|
||||
HttpHeaderHandle.AddHeader(httpWebRequest.Headers, pair.Key, pair.Value);
|
||||
}
|
||||
|
||||
//step3: set proxy, default proxy = null, improte performation
|
||||
SetRequestProxy(httpWebRequest, config);
|
||||
|
||||
//step4: https, default all true for "*.myqcloud.com"
|
||||
if (request.IsHttps)
|
||||
{
|
||||
ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationCertificate);
|
||||
}
|
||||
//初始化长度
|
||||
httpWebRequest.ContentLength = 0L;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// headle response headers
|
||||
/// </summary>
|
||||
/// <param name="response"></param>
|
||||
/// <param name="httpWebResponse"></param>
|
||||
private static void HandleHttpWebResponseHeaders(Response response, HttpWebResponse httpWebResponse)
|
||||
{
|
||||
response.Code = (int)httpWebResponse.StatusCode;
|
||||
response.Message = httpWebResponse.StatusDescription;
|
||||
|
||||
WebHeaderCollection headers = httpWebResponse.Headers;
|
||||
if (headers != null)
|
||||
{
|
||||
Dictionary<string, List<string>> result = new Dictionary<string, List<string>>(headers.Count);
|
||||
for (int i = 0; i < headers.Count; i++)
|
||||
{
|
||||
List<string> values = null;
|
||||
if (headers.GetValues(i) != null)
|
||||
{
|
||||
values = new List<string>();
|
||||
foreach (string value in headers.GetValues(i))
|
||||
{
|
||||
values.Add(value);
|
||||
}
|
||||
}
|
||||
|
||||
result.Add(headers.GetKey(i), values);
|
||||
}
|
||||
response.Headers = result;
|
||||
}
|
||||
|
||||
response.ContentLength = httpWebResponse.ContentLength;
|
||||
response.ContentType = httpWebResponse.ContentType;
|
||||
if (response.Body != null)
|
||||
{
|
||||
response.Body.ContentLength = httpWebResponse.ContentLength;
|
||||
response.ContentType = httpWebResponse.ContentType;
|
||||
}
|
||||
|
||||
//handle header
|
||||
response.HandleResponseHeader();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// set proxy
|
||||
/// </summary>
|
||||
/// <param name="httpWebRequest"></param>
|
||||
/// <param name="config"></param>
|
||||
private static void SetRequestProxy(HttpWebRequest httpWebRequest, HttpClientConfig config)
|
||||
{
|
||||
httpWebRequest.Proxy = null;
|
||||
|
||||
if (!String.IsNullOrEmpty(config.ProxyHost))
|
||||
{
|
||||
if (config.ProxyPort < 0)
|
||||
{
|
||||
httpWebRequest.Proxy = new WebProxy(config.ProxyHost);
|
||||
}
|
||||
else
|
||||
{
|
||||
httpWebRequest.Proxy = new WebProxy(config.ProxyHost, config.ProxyPort);
|
||||
}
|
||||
if (!String.IsNullOrEmpty(config.ProxyUserName))
|
||||
{
|
||||
httpWebRequest.Proxy.Credentials = String.IsNullOrEmpty(config.ProxyDomain) ?
|
||||
new NetworkCredential(config.ProxyUserName, config.ProxyUserPassword ?? String.Empty) :
|
||||
new NetworkCredential(config.ProxyUserName, config.ProxyUserPassword ?? String.Empty,
|
||||
config.ProxyDomain);
|
||||
}
|
||||
httpWebRequest.PreAuthenticate = true; // 代理验证
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// check certificate
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="certificate"></param>
|
||||
/// <param name="chain"></param>
|
||||
/// <param name="errors"></param>
|
||||
/// <returns></returns>
|
||||
private static bool CheckValidationCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// print request info
|
||||
/// </summary>
|
||||
/// <param name="httpWebRequest"></param>
|
||||
private static void PrintReqeustInfo(HttpWebRequest httpWebRequest)
|
||||
{
|
||||
StringBuilder requestLog = new StringBuilder("--->");
|
||||
requestLog.Append(httpWebRequest.Method).Append(' ').Append(httpWebRequest.Address.AbsoluteUri).Append('\n');
|
||||
int count = httpWebRequest.Headers.Count;
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
requestLog.Append(httpWebRequest.Headers.GetKey(i)).Append(":").Append(httpWebRequest.Headers.GetValues(i)[0]).Append('\n');
|
||||
}
|
||||
requestLog.Append("allow auto redirect: " + httpWebRequest.AllowAutoRedirect).Append('\n');
|
||||
requestLog.Append("connect timeout: " + httpWebRequest.Timeout).Append('\n');
|
||||
requestLog.Append("read write timeout: " + httpWebRequest.ReadWriteTimeout).Append('\n');
|
||||
requestLog.Append("AllowWriteStreamBuffering: " + httpWebRequest.AllowWriteStreamBuffering).Append('\n');
|
||||
//requestLog.Append("proxy: " + (httpWebRequest.Proxy == null ? "null" : ((WebProxy)httpWebRequest.Proxy).Address.ToString()));
|
||||
requestLog.Append("<---");
|
||||
QLog.D(TAG, requestLog.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// print response info
|
||||
/// </summary>
|
||||
/// <param name="httpWebResponse"></param>
|
||||
private static void PrintResponseInfo(HttpWebResponse httpWebResponse)
|
||||
{
|
||||
StringBuilder responseLog = new StringBuilder("--->");
|
||||
responseLog.Append(httpWebResponse.Method).Append(' ').Append(httpWebResponse.ResponseUri.AbsoluteUri).Append('\n');
|
||||
responseLog.Append((int)httpWebResponse.StatusCode).Append(' ').Append(httpWebResponse.StatusDescription).Append('\n'); ;
|
||||
int count = httpWebResponse.Headers.Count;
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
responseLog.Append(httpWebResponse.Headers.GetKey(i)).Append(":").Append(httpWebResponse.Headers.GetValues(i)[0]).Append('\n');
|
||||
}
|
||||
responseLog.Append("<---");
|
||||
QLog.D(TAG, responseLog.ToString());
|
||||
}
|
||||
|
||||
internal static class HttpHeaderHandle
|
||||
{
|
||||
private static MethodInfo addHeaderMethod;
|
||||
private static readonly ICollection<PlatformID> monoPlatforms = new List<PlatformID> { PlatformID.MacOSX, PlatformID.Unix };
|
||||
private static bool? isMonoPlatform;
|
||||
|
||||
internal static void AddHeader(WebHeaderCollection webHeaderCollection, string key, string value)
|
||||
{
|
||||
if (isMonoPlatform == null)
|
||||
{
|
||||
isMonoPlatform = monoPlatforms.Contains(Environment.OSVersion.Platform);
|
||||
}
|
||||
// HTTP headers should be encoded to iso-8859-1,
|
||||
// however it will be encoded automatically by HttpWebRequest in mono.
|
||||
if (false == isMonoPlatform)
|
||||
{
|
||||
// Encode headers for win platforms.
|
||||
|
||||
}
|
||||
if (addHeaderMethod == null)
|
||||
{
|
||||
// Specify the internal method name for adding headers
|
||||
// mono: AddWithoutValidate
|
||||
// win: AddInternal
|
||||
//var internalMethodName = (isMonoPlatform == false) ? "AddWithoutValidate" : "AddInternal";
|
||||
var internalMethodName = "AddWithoutValidate";
|
||||
QLog.D(TAG, internalMethodName.ToString());
|
||||
var method = typeof(WebHeaderCollection).GetMethod(
|
||||
internalMethodName,
|
||||
BindingFlags.NonPublic | BindingFlags.Instance,
|
||||
null,
|
||||
new Type[] { typeof(string), typeof(string) },
|
||||
null);
|
||||
addHeaderMethod = method;
|
||||
}
|
||||
|
||||
addHeaderMethod.Invoke(webHeaderCollection, new Object[] { key, value });
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal class RequestState
|
||||
{
|
||||
public HttpWebRequest httpWebRequest;
|
||||
public HttpWebResponse httpWebResponse;
|
||||
public Response response;
|
||||
public Request request;
|
||||
|
||||
public RequestState()
|
||||
{
|
||||
httpWebRequest = null;
|
||||
httpWebResponse = null;
|
||||
response = null;
|
||||
request = null;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
if (httpWebRequest != null) httpWebRequest.Abort();
|
||||
if (httpWebResponse != null) httpWebResponse.Close();
|
||||
QLog.D(TAG, "Close");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user