HttpClientPipelineTransport
An implementation of PipelineTransport that uses a
HttpClient to send and receive HTTP requests and responses.
using System.ClientModel.Internal;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
namespace System.ClientModel.Primitives
{
[System.Runtime.CompilerServices.NullableContext(1)]
[System.Runtime.CompilerServices.Nullable(0)]
public class HttpClientPipelineTransport : PipelineTransport, IDisposable
{
[System.Runtime.CompilerServices.Nullable(0)]
private class HttpPipelineRequest : PipelineRequest
{
[System.Runtime.CompilerServices.Nullable(0)]
private sealed class MessageBodyAdapter : HttpContent
{
private readonly BinaryContent _content;
private readonly CancellationToken _cancellationToken;
public MessageBodyAdapter(BinaryContent content, CancellationToken cancellationToken)
{
Argument.AssertNotNull(content, "content");
_content = content;
_cancellationToken = cancellationToken;
}
[AsyncStateMachine(typeof(<SerializeToStreamAsync>d__3))]
protected override Task SerializeToStreamAsync(Stream stream, [System.Runtime.CompilerServices.Nullable(2)] TransportContext context)
{
<SerializeToStreamAsync>d__3 stateMachine = default(<SerializeToStreamAsync>d__3);
stateMachine.<>t__builder = AsyncTaskMethodBuilder.Create();
stateMachine.<>4__this = this;
stateMachine.stream = stream;
stateMachine.<>1__state = -1;
stateMachine.<>t__builder.Start(ref stateMachine);
return stateMachine.<>t__builder.Task;
}
protected override bool TryComputeLength(out long length)
{
return _content.TryComputeLength(out length);
}
}
private const string AuthorizationHeaderName = "Authorization";
private string _method;
[System.Runtime.CompilerServices.Nullable(2)]
private Uri _uri;
[System.Runtime.CompilerServices.Nullable(2)]
private BinaryContent _content;
private readonly PipelineRequestHeaders _headers;
private bool _disposed;
private static readonly HttpMethod _patchMethod = new HttpMethod("PATCH");
protected override string MethodCore {
get {
return _method;
}
set {
Argument.AssertNotNull(value, "value");
_method = value;
}
}
[System.Runtime.CompilerServices.Nullable(2)]
protected override Uri UriCore {
[System.Runtime.CompilerServices.NullableContext(2)]
get {
return _uri;
}
[System.Runtime.CompilerServices.NullableContext(2)]
set {
Argument.AssertNotNull(value, "value");
_uri = value;
}
}
[System.Runtime.CompilerServices.Nullable(2)]
protected override BinaryContent ContentCore {
[System.Runtime.CompilerServices.NullableContext(2)]
get {
return _content;
}
[System.Runtime.CompilerServices.NullableContext(2)]
set {
_content = value;
}
}
protected override PipelineRequestHeaders HeadersCore => _headers;
protected internal HttpPipelineRequest()
{
_method = HttpMethod.Get.Method;
_headers = new ArrayBackedRequestHeaders();
}
private static HttpMethod ToHttpMethod(string method)
{
if (method == "GET")
return HttpMethod.Get;
if (method == "POST")
return HttpMethod.Post;
if (method == "PUT")
return HttpMethod.Put;
if (method == "HEAD")
return HttpMethod.Head;
if (method == "DELETE")
return HttpMethod.Delete;
if (method == "PATCH")
return _patchMethod;
return new HttpMethod(method);
}
internal static HttpRequestMessage BuildHttpRequestMessage(PipelineRequest request, CancellationToken cancellationToken)
{
if ((object)request.Uri == null)
throw new InvalidOperationException("Uri must be set on message request prior to sending message.");
HttpMethod method = ToHttpMethod(request.Method);
Uri uri = request.Uri;
HttpRequestMessage httpRequestMessage = new HttpRequestMessage(method, uri);
MessageBodyAdapter messageBodyAdapter = (MessageBodyAdapter)(httpRequestMessage.Content = ((request.Content == null) ? null : new MessageBodyAdapter(request.Content, cancellationToken)));
httpRequestMessage.Headers.ExpectContinue = false;
ArrayBackedRequestHeaders arrayBackedRequestHeaders = request.Headers as ArrayBackedRequestHeaders;
if (arrayBackedRequestHeaders == null)
throw new InvalidOperationException($"""{request.Headers?.GetType()}""");
int num = 0;
string name;
object value;
while (arrayBackedRequestHeaders.GetNextValue(num++, out name, out value)) {
string text = value as string;
AuthenticationHeaderValue parsedValue;
if (text == null) {
List<string> list = value as List<string>;
if (list != null && !httpRequestMessage.Headers.TryAddWithoutValidation(name, list) && messageBodyAdapter != null && !messageBodyAdapter.Headers.TryAddWithoutValidation(name, list))
throw new InvalidOperationException("Unable to add header " + name + " to header collection.");
} else if (name == "Authorization" && AuthenticationHeaderValue.TryParse(text, out parsedValue)) {
httpRequestMessage.Headers.Authorization = parsedValue;
} else if (!httpRequestMessage.Headers.TryAddWithoutValidation(name, text) && messageBodyAdapter != null && !messageBodyAdapter.Headers.TryAddWithoutValidation(name, text)) {
throw new InvalidOperationException("Unable to add header " + name + " to header collection.");
}
}
return httpRequestMessage;
}
public override string ToString()
{
return BuildHttpRequestMessage(this, default(CancellationToken)).ToString();
}
public sealed override void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected void Dispose(bool disposing)
{
if (disposing && !_disposed) {
BinaryContent content = _content;
if (content != null) {
_content = null;
content.Dispose();
}
_disposed = true;
}
}
}
[System.Runtime.CompilerServices.Nullable(0)]
private class HttpClientTransportResponse : PipelineResponse
{
[System.Runtime.CompilerServices.NullableContext(0)]
private class BufferedContentStream : MemoryStream
{
}
private readonly HttpResponseMessage _httpResponse;
private readonly HttpContent _httpResponseContent;
[System.Runtime.CompilerServices.Nullable(2)]
private Stream _contentStream;
[System.Runtime.CompilerServices.Nullable(2)]
private BinaryData _bufferedContent;
private bool _disposed;
public override int Status => (int)_httpResponse.StatusCode;
public override string ReasonPhrase => _httpResponse.ReasonPhrase ?? string.Empty;
protected override PipelineResponseHeaders HeadersCore => new HttpClientResponseHeaders(_httpResponse, _httpResponseContent);
[System.Runtime.CompilerServices.Nullable(2)]
public override Stream ContentStream {
[System.Runtime.CompilerServices.NullableContext(2)]
get {
if (_contentStream != null)
return _contentStream;
return BufferContent(default(CancellationToken)).ToStream();
}
[System.Runtime.CompilerServices.NullableContext(2)]
set {
_contentStream = value;
_bufferedContent = null;
}
}
public override BinaryData Content {
get {
if (_bufferedContent != null)
return _bufferedContent;
if (_contentStream == null || _contentStream is MemoryStream)
return BufferContent(default(CancellationToken));
throw new InvalidOperationException("The response is not buffered.");
}
}
public HttpClientTransportResponse(HttpResponseMessage httpResponse)
{
if (httpResponse == null)
throw new ArgumentNullException("httpResponse");
_httpResponse = httpResponse;
_httpResponseContent = _httpResponse.Content;
_httpResponse.Content = null;
}
public override BinaryData BufferContent(CancellationToken cancellationToken = default(CancellationToken))
{
return BufferContentSyncOrAsync(cancellationToken, false).EnsureCompleted();
}
[AsyncStateMachine(typeof(<BufferContentAsync>d__18))]
[return: System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})]
public override ValueTask<BinaryData> BufferContentAsync(CancellationToken cancellationToken = default(CancellationToken))
{
<BufferContentAsync>d__18 stateMachine = default(<BufferContentAsync>d__18);
stateMachine.<>t__builder = AsyncValueTaskMethodBuilder<BinaryData>.Create();
stateMachine.<>4__this = this;
stateMachine.cancellationToken = cancellationToken;
stateMachine.<>1__state = -1;
stateMachine.<>t__builder.Start(ref stateMachine);
return stateMachine.<>t__builder.Task;
}
[AsyncStateMachine(typeof(<BufferContentSyncOrAsync>d__19))]
[return: System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})]
private ValueTask<BinaryData> BufferContentSyncOrAsync(CancellationToken cancellationToken, bool async)
{
<BufferContentSyncOrAsync>d__19 stateMachine = default(<BufferContentSyncOrAsync>d__19);
stateMachine.<>t__builder = AsyncValueTaskMethodBuilder<BinaryData>.Create();
stateMachine.<>4__this = this;
stateMachine.cancellationToken = cancellationToken;
stateMachine.async = async;
stateMachine.<>1__state = -1;
stateMachine.<>t__builder.Start(ref stateMachine);
return stateMachine.<>t__builder.Task;
}
public override void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing && !_disposed) {
_httpResponse?.Dispose();
if (ContentStream is MemoryStream)
BufferContent(default(CancellationToken));
_contentStream?.Dispose();
_contentStream = null;
_disposed = true;
}
}
}
private static readonly HttpClient = CreateDefaultClient();
private readonly HttpClient _httpClient;
public static HttpClientPipelineTransport { get; } = new HttpClientPipelineTransport();
public HttpClientPipelineTransport()
: this(_sharedDefaultClient)
{
}
public HttpClientPipelineTransport(HttpClient client)
{
Argument.AssertNotNull(client, "client");
_httpClient = client;
}
private static HttpClient CreateDefaultClient()
{
HttpClientHandler obj = new HttpClientHandler {
AllowAutoRedirect = false
};
ServicePointHelpers.SetLimits(obj);
return new HttpClient(obj) {
Timeout = Timeout.InfiniteTimeSpan
};
}
protected override PipelineMessage CreateMessageCore()
{
return new PipelineMessage(new HttpPipelineRequest());
}
protected sealed override void ProcessCore(PipelineMessage message)
{
ProcessSyncOrAsync(message, true).AsTask().GetAwaiter().GetResult();
}
[AsyncStateMachine(typeof(<ProcessCoreAsync>d__10))]
protected sealed override ValueTask ProcessCoreAsync(PipelineMessage message)
{
<ProcessCoreAsync>d__10 stateMachine = default(<ProcessCoreAsync>d__10);
stateMachine.<>t__builder = AsyncValueTaskMethodBuilder.Create();
stateMachine.<>4__this = this;
stateMachine.message = message;
stateMachine.<>1__state = -1;
stateMachine.<>t__builder.Start(ref stateMachine);
return stateMachine.<>t__builder.Task;
}
[AsyncStateMachine(typeof(<ProcessSyncOrAsync>d__11))]
private ValueTask ProcessSyncOrAsync(PipelineMessage message, bool async)
{
<ProcessSyncOrAsync>d__11 stateMachine = default(<ProcessSyncOrAsync>d__11);
stateMachine.<>t__builder = AsyncValueTaskMethodBuilder.Create();
stateMachine.<>4__this = this;
stateMachine.message = message;
stateMachine.<>1__state = -1;
stateMachine.<>t__builder.Start(ref stateMachine);
return stateMachine.<>t__builder.Task;
}
protected virtual void OnSendingRequest(PipelineMessage message, HttpRequestMessage httpRequest)
{
}
protected virtual void OnReceivedResponse(PipelineMessage message, HttpResponseMessage httpResponse)
{
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
}
}
}