Files

414 lines
15 KiB
C#
Raw Permalink Normal View History

using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using COSXML.Network;
using COSXML.Model;
using COSXML.Common;
using COSXML.Auth;
using COSXML.CosException;
using COSXML.Transfer;
using COSXML.Model.Tag;
using COSXML.Log;
using System.IO;
using COSXML.Model.Object;
using COSXML.Utils;
/**
* Copyright (c) 2018 Tencent Cloud. All rights reserved.
* 11/6/2018 8:52:29 PM
* bradyxiao
*/
namespace COSXML.Network
{
/// <summary>
/// input: CosRequest; output: CosResponse
/// </summary>
public sealed class HttpClient
{
private static string TAG = "HttpClient";
private static HttpClientConfig config;
private static QCloudCredentialProvider credentialsProvider;
private static HttpClient instance;
private static Object sync = new Object();
private static Object syncInstance = new Object();
private const int MAX_ACTIVIE_TASKS = 5;
private volatile int activieTasks = 0;
public static HttpClient GetInstance()
{
lock (syncInstance)
{
if (instance == null)
{
instance = new HttpClient();
}
}
return instance;
}
public static void Init(HttpClientConfig config, QCloudCredentialProvider credentialsProvider)
{
lock (sync)
{
if (config == null)
{
throw new CosClientException((int)CosClientError.INVALID_ARGUMENT, "HttpClientConfig = null");
}
HttpClient.config = config;
HttpClient.credentialsProvider = credentialsProvider;
// init grobal httpwebreqeust
CommandTask.Init(HttpClient.config);
}
}
private HttpClient()
{
if (config == null)
{
throw new CosClientException((int)CosClientError.INTERNA_LERROR, "need to call Init(HttpClientConfig, QCloudCredentialProvider) before");
}
}
/// <summary>
/// excute request
/// </summary>
/// <param name="cosRequest"></param>
/// <param name="cosResult"></param>
/// <exception cref="COSXML.CosException.CosClientException">CosClientException</exception>
/// <exception cref="COSXML.CosException.CosServerException">CosServerException</exception>
public void Excute(CosRequest cosRequest, CosResult cosResult)
{
//HttpTask httpTask = new HttpTask();
//httpTask.cosRequest = cosRequest;
//httpTask.cosResult = cosResult;
//httpTask.isSchedue = false;
InternalExcute(cosRequest, cosResult);
}
public void Schedue(CosRequest cosRequest, CosResult cosResult, COSXML.Callback.OnSuccessCallback<CosResult> successCallback,
COSXML.Callback.OnFailedCallback failCallback)
{
//HttpTask httpTask = new HttpTask();
//httpTask.cosRequest = cosRequest;
//httpTask.cosResult = cosResult;
//httpTask.isSchedue = true;
//httpTask.successCallback = successCallback;
//httpTask.failCallback = failCallback;
InternalSchedue(cosRequest, cosResult, successCallback, failCallback);
}
/// <summary>
/// excute request
/// </summary>
/// <param name="cosRequest"></param>
/// <param name="cosResult"></param>
/// <exception cref="COSXML.CosException.CosClientException">CosClientException</exception>
/// <exception cref="COSXML.CosException.CosServerException">CosServerException</exception>
public void InternalExcute(CosRequest cosRequest, CosResult cosResult)
{
try
{
Request request = CreateRequest(cosRequest);
//extern informations exchange
cosResult.ExternInfo(cosRequest);
Response response;
if (cosRequest is GetObjectRequest)
{
GetObjectRequest getObjectRequest = cosRequest as GetObjectRequest;
response = new CosResponse(cosResult, getObjectRequest.GetSaveFilePath(), getObjectRequest.GetLocalFileOffset(),
getObjectRequest.GetCosProgressCallback());
}
else
{
response = new CosResponse(cosResult, null, -1L, null);
}
cosRequest.BindRequest(request);
CommandTask.Excute(request, response, config);
}
catch (CosServerException)
{
throw ;
}
catch (CosClientException)
{
throw ;
}
catch (Exception ex)
{
throw new CosClientException((int)CosClientError.BAD_REQUEST, ex.Message, ex);
}
}
public void excute(Request request, Response response)
{
try
{
CommandTask.Excute(request, response, config);
}
catch (CosServerException)
{
throw ;
}
catch (CosClientException)
{
throw ;
}
catch (Exception ex)
{
throw new CosClientException((int)CosClientError.BAD_REQUEST, ex.Message, ex);
}
}
public void InternalSchedue(CosRequest cosRequest, CosResult cosResult, COSXML.Callback.OnSuccessCallback<CosResult> successCallback,
COSXML.Callback.OnFailedCallback failCallback)
{
try
{
Request request = CreateRequest(cosRequest);
Response response;
if (cosRequest is GetObjectRequest)
{
GetObjectRequest getObjectRequest = cosRequest as GetObjectRequest;
response = new CosResponse(cosResult, getObjectRequest.GetSaveFilePath(), getObjectRequest.GetLocalFileOffset(),
getObjectRequest.GetCosProgressCallback(), successCallback, failCallback);
}
else
{
response = new CosResponse(cosResult, null, -1L, null,successCallback, failCallback);
}
cosRequest.BindRequest(request);
CommandTask.Schedue(request, response, config);
}
catch (CosServerException serverException)
{
//throw serverException;
failCallback(null, serverException);
}
catch (CosClientException clientException)
{
//throw clientException;
failCallback(clientException, null);
}
catch (Exception ex)
{
//throw new CosClientException((int)CosClientError.BAD_REQUEST, ex.Message, ex);
failCallback(new CosClientException((int)CosClientError.BAD_REQUEST, ex.Message, ex), null);
}
}
private Request CreateRequest(CosRequest cosRequest)
{
cosRequest.CheckParameters();
string requestUrlWithSign = cosRequest.RequestURLWithSign;
Request request = new Request();
request.Method = cosRequest.Method;
if (requestUrlWithSign != null)
{
if (requestUrlWithSign.StartsWith("https"))
{
request.IsHttps = true;
}
else
{
request.IsHttps = false;
}
request.RequestUrlString = requestUrlWithSign;
}
else
{
request.IsHttps = (bool)cosRequest.IsHttps;
request.Url = CreateUrl(cosRequest);
request.Host = cosRequest.GetHost();
}
request.UserAgent = config.UserAgnet;
Dictionary<string, string> headers = cosRequest.GetRequestHeaders();
if (headers != null)
{
foreach (KeyValuePair<string, string> pair in headers)
{
request.AddHeader(pair.Key, pair.Value);
}
}
request.Body = cosRequest.GetRequestBody();
// cacluate md5
if (CheckNeedMd5(request, cosRequest.IsNeedMD5) && request.Body != null)
{
request.AddHeader(CosRequestHeaderKey.CONTENT_MD5, request.Body.GetMD5());
}
// content type header
if(request.Body != null && request.Body.ContentType != null &&
!request.Headers.ContainsKey(CosRequestHeaderKey.CONTENT_TYPE)) {
request.AddHeader(CosRequestHeaderKey.CONTENT_TYPE, request.Body.ContentType);
}
//cacluate sign, and add it.
if (requestUrlWithSign == null)
{
cosRequest.GetSignSourceProvider().setCosHost(cosRequest.GetCOSHost());
CheckSign(cosRequest.GetSignSourceProvider(), request);
}
return request;
}
private HttpUrl CreateUrl(CosRequest cosRequest)
{
HttpUrl httpUrl = new HttpUrl();
httpUrl.Scheme = (bool)cosRequest.IsHttps ? "https" : "http";
httpUrl.Host = cosRequest.GetHost();
httpUrl.Path = URLEncodeUtils.EncodePathOfURL(cosRequest.RequestPath);
httpUrl.SetQueryParameters(cosRequest.GetRequestParamters());
return httpUrl;
}
/// <summary>
/// add authorization
/// </summary>
/// <param name="qcloudSignSource">QCloudSignSource</param>
/// <param name="request"></param>
private void CheckSign(QCloudSignSource qcloudSignSource, Request request)
{
// has authorizaiton, notice: using request.Headers otherwise, error
if (request.Headers.ContainsKey(CosRequestHeaderKey.AUTHORIZAIION))
{
QLog.D(TAG, "has add authorizaiton in headers");
return;
}
//has no authorization, but signSourceProvider == null
if (qcloudSignSource == null)
{
QLog.D(TAG, "signSourceProvider == null");
return;
}
if (credentialsProvider == null) throw new ArgumentNullException("credentialsProvider == null");
CosXmlSigner signer = new CosXmlSigner();
signer.Sign(request, qcloudSignSource, credentialsProvider.GetQCloudCredentials());
}
private bool CheckNeedMd5(Request request, bool isNeedMd5)
{
bool result = isNeedMd5;
if (request.Headers.ContainsKey(CosRequestHeaderKey.CONTENT_MD5))
{
result = false;
}
return result;
}
/// <summary>
/// cos response
/// 分为两类:
/// 一类下载文件
/// 一类直接读取数据
/// </summary>
private class CosResponse : Response
{
private CosResult cosResult;
private COSXML.Callback.OnSuccessCallback<CosResult> successCallback;
private COSXML.Callback.OnFailedCallback faileCallback;
private const int MAX_BUFFER_SIZE = 4096;
public CosResponse(CosResult cosResult, string saveFilePath, long saveFileOffset, COSXML.Callback.OnProgressCallback downloadProgressCallback)
{
this.cosResult = cosResult;
if (saveFilePath != null)
{
this.Body = new ResponseBody(saveFilePath, saveFileOffset);
this.Body.ProgressCallback = downloadProgressCallback;
}
else
{
this.Body = new ResponseBody();
}
}
public CosResponse(CosResult cosResult, string saveFilePath, long saveFileOffset, COSXML.Callback.OnProgressCallback downloadProgressCallback,
COSXML.Callback.OnSuccessCallback<CosResult> successCallback,
COSXML.Callback.OnFailedCallback failCallback):this(cosResult, saveFilePath, saveFileOffset, downloadProgressCallback)
{
this.successCallback = successCallback;
this.faileCallback = failCallback;
}
/// <summary>
/// response has been obtain, and parse headers from response
/// </summary>
public override void HandleResponseHeader()
{
cosResult.httpCode = Code;
cosResult.httpMessage = Message;
cosResult.responseHeaders = Headers;
cosResult.InternalParseResponseHeaders();
if (Code >= 300)
{
this.Body.ParseStream = PaserServerError;
}
else
{
this.Body.ParseStream = cosResult.ParseResponseBody;
}
}
public void PaserServerError(Stream inputStream, string contentType, long contentLength)
{
CosServerException cosServerException = new CosServerException(cosResult.httpCode, cosResult.httpMessage);
List<string> values;
Headers.TryGetValue("x-cos-request-id", out values);
cosServerException.requestId = (values != null && values.Count > 0) ? values[0] : null;
Headers.TryGetValue("x-cos-trace-id", out values);
cosServerException.traceId = (values != null && values.Count > 0) ? values[0] : null;
if (inputStream != null)
{
CosServerError cosServerError = new CosServerError();
try
{
XmlParse.ParseCosError(inputStream, cosServerError);
if (cosServerException.requestId != null) cosServerException.requestId = cosServerError.requestId;
if (cosServerException.traceId != null) cosServerException.traceId = cosServerError.traceId;
cosServerException.resource = cosServerError.resource;
cosServerException.errorCode = cosServerError.code;
cosServerException.errorMessage = cosServerError.message;
}
catch (Exception ex)
{
QLog.D(TAG, ex.Message);
}
}
throw cosServerException;
}
/// <summary>
/// error
/// </summary>
/// <param name="ex"></param>
public override void OnFinish(bool isSuccess, Exception ex)
{
if (isSuccess) successCallback(cosResult);
else
{
if (ex is CosClientException) faileCallback(ex as CosClientException, null);
else if (ex is CosServerException) faileCallback(null, ex as CosServerException);
else faileCallback(new CosClientException((int)CosClientError.INTERNA_LERROR, ex.Message, ex), null);
}
}
}
}
}