public async Task Send_MultipleRequests_Sequential_Success() { await RunMultiStreamTest( async (client, uri) => { foreach ((var testIdx, var headers, var content, var trailingHeaders) in InterleavedData()) { await using ValueHttpRequest request = (await client.CreateNewRequestAsync(Version, HttpVersionPolicy.RequestVersionExact)).Value; await ClientSendHelperAsync(request, uri, testIdx, headers, content, trailingHeaders); } }, async server => { foreach ((var testIdx, var headers, var content, var trailingHeaders) in InterleavedData()) { await using HttpTestStream serverStream = await server.AcceptStreamAsync(); HttpTestFullRequest request = await serverStream.ReceiveAndSendAsync(); Assert.True(request.Headers.Contains(headers)); Assert.Equal(string.Join("", content), request.Content); if (trailingHeaders is not null) { Assert.True(request.TrailingHeaders.Contains(trailingHeaders)); } } }, millisecondsTimeout : DefaultTestTimeout * 10); }
public static async Task WriteContentAsync(this ValueHttpRequest request, List <string> content) { foreach (string chunk in content) { await request.WriteContentAsync(chunk).ConfigureAwait(false); } }
static async Task Main(string[] args) { PreparedHeaderSet preparedHeaders = new PreparedHeaderSetBuilder() .AddHeader("User-Agent", "NetworkToolkit") .AddHeader("Accept", "text/html") .Build(); await using ConnectionFactory connectionFactory = new SocketConnectionFactory(); await using Connection connection = await connectionFactory.ConnectAsync(new DnsEndPoint ("microsoft.com", 80)); await using HttpConnection httpConnection = new Http1Connection(connection, HttpPrimitiveVersion.Version11); int requestCounter = 0; await SingleRequest(); await SingleRequest(); async Task SingleRequest() { await using ValueHttpRequest request = (await httpConnection.CreateNewRequestAsync(HttpPrimitiveVersion.Version11, HttpVersionPolicy.RequestVersionExact)).Value; request.ConfigureRequest(contentLength: 0, hasTrailingHeaders: false); request.WriteRequest(HttpMethod.Get, new Uri("http://microsoft.com")); request.WriteHeader(preparedHeaders); request.WriteHeader("X-Example-RequestNo", requestCounter++.ToString()); await request.CompleteRequestAsync(); await request.DrainAsync(); } }
static async Task Main(string[] args) { await using ConnectionFactory connectionFactory = new SocketConnectionFactory(); await using Connection connection = await connectionFactory.ConnectAsync(new DnsEndPoint ("microsoft.com", 80)); await using HttpConnection httpConnection = new Http1Connection(connection); await using (ValueHttpRequest request = (await httpConnection.CreateNewRequestAsync(HttpPrimitiveVersion.Version11, HttpVersionPolicy.RequestVersionExact)).Value) { request.ConfigureRequest(contentLength: 0, hasTrailingHeaders: false); request.WriteRequest(HttpMethod.Get, new Uri("http://microsoft.com")); request.WriteHeader("Accept", "text/html"); await request.CompleteRequestAsync(); await request.ReadToFinalResponseAsync(); Console.WriteLine($"Final response code: {request.StatusCode}"); if (await request.ReadToHeadersAsync()) { await request.ReadHeadersAsync(new PrintingHeadersSink(), state : null); } else { Console.WriteLine("No headers received."); } if (await request.ReadToContentAsync()) { long totalLen = 0; var buffer = new byte[4096]; int readLen; do { while ((readLen = await request.ReadContentAsync(buffer)) != 0) { totalLen += readLen; } }while (await request.ReadToNextContentAsync()); Console.WriteLine($"Received {totalLen} byte response."); } else { Console.WriteLine("No content received."); } if (await request.ReadToTrailingHeadersAsync()) { await request.ReadHeadersAsync(new PrintingHeadersSink(), state : null); } else { Console.WriteLine("No trailing headers received."); } } }
public static void WriteTrailingHeaders(this ValueHttpRequest request, TestHeadersSink headers) { foreach (KeyValuePair <string, List <string> > header in headers) { foreach (string headerValue in header.Value) { request.WriteTrailingHeader(header.Key, headerValue); } } }
public async Task Pipelining_Success() { const int PipelineLength = 10; await RunMultiStreamTest( async (client, serverUri) => { var tasks = new Task[PipelineLength]; for (int i = 0; i < tasks.Length; ++i) { tasks[i] = MakeRequest(i); } await tasks.WhenAllOrAnyFailed(10_000); async Task MakeRequest(int requestNo) { await using ValueHttpRequest request = (await client.CreateNewRequestAsync(Version, HttpVersionPolicy.RequestVersionExact)).Value; request.ConfigureRequest(contentLength: 0, hasTrailingHeaders: false); request.WriteRequest(HttpMethod.Get, serverUri); request.WriteHeader("X-Request-No", requestNo.ToString(CultureInfo.InvariantCulture)); await request.CompleteRequestAsync(); TestHeadersSink headers = await request.ReadAllHeadersAsync(); Assert.Equal(requestNo.ToString(CultureInfo.InvariantCulture), headers.GetSingleValue("X-Response-No")); } }, async server => { var streams = new (HttpTestStream, HttpTestFullRequest)[PipelineLength]; for (int i = 0; i < streams.Length; ++i) { HttpTestStream stream = await server.AcceptStreamAsync(); HttpTestFullRequest request = await stream.ReceiveFullRequestAsync(); Assert.Equal(i.ToString(CultureInfo.InvariantCulture), request.Headers.GetSingleValue("X-Request-No")); streams[i] = (stream, request); } for (int i = 0; i < streams.Length; ++i) { (HttpTestStream stream, HttpTestFullRequest request) = streams[i]; var responseHeaders = new TestHeadersSink() { { "X-Response-No", i.ToString(CultureInfo.InvariantCulture) } }; await stream.SendResponseAsync(headers: responseHeaders); await stream.DisposeAsync(); } });
public static async Task <TestHeadersSink> ReadAllTrailingHeadersAsync(this ValueHttpRequest request) { var sink = new TestHeadersSink(); if (await request.ReadToTrailingHeadersAsync().ConfigureAwait(false)) { await request.ReadHeadersAsync(sink, state : null).ConfigureAwait(false); } return(sink); }
public async Task Pipelining_PausedReads_Success() { if (TrickleForceAsync) { // This test depends on synchronous completion of reads, so will not work when async completion is forced. return; } const int PipelineLength = 10; using var semaphore = new SemaphoreSlim(0); await RunMultiStreamTest( async (client, serverUri) => { ValueHttpRequest prev = (await client.CreateNewRequestAsync(Version, HttpVersionPolicy.RequestVersionExact)).Value; prev.ConfigureRequest(contentLength: 0, hasTrailingHeaders: false); prev.WriteRequest(HttpMethod.Get, serverUri); await prev.CompleteRequestAsync(); await semaphore.WaitAsync(); for (int i = 1; i < PipelineLength; ++i) { ValueHttpRequest next = (await client.CreateNewRequestAsync(Version, HttpVersionPolicy.RequestVersionExact)).Value; next.ConfigureRequest(contentLength: 0, hasTrailingHeaders: false); next.WriteRequest(HttpMethod.Get, serverUri); await next.CompleteRequestAsync(); await semaphore.WaitAsync(); ValueTask <HttpReadType> nextReadTask = next.ReadAsync(); // wait for write to complete to guarantee DisposeAsync() will complete synchronously. Assert.False(nextReadTask.IsCompleted); await prev.DisposeAsync(); Assert.True(nextReadTask.IsCompleted); Assert.Equal(HttpReadType.FinalResponse, await nextReadTask); prev = next; } await prev.DisposeAsync(); }, async server => { for (int i = 0; i < PipelineLength; ++i) { await server.ReceiveAndSendSingleRequestAsync(); semaphore.Release(); } }); }
public static async Task <byte[]> ReadAllContentAsync(this ValueHttpRequest request) { var memoryStream = new MemoryStream(); var contentStream = new HttpContentStream(request, ownsRequest: false); await using (contentStream.ConfigureAwait(false)) { await contentStream.CopyToAsync(memoryStream).ConfigureAwait(false); } return(memoryStream.ToArray()); }
static async Task Main(string[] args) { Environment.SetEnvironmentVariable("DOTNET_SYSTEM_THREADING_POOLASYNCVALUETASKS", "1"); await using ConnectionFactory connectionFactory = new MemoryConnectionFactory(); await using ConnectionListener listener = await connectionFactory.ListenAsync(); await using SimpleHttp1Server server = new(listener, triggerBytes, responseBytes); await using Connection connection = await connectionFactory.ConnectAsync(listener.EndPoint !); await using HttpConnection httpConnection = new Http1Connection(connection, HttpPrimitiveVersion.Version11); if (!Debugger.IsAttached) { Console.WriteLine("Press any key to continue, once profiler is attached..."); Console.ReadKey(); } for (int i = 0; i < 1000000; ++i) { await using ValueHttpRequest request = (await httpConnection.CreateNewRequestAsync(HttpPrimitiveVersion.Version11, HttpVersionPolicy.RequestVersionExact)) ?? throw new Exception("HttpConnection failed to return a request"); request.ConfigureRequest(contentLength: 0, hasTrailingHeaders: false); request.WriteRequest(HttpRequest.GetMethod, authority, pathAndQuery); request.WriteHeader(preparedRequestHeaders); foreach ((byte[] name, byte[] value) in dynamicRequestHeaders) { request.WriteHeader(name, value); } await request.CompleteRequestAsync(); while (await request.ReadAsync() != HttpReadType.EndOfStream) { // do nothing, just draining. } } }
/// <inheritdoc/> public override async ValueTask <Connection> ConnectAsync(EndPoint endPoint, IConnectionProperties?options = null, CancellationToken cancellationToken = default) { string authority = endPoint switch { DnsEndPoint dns => Tools.EscapeIdnHost(dns.Host) + ":" + dns.Port.ToString(CultureInfo.InvariantCulture), IPEndPoint ip4 when ip4.AddressFamily == AddressFamily.InterNetwork => ip4.Address.ToString() + ":" + ip4.Port.ToString(CultureInfo.InvariantCulture), IPEndPoint ip6 when ip6.AddressFamily == AddressFamily.InterNetworkV6 => "[" + ip6.Address.ToString() + "]:" + ip6.Port.ToString(CultureInfo.InvariantCulture), null => throw new ArgumentNullException(nameof(endPoint)), _ => throw new ArgumentException($"{nameof(EndPoint)} is of an unsupported type. Must be one of {nameof(DnsEndPoint)} or {nameof(IPEndPoint)}", nameof(endPoint)) }; byte[] authorityBytes = Encoding.ASCII.GetBytes(authority); ValueHttpRequest request = (await _httpConnection.CreateNewRequestAsync(_httpVersion, _httpVersionPolicy, cancellationToken).ConfigureAwait(false)) ?? throw new Exception($"{nameof(HttpConnection)} in use by {nameof(HttpTunnelConnectionFactory)} has been closed by peer."); try { request.ConfigureRequest(contentLength: null, hasTrailingHeaders: false); request.WriteConnectRequest(authorityBytes); await request.FlushHeadersAsync(cancellationToken).ConfigureAwait(false); bool hasResponse = await request.ReadToFinalResponseAsync(cancellationToken).ConfigureAwait(false); Debug.Assert(hasResponse); if ((int)request.StatusCode > 299) { throw new Exception($"Connect to HTTP tunnel failed; received status code {request.StatusCode}."); } var localEndPoint = new TunnelEndPoint(request.LocalEndPoint, request.RemoteEndPoint); var stream = new HttpContentStream(request, ownsRequest: true); return(new HttpTunnelConnection(localEndPoint, endPoint, stream)); } catch { await request.DisposeAsync(cancellationToken).ConfigureAwait(false); throw; } }
private async Task ClientSendHelperAsync(ValueHttpRequest client, Uri serverUri, int testIdx, TestHeadersSink requestHeaders, List <string> requestContent, TestHeadersSink?requestTrailingHeaders) { long contentLength = requestContent.Sum(x => (long)x.Length); client.ConfigureRequest(contentLength, hasTrailingHeaders: requestTrailingHeaders != null); client.WriteRequest(HttpMethod.Post, serverUri); client.WriteHeader("Content-Length", contentLength.ToString(CultureInfo.InvariantCulture)); client.WriteHeader("Test-Index", testIdx.ToString(CultureInfo.InvariantCulture)); client.WriteHeaders(requestHeaders); foreach (string content in requestContent) { await client.WriteContentAsync(content); } if (requestTrailingHeaders != null) { client.WriteTrailingHeaders(requestTrailingHeaders); } await client.CompleteRequestAsync(); }
public async Task Pipelining_PausedWrites_Success() { const int PipelineLength = 10; await RunMultiStreamTest( async (client, serverUri) => { ValueHttpRequest prev = (await client.CreateNewRequestAsync(Version, HttpVersionPolicy.RequestVersionExact)).Value; for (int i = 1; i < PipelineLength; ++i) { ValueTask <ValueHttpRequest?> nextTask = client.CreateNewRequestAsync(Version, HttpVersionPolicy.RequestVersionExact); prev.ConfigureRequest(contentLength: 0, hasTrailingHeaders: false); prev.WriteRequest(HttpMethod.Get, serverUri); Assert.False(nextTask.IsCompleted); await prev.CompleteRequestAsync(); Assert.True(nextTask.IsCompleted); await prev.DisposeAsync(); prev = (await nextTask).Value; } prev.ConfigureRequest(contentLength: 0, hasTrailingHeaders: false); prev.WriteRequest(HttpMethod.Get, serverUri); await prev.CompleteRequestAsync(); await prev.DisposeAsync(); }, async server => { for (int i = 0; i < PipelineLength; ++i) { await server.ReceiveAndSendSingleRequestAsync(); } }); }
internal async Task RunSingleStreamTest(Func <ValueHttpRequest, Uri, Task> clientFunc, Func <HttpTestStream, Task> serverFunc, int?millisecondsTimeout = null) { await RunMultiStreamTest( async (client, serverUri) => { ValueHttpRequest?optionalRequest = await client.CreateNewRequestAsync(Version, HttpVersionPolicy.RequestVersionExact).ConfigureAwait(false); Assert.NotNull(optionalRequest); ValueHttpRequest request = optionalRequest.Value; await using (request.ConfigureAwait(false)) { await clientFunc(request, serverUri).ConfigureAwait(false); await request.DrainAsync().ConfigureAwait(false); } }, async server => { HttpTestStream request = await server.AcceptStreamAsync().ConfigureAwait(false); await using (request.ConfigureAwait(false)) { await serverFunc(request).ConfigureAwait(false); } }, millisecondsTimeout).ConfigureAwait(false); }
public PooledHttpRequest(ValueHttpRequest request, PooledHttpConnection owningConnection) { _request = request; _owningConnection = owningConnection; }
public PrimitiveHttpContentStream(ValueHttpRequest request) : base(request, ownsRequest: true) { }
internal override async Task RunSingleStreamTest(Func <ValueHttpRequest, Uri, Task> clientFunc, Func <HttpTestStream, Task> serverFunc, int?millisecondsTimeout = null) { ConnectionFactory connectionFactory = CreateConnectionFactory(); await using (connectionFactory.ConfigureAwait(false)) { var server = new Http1TestServer(await connectionFactory.ListenAsync().ConfigureAwait(false)); await using (server.ConfigureAwait(false)) { var uriBuilder = new UriBuilder { Scheme = Uri.UriSchemeHttp, Path = "/" }; switch (server.EndPoint) { case DnsEndPoint dnsEp: uriBuilder.Host = dnsEp.Host; uriBuilder.Port = dnsEp.Port; break; case IPEndPoint ipEp: uriBuilder.Host = ipEp.Address.ToString(); uriBuilder.Port = ipEp.Port; break; default: uriBuilder.Host = "localhost"; uriBuilder.Port = 80; break; } Uri serverUri = uriBuilder.Uri; await RunClientServer(RunClientAsync, RunServerAsync, millisecondsTimeout).ConfigureAwait(false); async Task RunClientAsync() { HttpConnection connection = new Http1Connection(await connectionFactory.ConnectAsync(server.EndPoint !).ConfigureAwait(false)); await using (connection.ConfigureAwait(false)) { ValueHttpRequest?optionalRequest = await connection.CreateNewRequestAsync(HttpPrimitiveVersion.Version11, HttpVersionPolicy.RequestVersionExact).ConfigureAwait(false); Assert.NotNull(optionalRequest); ValueHttpRequest request = optionalRequest.Value; await using (request.ConfigureAwait(false)) { await clientFunc(request, serverUri).ConfigureAwait(false); await request.DrainAsync().ConfigureAwait(false); } } } async Task RunServerAsync() { HttpTestConnection connection = await server.AcceptAsync().ConfigureAwait(false); await using (connection.ConfigureAwait(false)) { HttpTestStream request = await connection.AcceptStreamAsync().ConfigureAwait(false); await using (request.ConfigureAwait(false)) { await serverFunc(request).ConfigureAwait(false); } } } } } }
public override async ValueTask ProcessAsync(HttpMessage message) { var pipelineRequest = message.Request; var host = pipelineRequest.Uri.Host; HttpMethod method = MapMethod(pipelineRequest.Method); Connection connection = await connectionFactory.ConnectAsync(new DnsEndPoint(host, 80)); HttpConnection httpConnection = new Http1Connection(connection, HttpPrimitiveVersion.Version11); await using (ValueHttpRequest request = (await httpConnection.CreateNewRequestAsync(HttpPrimitiveVersion.Version11, HttpVersionPolicy.RequestVersionExact)).Value) { RequestContent pipelineContent = pipelineRequest.Content; long contentLength = 0; if (pipelineContent != null) { if (!pipelineContent.TryComputeLength(out contentLength)) { throw new NotImplementedException(); } } request.ConfigureRequest(contentLength: contentLength, hasTrailingHeaders: false); request.WriteRequest(method, pipelineRequest.Uri.ToUri()); var pipelineHeaders = pipelineRequest.Headers; foreach (var header in pipelineHeaders) { request.WriteHeader(header.Name, header.Value); } checked { if (contentLength != 0) { using var ms = new MemoryStream((int)contentLength); // TODO: can the buffer be disposed here? await pipelineContent.WriteToAsync(ms, message.CancellationToken); await request.WriteContentAsync(ms.GetBuffer().AsMemory(0, (int)ms.Length)); } } await request.CompleteRequestAsync(); var response = new NoAllocResponse(); message.Response = response; await request.ReadToFinalResponseAsync(); response.SetStatus((int)request.StatusCode); if (await request.ReadToHeadersAsync()) { await request.ReadHeadersAsync(response, state : null); } if (await request.ReadToContentAsync()) { var buffer = new byte[4096]; int readLen; do { while ((readLen = await request.ReadContentAsync(buffer)) != 0) { if (readLen < 4096) { response.ContentStream = new MemoryStream(buffer, 0, readLen); } else { throw new NotImplementedException(); } } }while (await request.ReadToNextContentAsync()); } if (await request.ReadToTrailingHeadersAsync()) { await request.ReadHeadersAsync(response, state : null); } } }
public static ValueTask WriteContentAsync(this ValueHttpRequest request, string content) => request.WriteContentAsync(Encoding.UTF8.GetBytes(content));
public void Init(ValueHttpRequest request, PooledHttpConnection owningConnection) { _request = request; _owningConnection = owningConnection; Reset(); }
public static async Task <string> ReadAllContentAsStringAsync(this ValueHttpRequest request) => Encoding.UTF8.GetString(await ReadAllContentAsync(request).ConfigureAwait(false));