Files
g.hnyhua.cn/COSXML/Network/HttpClient.cs
2026-02-07 15:48:27 +08:00

414 lines
15 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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);
}
}
}
}
}