in src/AlibabaCloud.OSS.V2/Internal/ExecuteMiddleware.cs [32:153]
public async Task<ResponseMessage> ExecuteAsync(RequestMessage request, ExecuteContext context)
{
using var cts = new CancellationTokenSource(context.RequestOnceTimeout);
var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cts.Token, context.ApiCallCancellationToken);
using var httpRequest = new HttpRequestMessage(ConvertMethod(request.Method), request.RequestUri);
HttpResponseMessage? httpResponse = null;
var completionOption = context.HttpCompletionOption ?? HttpCompletionOption.ResponseContentRead;
var content = NopCloseRequestContent.StreamFor(request.Content, cts, context.RequestOnceTimeout);
// Write data to the request stream.
// Get & Head Method does not support HttpContent
if (!(httpRequest.Method == HttpMethod.Get ||
httpRequest.Method == HttpMethod.Head))
httpRequest.Content = content != null
? new StreamContent(content)
: new ByteArrayContent(Array.Empty<byte>());
// Write headers
foreach (var item in request.Headers)
{
if (!ContentHeadersHash.Contains(item.Key))
{
httpRequest.Headers.TryAddWithoutValidation(item.Key, item.Value);
continue;
}
if (httpRequest.Content == null) continue;
switch (item.Key.ToLower())
{
case "content-disposition":
httpRequest.Content.Headers.ContentDisposition = ContentDispositionHeaderValue.Parse(item.Value);
break;
case "content-encoding":
httpRequest.Content.Headers.ContentEncoding.Add(item.Value);
break;
case "content-language":
httpRequest.Content.Headers.ContentLanguage.Add(item.Value);
break;
case "content-type":
httpRequest.Content.Headers.ContentType = MediaTypeHeaderValue.Parse(item.Value);
break;
case "content-md5":
httpRequest.Content.Headers.ContentMD5 = Convert.FromBase64String(item.Value);
break;
case "content-length":
httpRequest.Content.Headers.ContentLength = Convert.ToInt64(item.Value);
break;
case "expires":
if (DateTime.TryParse(
item.Value,
CultureInfo.InvariantCulture,
DateTimeStyles.None,
out var expires
))
httpRequest.Content.Headers.Expires = expires;
break;
}
}
try
{
httpResponse = await handler.SendAsync(httpRequest, completionOption, linkedCts.Token).ConfigureAwait(false);
Stream? contentStream = null;
if (httpResponse.Content != null)
{
contentStream = await httpResponse.Content.ReadAsStreamAsync().ConfigureAwait(false);
// allways save reponse body into memroy when status code is not 2xx(not include 203)
var statusCode = (int)httpResponse.StatusCode;
if ((statusCode == 203 || statusCode / 100 != 2) && !contentStream.CanSeek)
{
try
{
if (contentStream.CanTimeout)
{
contentStream.ReadTimeout = (int)context.RequestOnceTimeout.TotalMilliseconds;
}
var stream = new MemoryStream();
#if NET5_0_OR_GREATER
await contentStream.CopyToAsync(stream, linkedCts.Token).ConfigureAwait(false);
#else
await contentStream.CopyToAsync(stream).ConfigureAwait(false);
#endif
contentStream = stream;
contentStream.Seek(0, SeekOrigin.Begin);
}
finally
{
httpResponse.Content.Dispose();
}
}
}
var response = new ResponseMessage((int)httpResponse.StatusCode, httpResponse.ReasonPhrase!)
{
Request = request,
Content = contentStream
};
// headers
foreach (KeyValuePair<string, IEnumerable<string>> header in httpResponse.Headers) response.Headers[header.Key] = string.Join(",", header.Value);
if (httpResponse.Content != null)
{
foreach (KeyValuePair<string, IEnumerable<string>> header in httpResponse.Content.Headers) response.Headers[header.Key] = string.Join(",", header.Value);
}
return response;
}
catch (OperationCanceledException e) when (cts.Token.IsCancellationRequested)
{
throw CancellationHelper.CreateRequestTimeoutException(e, context.RequestOnceTimeout);
}
catch (HttpRequestException e)
{
throw new RequestFailedException(e.Message, e);
}
}