初始化
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) Alibaba Cloud Computing
|
||||
* All rights reserved.
|
||||
*
|
||||
* 版权所有 (C)阿里云计算有限公司
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace Aliyun.Api.LOG.Common.Authentication
|
||||
{
|
||||
internal class HmacSHA1Signature : ServiceSignature
|
||||
{
|
||||
private Encoding _encoding = Encoding.UTF8;
|
||||
|
||||
public override string SignatureMethod
|
||||
{
|
||||
get { return "HmacSHA1"; }
|
||||
}
|
||||
|
||||
public override string SignatureVersion
|
||||
{
|
||||
get { return "1"; }
|
||||
}
|
||||
|
||||
public HmacSHA1Signature()
|
||||
{
|
||||
}
|
||||
|
||||
protected override string ComputeSignatureCore(string key, string data)
|
||||
{
|
||||
Debug.Assert(!string.IsNullOrEmpty(data));
|
||||
|
||||
using (KeyedHashAlgorithm algorithm = KeyedHashAlgorithm.Create(
|
||||
this.SignatureMethod.ToString().ToUpperInvariant()))
|
||||
{
|
||||
algorithm.Key = _encoding.GetBytes(key.ToCharArray());
|
||||
return Convert.ToBase64String(
|
||||
algorithm.ComputeHash(_encoding.GetBytes(data.ToCharArray())));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Created by SharpDevelop.
|
||||
* User: xiaoming.yin
|
||||
* Date: 2012/5/30
|
||||
* Time: 14:18
|
||||
*
|
||||
* To change this template use Tools | Options | Coding | Edit Standard Headers.
|
||||
*/
|
||||
using System;
|
||||
using Aliyun.Api.LOG.Common.Communication;
|
||||
|
||||
namespace Aliyun.Api.LOG.Common.Authentication
|
||||
{
|
||||
/// <summary>
|
||||
/// Description of IRequestSigner.
|
||||
/// </summary>
|
||||
internal interface IRequestSigner
|
||||
{
|
||||
/// <summary>
|
||||
/// Signs a request.
|
||||
/// </summary>
|
||||
/// <param name="request">The request to sign.</param>
|
||||
/// <param name="credentials">The credentials used to sign.</param>
|
||||
void Sign(ServiceRequest request, ServiceCredentials credentials);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (C) Alibaba Cloud Computing
|
||||
* All rights reserved.
|
||||
*
|
||||
* 版权所有 (C)阿里云计算有限公司
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace Aliyun.Api.LOG.Common.Authentication
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the credentials used to access Aliyun Open Services.
|
||||
/// </summary>
|
||||
internal class ServiceCredentials
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the access ID.
|
||||
/// </summary>
|
||||
public string AccessId { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the access key.
|
||||
/// </summary>
|
||||
public string AccessKey { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initialize an new instance of <see cref="ServiceCredentials"/>.
|
||||
/// </summary>
|
||||
/// <param name="accessId">The access ID.</param>
|
||||
/// <param name="accessKey">The access key.</param>
|
||||
public ServiceCredentials(string accessId, string accessKey)
|
||||
{
|
||||
if (string.IsNullOrEmpty(accessId))
|
||||
throw new ArgumentException(Aliyun.Api.LOG.Properties.Resources.ExceptionIfArgumentStringIsNullOrEmpty, "accessId");
|
||||
|
||||
AccessId = accessId;
|
||||
AccessKey = accessKey;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (C) Alibaba Cloud Computing
|
||||
* All rights reserved.
|
||||
*
|
||||
* 版权所有 (C)阿里云计算有限公司
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace Aliyun.Api.LOG.Common.Authentication
|
||||
{
|
||||
internal abstract class ServiceSignature
|
||||
{
|
||||
public abstract string SignatureMethod { get; }
|
||||
|
||||
public abstract string SignatureVersion { get; }
|
||||
|
||||
protected ServiceSignature()
|
||||
{
|
||||
}
|
||||
|
||||
public string ComputeSignature(String key, String data)
|
||||
{
|
||||
if (string.IsNullOrEmpty(key))
|
||||
throw new ArgumentException(Aliyun.Api.LOG.Properties.Resources.ExceptionIfArgumentStringIsNullOrEmpty, "key");
|
||||
if (string.IsNullOrEmpty(data))
|
||||
throw new ArgumentException(Aliyun.Api.LOG.Properties.Resources.ExceptionIfArgumentStringIsNullOrEmpty, "data");
|
||||
|
||||
return ComputeSignatureCore(key, data);
|
||||
}
|
||||
|
||||
protected abstract string ComputeSignatureCore(string key, string data);
|
||||
|
||||
public static ServiceSignature Create()
|
||||
{
|
||||
return new HmacSHA1Signature();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Created by SharpDevelop.
|
||||
* User: xiaoming.yin
|
||||
* Date: 2012/5/30
|
||||
* Time: 14:21
|
||||
*
|
||||
* To change this template use Tools | Options | Coding | Edit Standard Headers.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Aliyun.Api.LOG.Common.Authentication;
|
||||
using Aliyun.Api.LOG.Common.Handlers;
|
||||
|
||||
namespace Aliyun.Api.LOG.Common.Communication
|
||||
{
|
||||
/// <summary>
|
||||
/// Description of ExecutionContext.
|
||||
/// </summary>
|
||||
internal class ExecutionContext
|
||||
{
|
||||
/// <summary>
|
||||
/// The default encoding (charset name).
|
||||
/// </summary>
|
||||
private const string DefaultEncoding = "utf-8";
|
||||
|
||||
private IList<IResponseHandler> _responseHandlers = new List<IResponseHandler>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the charset.
|
||||
/// </summary>
|
||||
public string Charset { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the request signer.
|
||||
/// </summary>
|
||||
public IRequestSigner Signer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the credentials.
|
||||
/// </summary>
|
||||
public ServiceCredentials Credentials { get; set ;}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of <see cref="IResponseHandler" />.
|
||||
/// </summary>
|
||||
public IList<IResponseHandler> ResponseHandlers
|
||||
{
|
||||
get { return _responseHandlers; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
public ExecutionContext()
|
||||
{
|
||||
this.Charset = DefaultEncoding;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) Alibaba Cloud Computing
|
||||
* All rights reserved.
|
||||
*
|
||||
* 版权所有 (C)阿里云计算有限公司
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace Aliyun.Api.LOG.Common.Communication
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a HTTP method.
|
||||
/// </summary>
|
||||
internal enum HttpMethod
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents HTTP GET. Default value.
|
||||
/// </summary>
|
||||
Get = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Represents HTTP DELETE.
|
||||
/// </summary>
|
||||
Delete,
|
||||
|
||||
/// <summary>
|
||||
/// Represents HTTP HEAD.
|
||||
/// </summary>
|
||||
Head,
|
||||
|
||||
/// <summary>
|
||||
/// Represents HTTP POST.
|
||||
/// </summary>
|
||||
Post,
|
||||
|
||||
/// <summary>
|
||||
/// Represents HTTP PUT.
|
||||
/// </summary>
|
||||
Put,
|
||||
|
||||
/// <summary>
|
||||
/// Represents HTTP OPTIONS.
|
||||
/// </summary>
|
||||
Options,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) Alibaba Cloud Computing
|
||||
* All rights reserved.
|
||||
*
|
||||
* 版权所有 (C)阿里云计算有限公司
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace Aliyun.Api.LOG.Common.Communication
|
||||
{
|
||||
/// <summary>
|
||||
/// Represent the channel that communicates with an Aliyun Open Service.
|
||||
/// </summary>
|
||||
internal interface IServiceClient
|
||||
{
|
||||
/// <summary>
|
||||
/// Sends a request to the service.
|
||||
/// </summary>
|
||||
/// <param name="request">The request data.</param>
|
||||
/// <param name="context">The execution context.</param>
|
||||
/// <returns>The response data.</returns>
|
||||
ServiceResponse Send(ServiceRequest request, ExecutionContext context);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (C) Alibaba Cloud Computing
|
||||
* All rights reserved.
|
||||
*
|
||||
* 版权所有 (C)阿里云计算有限公司
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Net;
|
||||
using Aliyun.Api.LOG;
|
||||
using Aliyun.Api.LOG.Utilities;
|
||||
using Aliyun.Api.LOG.Common;
|
||||
using Aliyun.Api.LOG.Common.Communication;
|
||||
using Aliyun.Api.LOG.Common.Handlers;
|
||||
using Aliyun.Api.LOG.Common.Utilities;
|
||||
|
||||
namespace Aliyun.Api.LOG.Common.Communication
|
||||
{
|
||||
/// <summary>
|
||||
/// The default implementation of <see cref="IServiceClient" />.
|
||||
/// </summary>
|
||||
internal abstract class ServiceClient : IServiceClient
|
||||
{
|
||||
|
||||
#region Fields and Properties
|
||||
|
||||
private ClientConfiguration _configuration;
|
||||
|
||||
public ClientConfiguration Configuration
|
||||
{
|
||||
get { return _configuration; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
protected ServiceClient(ClientConfiguration configuration)
|
||||
{
|
||||
Debug.Assert(configuration != null);
|
||||
// Make a definsive copy to ensure the class is immutable.
|
||||
_configuration = (ClientConfiguration)configuration.Clone();
|
||||
}
|
||||
|
||||
public static ServiceClient Create(ClientConfiguration configuration)
|
||||
{
|
||||
return new ServiceClientImpl(configuration);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IServiceClient Members
|
||||
|
||||
public ServiceResponse Send(ServiceRequest request, ExecutionContext context)
|
||||
{
|
||||
Debug.Assert(request != null);
|
||||
SignRequest(request, context);
|
||||
ServiceResponse response = SendCore(request, context);
|
||||
HandleResponse(response, context.ResponseHandlers);
|
||||
return response;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
protected abstract ServiceResponse SendCore(ServiceRequest request, ExecutionContext context);
|
||||
|
||||
|
||||
internal static void SignRequest(ServiceRequest request, ExecutionContext context)
|
||||
{
|
||||
if (context.Signer != null)
|
||||
{
|
||||
context.Signer.Sign(request, context.Credentials);
|
||||
}
|
||||
}
|
||||
|
||||
protected static void HandleResponse(ServiceResponse response, IList<IResponseHandler> handlers)
|
||||
{
|
||||
foreach(IResponseHandler handler in handlers)
|
||||
{
|
||||
handler.Handle(response);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,429 @@
|
||||
/*
|
||||
* Copyright (C) Alibaba Cloud Computing
|
||||
* All rights reserved.
|
||||
*
|
||||
* 版权所有 (C)阿里云计算有限公司
|
||||
*/
|
||||
//#define __UT_TEST_0EC173788C65DD08DA60575219707632__
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Reflection;
|
||||
using Aliyun.Api.LOG;
|
||||
using Aliyun.Api.LOG.Common.Utilities;
|
||||
using Aliyun.Api.LOG.Utilities;
|
||||
|
||||
namespace Aliyun.Api.LOG.Common.Communication
|
||||
{
|
||||
/// <summary>
|
||||
/// An default <see cref="ServiceClient"/> implementation that
|
||||
/// communicates with Aliyun Services over the HTTP protocol.
|
||||
/// </summary>
|
||||
internal class ServiceClientImpl : ServiceClient
|
||||
{
|
||||
|
||||
#region Embeded Classes
|
||||
|
||||
/// <summary>
|
||||
/// Represents the async operation of requests in <see cref="ServiceClientImpl"/>.
|
||||
/// </summary>
|
||||
private class HttpAsyncResult : AsyncResult<ServiceResponse>
|
||||
{
|
||||
public HttpWebRequest WebRequest { get; set; }
|
||||
|
||||
public ExecutionContext Context { get; set; }
|
||||
|
||||
public HttpAsyncResult(AsyncCallback callback, object state)
|
||||
: base(callback, state)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents the response data of <see cref="ServiceClientImpl"/> requests.
|
||||
/// </summary>
|
||||
internal class ResponseImpl : ServiceResponse
|
||||
{
|
||||
private bool _disposed;
|
||||
private HttpWebResponse _response;
|
||||
private Exception _failure;
|
||||
#if(__UT_TEST_0EC173788C65DD08DA60575219707632__)
|
||||
private HttpStatusCode _httpStatusCode = HttpStatusCode.OK;
|
||||
#endif
|
||||
public override HttpStatusCode StatusCode
|
||||
{
|
||||
get
|
||||
{
|
||||
#if(__UT_TEST_0EC173788C65DD08DA60575219707632__)
|
||||
return _httpStatusCode;
|
||||
#else
|
||||
return _response.StatusCode;
|
||||
#endif
|
||||
}
|
||||
#if(__UT_TEST_0EC173788C65DD08DA60575219707632__)
|
||||
set {
|
||||
_httpStatusCode = value;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
public override Exception Failure {
|
||||
get
|
||||
{
|
||||
return this._failure;
|
||||
}
|
||||
}
|
||||
|
||||
public override IDictionary<string, string> Headers
|
||||
{
|
||||
get
|
||||
{
|
||||
ThrowIfObjectDisposed();
|
||||
if (_headers == null)
|
||||
{
|
||||
_headers = GetResponseHeaders(_response);
|
||||
}
|
||||
|
||||
return _headers;
|
||||
}
|
||||
|
||||
}
|
||||
#if(__UT_TEST_0EC173788C65DD08DA60575219707632__)
|
||||
private Stream _stream;
|
||||
#endif
|
||||
public override Stream Content
|
||||
{
|
||||
get
|
||||
{
|
||||
ThrowIfObjectDisposed();
|
||||
|
||||
try
|
||||
{
|
||||
#if(__UT_TEST_0EC173788C65DD08DA60575219707632__)
|
||||
return _response != null ?
|
||||
_response.GetResponseStream() : _stream;
|
||||
#else
|
||||
return _response != null ?
|
||||
_response.GetResponseStream() : null;
|
||||
#endif
|
||||
}
|
||||
catch (ProtocolViolationException ex)
|
||||
{
|
||||
throw new InvalidOperationException(ex.Message, ex);
|
||||
}
|
||||
}
|
||||
#if(__UT_TEST_0EC173788C65DD08DA60575219707632__)
|
||||
set
|
||||
{
|
||||
_stream = value;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
public ResponseImpl(HttpWebResponse httpWebResponse)
|
||||
{
|
||||
Debug.Assert(httpWebResponse != null);
|
||||
_response = httpWebResponse;
|
||||
|
||||
Debug.Assert(this.IsSuccessful(), "This constructor only allows a successfull response.");
|
||||
}
|
||||
|
||||
public ResponseImpl(WebException failure)
|
||||
{
|
||||
Debug.Assert(failure != null);
|
||||
HttpWebResponse httpWebResponse = failure.Response as HttpWebResponse;
|
||||
Debug.Assert(httpWebResponse != null);
|
||||
|
||||
_failure = failure;
|
||||
_response = httpWebResponse;
|
||||
Debug.Assert(!this.IsSuccessful(), "This constructor only allows a failed response.");
|
||||
}
|
||||
//#if(__UT_TEST_0EC173788C65DD08DA60575219707632__)
|
||||
internal ResponseImpl()
|
||||
{
|
||||
}
|
||||
//#endif
|
||||
|
||||
|
||||
private static IDictionary<string, string> GetResponseHeaders(HttpWebResponse response)
|
||||
{
|
||||
#if(__UT_TEST_0EC173788C65DD08DA60575219707632__)
|
||||
if (response == null)
|
||||
{
|
||||
IDictionary<string, string> testHeaders = new Dictionary<String, String>();
|
||||
testHeaders.Add(LogConsts.NAME_HEADER_AUTH, "LOG mockkeyid:EX2VSCpdyFrcysmBaQ+aokupwcg=");
|
||||
return testHeaders;
|
||||
}
|
||||
#endif
|
||||
var headers = response.Headers;
|
||||
var result = new Dictionary<string, string>(headers.Count,StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
for (int i = 0; i < headers.Count; i++)
|
||||
{
|
||||
var key = headers.Keys[i];
|
||||
var value = headers.Get(key);
|
||||
result.Add(key,
|
||||
HttpUtils.ReEncode(
|
||||
value,
|
||||
HttpUtils.Iso88591Charset,
|
||||
HttpUtils.UTF8Charset));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
if (_disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
if (_response != null)
|
||||
{
|
||||
_response.Close();
|
||||
_response = null;
|
||||
}
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void ThrowIfObjectDisposed()
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
throw new ObjectDisposedException(this.GetType().Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public ServiceClientImpl(ClientConfiguration configuration)
|
||||
: base(configuration)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Implementations
|
||||
internal delegate ServiceResponse WebSend(HttpWebRequest request);
|
||||
internal WebSend SendMethod = DefaultSend;
|
||||
internal static ResponseImpl DefaultSend(HttpWebRequest request)
|
||||
{
|
||||
var response = request.GetResponse() as HttpWebResponse;
|
||||
return new ResponseImpl(response);
|
||||
}
|
||||
private static ServiceResponse HandleException(WebException ex)
|
||||
{
|
||||
var response = ex.Response as HttpWebResponse;
|
||||
if (response == null)
|
||||
{
|
||||
throw new LogException("LogRequestError", "request is failed.", ex);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new ResponseImpl(ex);
|
||||
}
|
||||
}
|
||||
protected override ServiceResponse SendCore(ServiceRequest serviceRequest,
|
||||
ExecutionContext context)
|
||||
{
|
||||
try
|
||||
{
|
||||
serviceRequest.HttpRequest = HttpFactory.CreateWebRequest(serviceRequest, Configuration);
|
||||
#if(!__UT_TEST_0EC173788C65DD08DA60575219707632__)
|
||||
SetRequestContent(serviceRequest.HttpRequest, serviceRequest);
|
||||
#endif
|
||||
|
||||
return SendMethod(serviceRequest.HttpRequest);
|
||||
}
|
||||
catch (WebException ex)
|
||||
{
|
||||
return HandleException(ex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void SetRequestContent(HttpWebRequest webRequest,
|
||||
ServiceRequest serviceRequest)
|
||||
{
|
||||
|
||||
var data = serviceRequest.BuildRequestContent();
|
||||
|
||||
if (data == null ||
|
||||
(serviceRequest.Method != HttpMethod.Put &&
|
||||
serviceRequest.Method != HttpMethod.Post))
|
||||
{
|
||||
// Skip setting content body in this case.
|
||||
webRequest.ContentLength = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Write data to the request stream.
|
||||
long userSetContentLength = -1;
|
||||
if (serviceRequest.Headers.ContainsKey(Aliyun.Api.LOG.Common.Utilities.HttpHeaders.ContentLength))
|
||||
{
|
||||
userSetContentLength = long.Parse(serviceRequest.Headers[Aliyun.Api.LOG.Common.Utilities.HttpHeaders.ContentLength]);
|
||||
}
|
||||
|
||||
long streamLength = data.Length - data.Position;
|
||||
webRequest.ContentLength = (userSetContentLength >= 0 && userSetContentLength <= streamLength) ?
|
||||
userSetContentLength : streamLength;
|
||||
|
||||
webRequest.KeepAlive = false;
|
||||
try
|
||||
{
|
||||
webRequest.ServicePoint.ConnectionLeaseTimeout = 5000;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// https://github.com/dotnet/standard/issues/642
|
||||
}
|
||||
|
||||
webRequest.ServicePoint.MaxIdleTime = 5000;
|
||||
webRequest.ServicePoint.ConnectionLimit = 1000;
|
||||
webRequest.ServicePoint.Expect100Continue = false;
|
||||
// Generate GUID for connection group name, force close it when request is done.
|
||||
webRequest.ConnectionGroupName = Guid.NewGuid().ToString();
|
||||
|
||||
using (var requestStream = webRequest.GetRequestStream())
|
||||
{
|
||||
data.WriteTo(requestStream, webRequest.ContentLength);
|
||||
data.Seek(0, SeekOrigin.Begin);
|
||||
requestStream.Flush();
|
||||
requestStream.Close();
|
||||
|
||||
}
|
||||
data.Close();
|
||||
data.Dispose();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
internal static class HttpFactory
|
||||
{
|
||||
internal static HttpWebRequest CreateWebRequest(ServiceRequest serviceRequest, ClientConfiguration configuration)
|
||||
{
|
||||
Debug.Assert(serviceRequest != null && configuration != null);
|
||||
|
||||
HttpWebRequest webRequest = WebRequest.Create(serviceRequest.BuildRequestUri()) as HttpWebRequest;
|
||||
|
||||
SetRequestHeaders(webRequest, serviceRequest, configuration);
|
||||
SetRequestProxy(webRequest, configuration);
|
||||
|
||||
return webRequest;
|
||||
}
|
||||
|
||||
// Set request headers
|
||||
private static void SetRequestHeaders(HttpWebRequest webRequest, ServiceRequest serviceRequest,
|
||||
ClientConfiguration configuration)
|
||||
{
|
||||
webRequest.Timeout = configuration.ConnectionTimeout;
|
||||
webRequest.ReadWriteTimeout = configuration.ReadWriteTimeout;
|
||||
webRequest.Method = serviceRequest.Method.ToString().ToUpperInvariant();
|
||||
|
||||
// Because it is not allowed to set common headers
|
||||
// with the WebHeaderCollection.Add method,
|
||||
// we have to call an internal method to skip validation.
|
||||
foreach (var h in serviceRequest.Headers)
|
||||
{
|
||||
//if (h.Key.CompareTo(LogConsts.NAME_HEADER_HOST) == 0)
|
||||
// webRequest.Host = h.Value;
|
||||
//else if (h.Key.CompareTo(LogConsts.NAME_HEADER_DATE) == 0)
|
||||
// webRequest.Date = DateUtils.ParseRfc822Date(h.Value);
|
||||
//if (h.Key.CompareTo(LogConsts.NAME_HEADER_CONTENTTYPE) == 0)
|
||||
// webRequest.ContentType = h.Value;
|
||||
//else
|
||||
webRequest.Headers.AddInternal(h.Key, h.Value);
|
||||
}
|
||||
|
||||
// Set user-agent
|
||||
if (!string.IsNullOrEmpty(configuration.UserAgent))
|
||||
{
|
||||
webRequest.UserAgent = configuration.UserAgent;
|
||||
}
|
||||
}
|
||||
|
||||
// Set proxy
|
||||
private static void SetRequestProxy(HttpWebRequest webRequest, ClientConfiguration configuration)
|
||||
{
|
||||
// Perf Improvement:
|
||||
// If HttpWebRequest.Proxy is not set to null explicitly,
|
||||
// it will try to load the IE proxy settings including auto proxy detection,
|
||||
// which is quite time consuming.
|
||||
webRequest.Proxy = null;
|
||||
|
||||
// Set proxy if proxy settings are specified.
|
||||
if (!string.IsNullOrEmpty(configuration.ProxyHost))
|
||||
{
|
||||
if (configuration.ProxyPort < 0)
|
||||
{
|
||||
webRequest.Proxy = new WebProxy(configuration.ProxyHost);
|
||||
} else
|
||||
{
|
||||
webRequest.Proxy = new WebProxy(configuration.ProxyHost, configuration.ProxyPort);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(configuration.ProxyUserName)) {
|
||||
webRequest.Proxy.Credentials = String.IsNullOrEmpty(configuration.ProxyDomain) ?
|
||||
new NetworkCredential(configuration.ProxyUserName, configuration.ProxyPassword ?? string.Empty) :
|
||||
new NetworkCredential(configuration.ProxyUserName, configuration.ProxyPassword ?? string.Empty,
|
||||
configuration.ProxyDomain);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal static class HttpExtensions
|
||||
{
|
||||
private static MethodInfo _addInternalMethod;
|
||||
private static ICollection<PlatformID> monoPlatforms = new List<PlatformID>
|
||||
{ PlatformID.MacOSX, PlatformID.Unix };
|
||||
private static bool? isMonoPlatform;
|
||||
|
||||
internal static void AddInternal(this WebHeaderCollection headers, string key, string value)
|
||||
{
|
||||
if (isMonoPlatform == null)
|
||||
{
|
||||
isMonoPlatform = monoPlatforms.Contains(System.Environment.OSVersion.Platform);
|
||||
}
|
||||
|
||||
// HTTP headers should be encoded to iso-8859-1,
|
||||
// however it will be encoded automatically by HttpWebRequest in mono.
|
||||
if (isMonoPlatform == false)
|
||||
// Encode headers for win platforms.
|
||||
value = HttpUtils.ReEncode(
|
||||
value,
|
||||
HttpUtils.UTF8Charset,
|
||||
HttpUtils.Iso88591Charset);
|
||||
|
||||
if (_addInternalMethod == null)
|
||||
{
|
||||
// Specify the internal method name for adding headers
|
||||
// mono: AddWithoutValidate
|
||||
// win: AddInternal
|
||||
string internalMethodName = (isMonoPlatform == true) ? "AddWithoutValidate" : "AddInternal";
|
||||
|
||||
MethodInfo mi = typeof(WebHeaderCollection).GetMethod(
|
||||
internalMethodName,
|
||||
BindingFlags.NonPublic | BindingFlags.Instance,
|
||||
null,
|
||||
new Type[] { typeof(string), typeof(string) },
|
||||
null);
|
||||
_addInternalMethod = mi;
|
||||
}
|
||||
|
||||
_addInternalMethod.Invoke(headers, new object[] { key, value });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) Alibaba Cloud Computing
|
||||
* All rights reserved.
|
||||
*
|
||||
* 版权所有 (C)阿里云计算有限公司
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Aliyun.Api.LOG.Common.Communication
|
||||
{
|
||||
/// <summary>
|
||||
/// Description of ServiceMessage.
|
||||
/// </summary>
|
||||
internal class ServiceMessage
|
||||
{
|
||||
// HTTP header keys are case-insensitive.
|
||||
protected IDictionary<String, String> _headers;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the dictionary of HTTP headers.
|
||||
/// </summary>
|
||||
public virtual IDictionary<String, String> Headers
|
||||
{
|
||||
get { return _headers; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the content stream.
|
||||
/// </summary>
|
||||
public virtual Stream Content { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
public ServiceMessage()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Copyright (C) Alibaba Cloud Computing
|
||||
* All rights reserved.
|
||||
*
|
||||
* 版权所有 (C)阿里云计算有限公司
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
using Aliyun.Api.LOG.Common.Utilities;
|
||||
using System.Net;
|
||||
|
||||
namespace Aliyun.Api.LOG.Common.Communication
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the information for sending requests.
|
||||
/// </summary>
|
||||
internal class ServiceRequest : ServiceMessage, IDisposable
|
||||
{
|
||||
private bool _disposed;
|
||||
|
||||
private IDictionary<String, String> parameters =
|
||||
new Dictionary<String, String>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the endpoint.
|
||||
/// </summary>
|
||||
public Uri Endpoint { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the resource path of the request URI.
|
||||
/// </summary>
|
||||
public String ResourcePath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the HTTP method.
|
||||
/// </summary>
|
||||
public HttpMethod Method { get; set; }
|
||||
|
||||
public HttpWebRequest HttpRequest { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the dictionary of the request parameters.
|
||||
/// </summary>
|
||||
public IDictionary<String, String> Parameters{
|
||||
get { return parameters; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the request can be repeated.
|
||||
/// </summary>
|
||||
public bool IsRepeatable
|
||||
{
|
||||
get { return this.Content == null || this.Content.CanSeek; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constuctor.
|
||||
/// </summary>
|
||||
public ServiceRequest()
|
||||
{
|
||||
_headers = new Dictionary<String, String>(StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Build the request URI from the request message.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public string BuildRequestUri()
|
||||
{
|
||||
const string delimiter = "/";
|
||||
String uri = Endpoint.ToString();
|
||||
if (!uri.EndsWith(delimiter)
|
||||
&& (ResourcePath == null ||
|
||||
!ResourcePath.StartsWith(delimiter)))
|
||||
{
|
||||
uri += delimiter;
|
||||
}
|
||||
else if (uri.EndsWith(delimiter) && (ResourcePath != null && ResourcePath.StartsWith(delimiter)))
|
||||
{
|
||||
uri = uri.Substring(0, uri.Length - 1);
|
||||
}
|
||||
|
||||
if (ResourcePath != null){
|
||||
uri += ResourcePath;
|
||||
}
|
||||
|
||||
if (IsParameterInUri())
|
||||
{
|
||||
String paramString = HttpUtils.GetRequestParameterString(parameters);
|
||||
if (!string.IsNullOrEmpty(paramString))
|
||||
{
|
||||
uri += "?" + paramString;
|
||||
}
|
||||
}
|
||||
return uri;
|
||||
}
|
||||
|
||||
public Stream BuildRequestContent()
|
||||
{
|
||||
if (!IsParameterInUri())
|
||||
{
|
||||
String paramString = HttpUtils.GetRequestParameterString(parameters);
|
||||
if (!string.IsNullOrEmpty(paramString))
|
||||
{
|
||||
byte[] buffer = Encoding.GetEncoding("utf-8").GetBytes(paramString);
|
||||
Stream content = new MemoryStream();
|
||||
content.Write(buffer, 0, buffer.Length);
|
||||
content.Flush();
|
||||
// Move the marker to the beginning for further read.
|
||||
content.Seek(0, SeekOrigin.Begin);
|
||||
return content;
|
||||
}
|
||||
}
|
||||
|
||||
return this.Content;
|
||||
}
|
||||
|
||||
private bool IsParameterInUri()
|
||||
{
|
||||
bool requestHasPayload = this.Content != null;
|
||||
bool requestIsPost = this.Method == HttpMethod.Post;
|
||||
bool putParamsInUri = !requestIsPost || requestHasPayload;
|
||||
return putParamsInUri;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
this.Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
if (Content != null)
|
||||
{
|
||||
Content.Close();
|
||||
Content = null;
|
||||
}
|
||||
if (HttpRequest != null)
|
||||
{
|
||||
// force close connection group
|
||||
//Console.WriteLine(HttpRequest.ConnectionGroupName + "[]" + HttpRequest.ConnectionGroupName.Length.ToString() + "[]" + HttpRequest.ServicePoint.CurrentConnections.ToString());
|
||||
HttpRequest.ServicePoint.CloseConnectionGroup(HttpRequest.ConnectionGroupName);
|
||||
HttpRequest.Abort();
|
||||
HttpRequest = null;
|
||||
}
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (C) Alibaba Cloud Computing
|
||||
* All rights reserved.
|
||||
*
|
||||
* 版权所有 (C)阿里云计算有限公司
|
||||
*/
|
||||
//#define __UT_TEST_0EC173788C65DD08DA60575219707632__
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
|
||||
namespace Aliyun.Api.LOG.Common.Communication
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the data of the responses of requests.
|
||||
/// </summary>
|
||||
internal abstract class ServiceResponse : ServiceMessage, IDisposable
|
||||
{
|
||||
public abstract HttpStatusCode StatusCode {
|
||||
get;
|
||||
#if(__UT_TEST_0EC173788C65DD08DA60575219707632__)
|
||||
set;
|
||||
#endif
|
||||
}
|
||||
|
||||
public abstract Exception Failure { get; }
|
||||
|
||||
public virtual bool IsSuccessful()
|
||||
{
|
||||
return (int)this.StatusCode / 100 == (int)HttpStatusCode.OK / 100;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Throws the exception from communication if the status code is not 2xx.
|
||||
/// </summary>
|
||||
public virtual void EnsureSuccessful()
|
||||
{
|
||||
if (!IsSuccessful())
|
||||
{
|
||||
// Disposing the content should help users: If users call EnsureSuccessStatusCode(), an exception is
|
||||
// thrown if the response status code is != 2xx. I.e. the behavior is similar to a failed request (e.g.
|
||||
// connection failure). Users don't expect to dispose the content in this case: If an exception is
|
||||
// thrown, the object is responsible fore cleaning up its state.
|
||||
if (Content != null)
|
||||
{
|
||||
Content.Dispose();
|
||||
}
|
||||
|
||||
Debug.Assert(this.Failure != null);
|
||||
throw this.Failure;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
public ServiceResponse()
|
||||
{
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
this.Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) Alibaba Cloud Computing
|
||||
* All rights reserved.
|
||||
*
|
||||
* 版权所有 (C)阿里云计算有限公司
|
||||
*/
|
||||
|
||||
using System;
|
||||
using Aliyun.Api.LOG.Common.Communication;
|
||||
|
||||
namespace Aliyun.Api.LOG.Common.Handlers
|
||||
{
|
||||
/// <summary>
|
||||
/// Handles the response message from the services.
|
||||
/// </summary>
|
||||
internal interface IResponseHandler
|
||||
{
|
||||
void Handle(ServiceResponse response);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (C) Alibaba Cloud Computing
|
||||
* All rights reserved.
|
||||
*
|
||||
* 版权所有 (C)阿里云计算有限公司
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using Aliyun.Api.LOG.Common.Communication;
|
||||
|
||||
namespace Aliyun.Api.LOG.Common.Handlers
|
||||
{
|
||||
/// <summary>
|
||||
/// Description of ResponseHandler.
|
||||
/// </summary>
|
||||
internal class ResponseHandler : IResponseHandler
|
||||
{
|
||||
public ResponseHandler()
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void Handle(ServiceResponse response)
|
||||
{
|
||||
Debug.Assert(response != null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
|
||||
namespace Aliyun.Api.LOG.Common
|
||||
{
|
||||
/// <summary>
|
||||
/// The implementation of <see cref="IAsyncResult"/>
|
||||
/// that represents the status of an async operation.
|
||||
/// </summary>
|
||||
internal abstract class AsyncResult : IAsyncResult, IDisposable
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private object _asyncState;
|
||||
private bool _completedSynchronously;
|
||||
private bool _isCompleted;
|
||||
private AsyncCallback _userCallback;
|
||||
private ManualResetEvent _asyncWaitEvent;
|
||||
private Exception _exception;
|
||||
|
||||
#endregion
|
||||
|
||||
#region IAsyncResult Members
|
||||
|
||||
/// <summary>
|
||||
/// Gets a user-defined object that qualifies or contains information about an asynchronous operation.
|
||||
/// </summary>
|
||||
[DebuggerNonUserCode]
|
||||
public object AsyncState
|
||||
{
|
||||
get
|
||||
{
|
||||
return _asyncState;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="WaitHandle"/> that is used to wait for an asynchronous operation to complete.
|
||||
/// </summary>
|
||||
[DebuggerNonUserCode]
|
||||
public WaitHandle AsyncWaitHandle
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_asyncWaitEvent != null)
|
||||
{
|
||||
return _asyncWaitEvent;
|
||||
}
|
||||
|
||||
ManualResetEvent manualResetEvent = new ManualResetEvent(false);
|
||||
if (Interlocked.CompareExchange<ManualResetEvent>(ref _asyncWaitEvent, manualResetEvent, null) != null)
|
||||
{
|
||||
manualResetEvent.Close();
|
||||
}
|
||||
if (this.IsCompleted)
|
||||
{
|
||||
_asyncWaitEvent.Set();
|
||||
}
|
||||
|
||||
return _asyncWaitEvent;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value that indicates whether the asynchronous operation completed synchronously.
|
||||
/// </summary>
|
||||
[DebuggerNonUserCode]
|
||||
public bool CompletedSynchronously
|
||||
{
|
||||
get
|
||||
{
|
||||
return _completedSynchronously;
|
||||
}
|
||||
protected set
|
||||
{
|
||||
_completedSynchronously = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value that indicates whether the asynchronous operation has completed.
|
||||
/// </summary>
|
||||
[DebuggerNonUserCode]
|
||||
public bool IsCompleted
|
||||
{
|
||||
get
|
||||
{
|
||||
return _isCompleted;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Initializes an instance of <see cref="AsyncResult"/>.
|
||||
/// </summary>
|
||||
/// <param name="callback">The callback method when the async operation completes.</param>
|
||||
/// <param name="state">A user-defined object that qualifies or contains information about an asynchronous operation.</param>
|
||||
protected AsyncResult(AsyncCallback callback, object state)
|
||||
{
|
||||
_userCallback = callback;
|
||||
_asyncState = state;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Completes the async operation with an exception.
|
||||
/// </summary>
|
||||
/// <param name="ex">Exception from the async operation.</param>
|
||||
public void Complete(Exception ex)
|
||||
{
|
||||
// Complete should not throw if disposed.
|
||||
Debug.Assert(ex != null);
|
||||
_exception = ex;
|
||||
this.NotifyCompletion();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When called in the dervied classes, wait for completion.
|
||||
/// It throws exception if the async operation ends with an exception.
|
||||
/// </summary>
|
||||
protected void WaitForCompletion()
|
||||
{
|
||||
if (!this.IsCompleted)
|
||||
{
|
||||
_asyncWaitEvent.WaitOne();
|
||||
}
|
||||
|
||||
if (this._exception != null)
|
||||
{
|
||||
throw this._exception;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When called in the derived classes, notify operation completion
|
||||
/// by setting <see cref="P:AsyncWaitHandle"/> and calling the user callback.
|
||||
/// </summary>
|
||||
[DebuggerNonUserCode]
|
||||
protected void NotifyCompletion()
|
||||
{
|
||||
_isCompleted = true;
|
||||
if (_asyncWaitEvent != null)
|
||||
{
|
||||
_asyncWaitEvent.Set();
|
||||
}
|
||||
|
||||
if (_userCallback != null)
|
||||
{
|
||||
_userCallback(this);
|
||||
}
|
||||
}
|
||||
|
||||
#region IDisposable Members
|
||||
|
||||
/// <summary>
|
||||
/// Disposes the object and release resource.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
this.Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When overrided in the derived classes, release resources.
|
||||
/// </summary>
|
||||
/// <param name="disposing">Whether the method is called <see cref="M:Dispose"/></param>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && _asyncWaitEvent != null)
|
||||
{
|
||||
_asyncWaitEvent.Close();
|
||||
_asyncWaitEvent = null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents the status of an async operation.
|
||||
/// It also holds the result of the operation.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of the operation result.</typeparam>
|
||||
internal class AsyncResult<T> : AsyncResult
|
||||
{
|
||||
/// <summary>
|
||||
/// The result of the async operation.
|
||||
/// </summary>
|
||||
private T _result;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes an instance of <see cref="AsyncResult<T>"/>.
|
||||
/// </summary>
|
||||
/// <param name="callback">The callback method when the async operation completes.</param>
|
||||
/// <param name="state">A user-defined object that qualifies or contains information about an asynchronous operation.</param>
|
||||
public AsyncResult(AsyncCallback callback, object state)
|
||||
: base(callback, state)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets result and release resources.
|
||||
/// </summary>
|
||||
/// <returns>The instance of result.</returns>
|
||||
public T GetResult()
|
||||
{
|
||||
base.WaitForCompletion();
|
||||
return _result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets result and notify completion.
|
||||
/// </summary>
|
||||
/// <param name="result">The instance of result.</param>
|
||||
public void Complete(T result)
|
||||
{
|
||||
// Complete should not throw if disposed.
|
||||
this._result = result;
|
||||
base.NotifyCompletion();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (C) Alibaba Cloud Computing
|
||||
* All rights reserved.
|
||||
*
|
||||
* 版权所有 (C)阿里云计算有限公司
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Aliyun.Api.LOG.Common.Utilities
|
||||
{
|
||||
/// <summary>
|
||||
/// Description of DateUtils.
|
||||
/// </summary>
|
||||
public static class DateUtils
|
||||
{
|
||||
private static DateTime _1970StartDateTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1, 0, 0, 0, 0));
|
||||
private const string _rfc822DateFormat = "ddd, dd MMM yyyy HH:mm:ss \\G\\M\\T";
|
||||
private const string _iso8601DateFormat = "yyyy-MM-dd'T'HH:mm:ss.fff'Z'";
|
||||
|
||||
/// <summary>
|
||||
/// Formats an instance of <see cref="DateTime" /> to a GMT string.
|
||||
/// </summary>
|
||||
/// <param name="dt">The date time to format.</param>
|
||||
/// <returns></returns>
|
||||
public static string FormatRfc822Date(DateTime dt)
|
||||
{
|
||||
return dt.ToUniversalTime().ToString(_rfc822DateFormat,
|
||||
CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Formats a GMT date string to an object of <see cref="DateTime" />.
|
||||
/// </summary>
|
||||
/// <param name="dt"></param>
|
||||
/// <returns></returns>
|
||||
public static DateTime ParseRfc822Date(String dt)
|
||||
{
|
||||
Debug.Assert(!string.IsNullOrEmpty(dt));
|
||||
return DateTime.SpecifyKind(
|
||||
DateTime.ParseExact(dt,
|
||||
_rfc822DateFormat,
|
||||
CultureInfo.InvariantCulture),
|
||||
DateTimeKind.Utc);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Formats a date to a string in the format of ISO 8601 spec.
|
||||
/// </summary>
|
||||
/// <param name="dt"></param>
|
||||
/// <returns></returns>
|
||||
public static string FormatIso8601Date(DateTime dt)
|
||||
{
|
||||
return dt.ToUniversalTime().ToString(_iso8601DateFormat,
|
||||
CultureInfo.CreateSpecificCulture("en-US"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// convert time stamp to DateTime.
|
||||
/// </summary>
|
||||
/// <param name="timeStamp">seconds</param>
|
||||
/// <returns></returns>
|
||||
public static DateTime GetDateTime(uint timeStamp)
|
||||
{
|
||||
DateTime dtStart = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1));
|
||||
long lTime = ((long)timeStamp * System.TimeSpan.TicksPerSecond);
|
||||
System.TimeSpan toNow = new System.TimeSpan(lTime);
|
||||
DateTime targetDt = dtStart.Add(toNow);
|
||||
return targetDt;
|
||||
}
|
||||
|
||||
public static uint TimeSpan() {
|
||||
return (uint)Math.Round((DateTime.Now - _1970StartDateTime).TotalSeconds, MidpointRounding.AwayFromZero);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) Alibaba Cloud Computing
|
||||
* All rights reserved.
|
||||
*
|
||||
* 版权所有 (C)阿里云计算有限公司
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Aliyun.Api.LOG.Common.Utilities
|
||||
{
|
||||
/// <summary>
|
||||
/// Description of EnumUtils.
|
||||
/// </summary>
|
||||
internal static class EnumUtils
|
||||
{
|
||||
private static IDictionary<Enum, StringValueAttribute> _stringValues =
|
||||
new Dictionary<Enum, StringValueAttribute>();
|
||||
|
||||
public static string GetStringValue(this Enum value)
|
||||
{
|
||||
string output = null;
|
||||
Type type = value.GetType();
|
||||
|
||||
if (_stringValues.ContainsKey(value))
|
||||
{
|
||||
output = (_stringValues[value] as StringValueAttribute).Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
FieldInfo fi = type.GetField(value.ToString());
|
||||
StringValueAttribute[] attrs =
|
||||
fi.GetCustomAttributes(typeof (StringValueAttribute),
|
||||
false) as StringValueAttribute[];
|
||||
if (attrs.Length > 0)
|
||||
{
|
||||
output = attrs[0].Value;
|
||||
// Put it in the cache.
|
||||
lock(_stringValues)
|
||||
{
|
||||
// Double check
|
||||
if (!_stringValues.ContainsKey(value))
|
||||
{
|
||||
_stringValues.Add(value, attrs[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return value.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (C) Alibaba Cloud Computing
|
||||
* All rights reserved.
|
||||
*
|
||||
* 版权所有 (C)阿里云计算有限公司
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace Aliyun.Api.LOG.Common.Utilities
|
||||
{
|
||||
/// <summary>
|
||||
/// Description of HttpHeaders.
|
||||
/// </summary>
|
||||
internal static class HttpHeaders
|
||||
{
|
||||
public const string Authorization = "Authorization";
|
||||
|
||||
public const string CacheControl = "Cache-Control";
|
||||
|
||||
public const string ContentDisposition = "Content-Disposition";
|
||||
|
||||
public const string ContentEncoding = "Content-Encoding";
|
||||
|
||||
public const string ContentLength = "Content-Length";
|
||||
|
||||
public const string ContentMd5 = "Content-MD5";
|
||||
|
||||
public const string ContentType = "Content-Type";
|
||||
|
||||
public const string Date = "Date";
|
||||
|
||||
public const string Expires = "Expires";
|
||||
|
||||
public const string ETag = "ETag";
|
||||
|
||||
public const string LastModified = "Last-Modified";
|
||||
|
||||
public const string Range = "Range";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (C) Alibaba Cloud Computing
|
||||
* All rights reserved.
|
||||
*
|
||||
* 版权所有 (C)阿里云计算有限公司
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
|
||||
namespace Aliyun.Api.LOG.Common.Utilities
|
||||
{
|
||||
/// <summary>
|
||||
/// Description of HttpUtils.
|
||||
/// </summary>
|
||||
internal static class HttpUtils
|
||||
{
|
||||
public const string UTF8Charset = "utf-8";
|
||||
public const string Iso88591Charset = "iso-8859-1";
|
||||
|
||||
/// <summary>
|
||||
/// Builds the URI parameter string from the request parameters.
|
||||
/// </summary>
|
||||
/// <param name="parameters"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetRequestParameterString(IEnumerable<KeyValuePair<string, string>> parameters)
|
||||
{
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
bool isFirst = true;
|
||||
foreach (var p in parameters)
|
||||
{
|
||||
Debug.Assert(!string.IsNullOrEmpty(p.Key), "Null Or empty key is not allowed.");
|
||||
if (!isFirst)
|
||||
{
|
||||
stringBuilder.Append("&");
|
||||
}
|
||||
isFirst = false;
|
||||
stringBuilder.Append(p.Key);
|
||||
if (p.Value != null)
|
||||
{
|
||||
stringBuilder.Append("=").Append(UrlEncode(p.Value, UTF8Charset));
|
||||
}
|
||||
}
|
||||
|
||||
return stringBuilder.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Encodes the URL.
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="charset"></param>
|
||||
/// <returns></returns>
|
||||
public static string UrlEncode(string data, string charset = UTF8Charset)
|
||||
{
|
||||
Debug.Assert(data != null && !string.IsNullOrEmpty(charset));
|
||||
|
||||
StringBuilder stringBuilder = new StringBuilder(data.Length * 2);
|
||||
string text = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~";
|
||||
byte[] bytes = Encoding.GetEncoding(charset).GetBytes(data);
|
||||
foreach (char c in bytes)
|
||||
{
|
||||
if (text.IndexOf(c) != -1)
|
||||
{
|
||||
stringBuilder.Append(c);
|
||||
}
|
||||
else
|
||||
{
|
||||
stringBuilder.Append("%").Append(
|
||||
string.Format(CultureInfo.InvariantCulture, "{0:X2}", (int)c));
|
||||
}
|
||||
}
|
||||
return stringBuilder.ToString();
|
||||
}
|
||||
|
||||
// Convert a text from one charset to another.
|
||||
public static string ReEncode(string text, string fromCharset, string toCharset)
|
||||
{
|
||||
Debug.Assert(text != null);
|
||||
var buffer = Encoding.GetEncoding(fromCharset).GetBytes(text);
|
||||
return Encoding.GetEncoding(toCharset).GetString(buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (C) Alibaba Cloud Computing
|
||||
* All rights reserved.
|
||||
*
|
||||
* 版权所有 (C)阿里云计算有限公司
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
|
||||
namespace Aliyun.Api.LOG.Common.Utilities
|
||||
{
|
||||
/// <summary>
|
||||
/// Description of IOUtils.
|
||||
/// </summary>
|
||||
internal static class IOUtils
|
||||
{
|
||||
private const int _bufferSize = 1024 * 4;
|
||||
|
||||
public static void WriteTo(this Stream src, Stream dest){
|
||||
if (dest == null)
|
||||
throw new ArgumentNullException("dest");
|
||||
|
||||
byte[] buffer = new byte[_bufferSize];
|
||||
int bytesRead = 0;
|
||||
while((bytesRead = src.Read(buffer, 0, buffer.Length)) > 0)
|
||||
{
|
||||
dest.Write(buffer, 0, bytesRead);
|
||||
}
|
||||
dest.Flush();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a stream to another
|
||||
/// </summary>
|
||||
/// <param name="orignStream">The stream you want to write from</param>
|
||||
/// <param name="destStream">The stream written to</param>
|
||||
/// <param name="maxLength">The max length of the stream to write</param>
|
||||
/// <returns>The actual length written to destStream</returns>
|
||||
public static long WriteTo(this Stream orignStream, Stream destStream, long maxLength)
|
||||
{
|
||||
const int buffSize = 1024;
|
||||
byte[] buff = new byte[buffSize];
|
||||
long alreadyRead = 0;
|
||||
|
||||
int readCount = 0;
|
||||
while (alreadyRead < maxLength)
|
||||
{
|
||||
readCount = orignStream.Read(buff, 0, buffSize);
|
||||
if (readCount <= 0) { break; }
|
||||
|
||||
if (alreadyRead + readCount > maxLength)
|
||||
{
|
||||
readCount = (int) (maxLength - alreadyRead);
|
||||
}
|
||||
alreadyRead += readCount;
|
||||
destStream.Write(buff, 0, readCount);
|
||||
}
|
||||
destStream.Flush();
|
||||
return alreadyRead;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) Alibaba Cloud Computing
|
||||
* All rights reserved.
|
||||
*
|
||||
* 版权所有 (C)阿里云计算有限公司
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace Aliyun.Api.LOG.Common.Utilities
|
||||
{
|
||||
/// <summary>
|
||||
/// The Attribute to mark a field that corresponds a string.
|
||||
/// </summary>
|
||||
internal sealed class StringValueAttribute : System.Attribute
|
||||
{
|
||||
public string Value { get; private set; }
|
||||
|
||||
public StringValueAttribute(string value)
|
||||
{
|
||||
this.Value = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user