protected override async Task <HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { var endpoint = new UnixDomainSocketEndPoint(this.providerUri.LocalPath); using (Socket socket = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified)) { Events.Connecting(this.providerUri.LocalPath); await socket.ConnectAsync(endpoint); Events.Connected(this.providerUri.LocalPath); using (var stream = new HttpBufferedStream(new NetworkStream(socket, true))) { var serializer = new HttpRequestResponseSerializer(); byte[] requestBytes = serializer.SerializeRequest(request); Events.SendRequest(request.RequestUri); await stream.WriteAsync(requestBytes, 0, requestBytes.Length, cancellationToken); if (request.Content != null) { await request.Content.CopyToAsync(stream); } HttpResponseMessage response = await serializer.DeserializeResponse(stream, cancellationToken); Events.ResponseReceived(response.StatusCode); return(response); } } }
async Task SetResponseStatusLine(HttpResponseMessage httpResponse, HttpBufferedStream bufferedStream, CancellationToken cancellationToken) { string statusLine = await bufferedStream.ReadLineAsync(cancellationToken).ConfigureAwait(false); if (string.IsNullOrWhiteSpace(statusLine)) { throw new HttpRequestException("Response is empty."); } string[] statusLineParts = statusLine.Split(new[] { SP }, 3); if (statusLineParts.Length < 3) { throw new HttpRequestException("Status line is not valid."); } string[] httpVersion = statusLineParts[0].Split(new[] { ProtocolVersionSeparator }, 2); if (httpVersion.Length < 2 || !Version.TryParse(httpVersion[1], out Version versionNumber)) { throw new HttpRequestException($"Version is not valid {statusLineParts[0]}."); } httpResponse.Version = versionNumber; if (!Enum.TryParse(statusLineParts[1], out HttpStatusCode statusCode)) { throw new HttpRequestException($"StatusCode is not valid {statusLineParts[1]}."); } httpResponse.StatusCode = statusCode; httpResponse.ReasonPhrase = statusLineParts[2]; }
protected override async Task <HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { var endpoint = new UnixDomainSocketEndPoint(this.providerUri.LocalPath); Events.Connecting(this.providerUri.LocalPath); // do not dispose `Socket` or `HttpBufferedStream` here, b/c it will be used later // by the consumer of HttpResponseMessage (HttpResponseMessage.Content.ReadAsStringAsync()). // When HttpResponseMessage is disposed - the stream and socket is disposed as well. Socket socket = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified); await socket.ConnectAsync(endpoint); Events.Connected(this.providerUri.LocalPath); var stream = new HttpBufferedStream(new NetworkStream(socket, true)); var serializer = new HttpRequestResponseSerializer(); byte[] requestBytes = serializer.SerializeRequest(request); Events.SendRequest(request.RequestUri); await stream.WriteAsync(requestBytes, 0, requestBytes.Length, cancellationToken); if (request.Content != null) { await request.Content.CopyToAsync(stream); } HttpResponseMessage response = await serializer.DeserializeResponse(stream, cancellationToken); Events.ResponseReceived(response.StatusCode); return(response); }
async Task SetHeadersAndContent(HttpResponseMessage httpResponse, HttpBufferedStream bufferedStream, CancellationToken cancellationToken) { IList <string> headers = new List <string>(); string line = await bufferedStream.ReadLineAsync(cancellationToken); while (!string.IsNullOrWhiteSpace(line)) { headers.Add(line); line = await bufferedStream.ReadLineAsync(cancellationToken); } httpResponse.Content = new StreamContent(bufferedStream); var contentHeaders = new Dictionary <string, string>(); foreach (string header in headers) { if (string.IsNullOrWhiteSpace(header)) { // headers end break; } int headerSeparatorPosition = header.IndexOf(HeaderSeparator); if (headerSeparatorPosition <= 0) { throw new HttpRequestException($"Header is invalid {header}."); } string headerName = header.Substring(0, headerSeparatorPosition).Trim(); string headerValue = header.Substring(headerSeparatorPosition + 1).Trim(); bool headerAdded = httpResponse.Headers.TryAddWithoutValidation(headerName, headerValue); if (!headerAdded) { contentHeaders.Add(headerName, headerValue); } } bool isChunked = httpResponse.Headers.TransferEncodingChunked.HasValue && httpResponse.Headers.TransferEncodingChunked.Value; httpResponse.Content = isChunked ? new StreamContent(new HttpChunkedStreamReader(bufferedStream)) : new StreamContent(bufferedStream); foreach (KeyValuePair <string, string> contentHeader in contentHeaders) { httpResponse.Content.Headers.TryAddWithoutValidation(contentHeader.Key, contentHeader.Value); if (string.Equals(contentHeader.Key, ContentLengthHeaderName, StringComparison.InvariantCultureIgnoreCase)) { if (!long.TryParse(contentHeader.Value, out long contentLength)) { throw new HttpRequestException($"Header value {contentHeader.Value} is invalid for {ContentLengthHeaderName}."); } await httpResponse.Content.LoadIntoBufferAsync(contentLength); } } }
public async Task <HttpResponseMessage> DeserializeResponse(HttpBufferedStream bufferedStream, CancellationToken cancellationToken) { var httpResponse = new HttpResponseMessage(); await SetResponseStatusLine(httpResponse, bufferedStream, cancellationToken).ConfigureAwait(false); await SetHeadersAndContent(httpResponse, bufferedStream, cancellationToken).ConfigureAwait(false); return(httpResponse); }
public HttpChunkedStreamReader(HttpBufferedStream stream) { if (stream == null) { throw new ArgumentNullException(nameof(stream)); } this.stream = stream; }
async Task SetHeadersAndContent(HttpResponseMessage httpResponse, HttpBufferedStream bufferedStream, CancellationToken cancellationToken) { IList <string> headers = new List <string>(); string line = await bufferedStream.ReadLineAsync(cancellationToken).ConfigureAwait(false); while (!string.IsNullOrWhiteSpace(line)) { headers.Add(line); line = await bufferedStream.ReadLineAsync(cancellationToken).ConfigureAwait(false); } httpResponse.Content = new StreamContent(bufferedStream); foreach (string header in headers) { if (string.IsNullOrWhiteSpace(header)) { // headers end break; } int headerSeparatorPosition = header.IndexOf(HeaderSeparator); if (headerSeparatorPosition <= 0) { throw new HttpRequestException($"Header is invalid {header}."); } string headerName = header.Substring(0, headerSeparatorPosition).Trim(); string headerValue = header.Substring(headerSeparatorPosition + 1).Trim(); bool headerAdded = httpResponse.Headers.TryAddWithoutValidation(headerName, headerValue); if (!headerAdded) { if (string.Equals(headerName, ContentLengthHeaderName, StringComparison.InvariantCultureIgnoreCase)) { if (!long.TryParse(headerValue, out long contentLength)) { throw new HttpRequestException($"Header value is invalid for {headerName}."); } await httpResponse.Content.LoadIntoBufferAsync(contentLength).ConfigureAwait(false); } httpResponse.Content.Headers.TryAddWithoutValidation(headerName, headerValue); } } }
protected override async Task <HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { Socket socket = await this.GetConnectedSocketAsync(); var stream = new HttpBufferedStream(new NetworkStream(socket, true)); var serializer = new HttpRequestResponseSerializer(); byte[] requestBytes = serializer.SerializeRequest(request); await stream.WriteAsync(requestBytes, 0, requestBytes.Length, cancellationToken); if (request.Content != null) { await request.Content.CopyToAsync(stream); } HttpResponseMessage response = await serializer.DeserializeResponse(stream, cancellationToken); return(response); }
public HttpChunkedStreamReader(HttpBufferedStream stream) { this.stream = Preconditions.CheckNotNull(stream, nameof(stream)); }
public HttpChunkedStreamReader(HttpBufferedStream stream) { this.stream = stream; }