예제 #1
0
        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);
        }
예제 #2
0
 public static async Task WriteContentAsync(this ValueHttpRequest request, List <string> content)
 {
     foreach (string chunk in content)
     {
         await request.WriteContentAsync(chunk).ConfigureAwait(false);
     }
 }
예제 #3
0
        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();
            }
        }
예제 #4
0
        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.");
                }
            }
        }
예제 #5
0
 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);
         }
     }
 }
예제 #6
0
        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();
                }
            });
예제 #7
0
        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);
        }
예제 #8
0
        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();
                }
            });
        }
예제 #9
0
        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());
        }
예제 #10
0
        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;
            }
        }
예제 #12
0
        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();
        }
예제 #13
0
        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();
                }
            });
        }
예제 #14
0
        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)
 {
 }
예제 #17
0
        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);
                            }
                        }
                    }
                }
            }
        }
예제 #18
0
        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);
                }
            }
        }
예제 #19
0
 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();
 }
예제 #21
0
 public static async Task <string> ReadAllContentAsStringAsync(this ValueHttpRequest request)
 => Encoding.UTF8.GetString(await ReadAllContentAsync(request).ConfigureAwait(false));