sdk/Common/Communication/netcore/ServiceClientNewImpl.cs (340 lines of code) (raw):

/* * Copyright (C) Alibaba Cloud Computing * All rights reserved. * */ using System; using System.Collections.Generic; using System.IO; using System.Net; using System.Net.Http; using System.Threading.Tasks; using Aliyun.OSS.Util; namespace Aliyun.OSS.Common.Communication { /// <summary> /// The new implementation for ServiceClient under dotnet core /// </summary> internal class ServiceClientNewImpl : ServiceClient { internal class ResponseImpl : ServiceResponse { private bool _disposed; private HttpResponseMessage _response; private readonly Exception _failure; private IDictionary<string, string> _headers; private Stream _stream; private bool _disposeStream; public override HttpStatusCode StatusCode { get { return _response.StatusCode; } } public override Exception Failure { get { return _failure; } } public override IDictionary<string, string> Headers { get { ThrowIfObjectDisposed(); return _headers ?? (_headers = GetResponseHeaders(_response)); } } public override Stream Content { get { ThrowIfObjectDisposed(); return _stream; } } public ResponseImpl(HttpResponseMessage httpWebResponse) { _response = httpWebResponse; try { _stream = (_response.Content != null) ? _response.Content.ReadAsStreamAsync().Result : null; if (!_response.IsSuccessStatusCode) { if (_response.Content != null) { // after the EnsureSuccessStatusCode(), the _strema will be closed if the status code is non-successful one. var tmpStream = new MemoryStream(); _stream.CopyToAsync(tmpStream).Wait(); _stream.Dispose(); _stream = tmpStream; _stream.Seek(0, SeekOrigin.Begin); _disposeStream = true; } } _response.EnsureSuccessStatusCode(); } catch(HttpRequestException e) { _failure = e; } } private static IDictionary<string, string> GetResponseHeaders(HttpResponseMessage response) { var headers = response.Headers; var result = new Dictionary<string, string>(); foreach(var header in headers) { System.Text.StringBuilder sb = new System.Text.StringBuilder(); string s = ""; foreach(var val in header.Value) { sb.Append(s); sb.Append(val); s = "\r\n"; } result.Add(header.Key, sb.ToString()); } if (response.Content != null && response.Content.Headers != null) { foreach (var header in response.Content.Headers) { System.Text.StringBuilder sb = new System.Text.StringBuilder(); string s = ""; foreach (var val in header.Value) { sb.Append(s); sb.Append(val); s = "\r\n"; } result.Add(header.Key, sb.ToString()); } } return result; } protected override void Dispose(bool disposing) { base.Dispose(disposing); if (_disposed) return; if (disposing) { if (_response != null) { _response.Dispose(); _response = null; } if (_disposeStream) { _stream.Dispose(); } _disposed = true; } } private void ThrowIfObjectDisposed() { if (_disposed) throw new ObjectDisposedException(GetType().Name); } } public ServiceClientNewImpl(ClientConfiguration configuration) : base(configuration) { } protected override ServiceResponse SendCore(ServiceRequest request, ExecutionContext context) { var req = new HttpRequestMessage(Convert(request.Method), request.BuildRequestUri()); this.SetRequestContent(req, request); this.SetHeaders(req, request); HttpClient client = GetClient(); HttpResponseMessage resp = client.SendAsync(req, HttpCompletionOption.ResponseHeadersRead).Result; return new ResponseImpl(resp); } private void SetRequestContent(HttpRequestMessage requestMsg, ServiceRequest serviceRequest) { var data = serviceRequest.BuildRequestContent(); if (serviceRequest.Method == HttpMethod.Get || serviceRequest.Method == HttpMethod.Head) { return; } if (data == null || (serviceRequest.Method != HttpMethod.Put && serviceRequest.Method != HttpMethod.Post)) { requestMsg.Content = new System.Net.Http.ByteArrayContent(new byte[0]); return; } // Write data to the request stream. requestMsg.Content = new StreamContent(new StreamWeakReferece(data)); } void SetHeaders(HttpRequestMessage req, ServiceRequest request) { if (req.Content != null) { if (request.Headers.ContainsKey(HttpHeaders.ContentDisposition) && !string.IsNullOrEmpty(request.Headers[HttpHeaders.ContentDisposition])) { req.Content.Headers.ContentDisposition = System.Net.Http.Headers.ContentDispositionHeaderValue.Parse(request.Headers[HttpHeaders.ContentDisposition]); } if (request.Headers.ContainsKey(HttpHeaders.ContentEncoding) &&!string.IsNullOrEmpty(request.Headers[HttpHeaders.ContentEncoding])) { req.Content.Headers.ContentEncoding.Add(request.Headers[HttpHeaders.ContentEncoding]); } if (request.Headers.ContainsKey(HttpHeaders.ContentType) && !string.IsNullOrEmpty(request.Headers[HttpHeaders.ContentType])) { req.Content.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse(request.Headers[HttpHeaders.ContentType]); } if (request.Headers.ContainsKey(HttpHeaders.ContentMd5) && !string.IsNullOrEmpty(request.Headers[HttpHeaders.ContentMd5])) { req.Content.Headers.ContentMD5 = System.Convert.FromBase64String(request.Headers[HttpHeaders.ContentMd5]); } } foreach (var item in request.Headers) { if (!item.Key.StartsWith("Content")) { req.Headers.TryAddWithoutValidation(item.Key, item.Value); } } } void SetProxy(HttpClientHandler httpClientHandler) { if (String.IsNullOrEmpty(Configuration.ProxyHost)) { httpClientHandler.Proxy = null; } else { httpClientHandler.UseProxy = true; if (Configuration.ProxyPort < 0) httpClientHandler.Proxy = new WebProxy(Configuration.ProxyHost); else httpClientHandler.Proxy = new WebProxy(Configuration.ProxyHost, Configuration.ProxyPort); if (!string.IsNullOrEmpty(Configuration.ProxyUserName)) { httpClientHandler.Proxy.Credentials = String.IsNullOrEmpty(Configuration.ProxyDomain) ? new NetworkCredential(Configuration.ProxyUserName, Configuration.ProxyPassword ?? string.Empty) : new NetworkCredential(Configuration.ProxyUserName, Configuration.ProxyPassword ?? string.Empty, Configuration.ProxyDomain); httpClientHandler.PreAuthenticate = true; } } } protected override IAsyncResult BeginSendCore(ServiceRequest request, ExecutionContext context, AsyncCallback callback, Object state) { var req = new HttpRequestMessage(Convert(request.Method), request.BuildRequestUri()); this.SetRequestContent(req, request); this.SetHeaders(req, request); HttpClient client = GetClient(); var task = client.SendAsync(req, HttpCompletionOption.ResponseHeadersRead); ServiceClientImpl.HttpAsyncResult result = new ServiceClientImpl.HttpAsyncResult(callback, state); task.ContinueWith((resp) => { ServiceResponse serviceResponse = new ResponseImpl(resp.Result); result.Complete(serviceResponse); }); return result; } private static System.Net.Http.HttpMethod Convert(HttpMethod method) { switch (method) { case HttpMethod.Delete: return System.Net.Http.HttpMethod.Delete; case HttpMethod.Get: return System.Net.Http.HttpMethod.Get; case HttpMethod.Head: return System.Net.Http.HttpMethod.Head; case HttpMethod.Options: return System.Net.Http.HttpMethod.Options; case HttpMethod.Post: return System.Net.Http.HttpMethod.Post; case HttpMethod.Put: return System.Net.Http.HttpMethod.Put; default: throw new InvalidCastException(); } } private HttpClient GetClient() { if (_httpClientSelf != null) { return _httpClientSelf; } bool notUseProxy = string.IsNullOrEmpty(Configuration.ProxyHost); if (notUseProxy) { if (_httpClientNoProxy == null) { lock (_clientLock) { if (_httpClientNoProxy == null) { _configurationNoProxy = Configuration.Clone() as ClientConfiguration; _httpClientNoProxy = Create(false); } } } } else { if (_httpClient == null) { lock (_clientLock) { if (_httpClient == null) { _configuration = Configuration.Clone() as ClientConfiguration; _httpClient = Create(true); } } } } if (notUseProxy) { if (CanReuseHttpClient(_configurationNoProxy, Configuration)) { _httpClientSelf = _httpClientNoProxy; } } else { if (CanReuseHttpClient(_configuration, Configuration)) { _httpClientSelf = _httpClient; } } if (_httpClientSelf == null) { lock (_clientLock) { if (_httpClientSelf == null) { _httpClientSelf = Create(!notUseProxy); } } } return _httpClientSelf; } private HttpClient Create(bool setProxy) { HttpClientHandler httpClientHandler = new HttpClientHandler(); HttpClient client = new HttpClient(httpClientHandler); if (setProxy) { this.SetProxy(httpClientHandler); } client.Timeout = Configuration.ConnectionTimeout < 0 ? TimeSpan.FromDays(1) : TimeSpan.FromMilliseconds(Configuration.ConnectionTimeout); client.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", Configuration.UserAgent); ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(HttpFactory.CheckValidationResult); return client; } private bool CanReuseHttpClient(ClientConfiguration dst, ClientConfiguration src) { if (dst == null || src == null || (dst.ConnectionTimeout == src.ConnectionTimeout && dst.ProxyHost == src.ProxyHost && dst.ProxyPort == src.ProxyPort && dst.ProxyUserName == src.ProxyUserName && dst.ProxyPassword == src.ProxyPassword )) { return true; } return false; } private static HttpClient _httpClient; private static HttpClient _httpClientNoProxy; private static object _clientLock = new object(); private static ClientConfiguration _configuration; private static ClientConfiguration _configurationNoProxy; private HttpClient _httpClientSelf; } }