Example #1
0
        public async Task AltSvc_ResponseFrame_UpgradeFrom20_Success()
        {
            using Http2LoopbackServer firstServer  = Http2LoopbackServer.CreateServer();
            using Http3LoopbackServer secondServer = new Http3LoopbackServer();
            using HttpClient client = CreateHttpClient();

            Task <HttpResponseMessage> firstResponseTask = client.GetAsync(firstServer.Address);
            Task serverTask = Task.Run(async() =>
            {
                using Http2LoopbackConnection connection = await firstServer.EstablishConnectionAsync();

                int streamId = await connection.ReadRequestHeaderAsync();
                await connection.SendDefaultResponseHeadersAsync(streamId);
                await connection.WriteFrameAsync(new AltSvcFrame("", $"h3=\"{secondServer.Address.IdnHost}:{secondServer.Address.Port}\"", streamId));
                await connection.SendResponseDataAsync(streamId, Array.Empty <byte>(), true);
            });

            await new[] { firstResponseTask, serverTask }.WhenAllOrAnyFailed(30_000);

            HttpResponseMessage firstResponse = firstResponseTask.Result;

            Assert.True(firstResponse.IsSuccessStatusCode);

            await AltSvc_Upgrade_Success(firstServer, secondServer, client);
        }
        public async Task Http2GetAsync_TrailingHeaders_NoData_EmptyResponseObserved()
        {
            using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
                using (HttpClient client = new HttpClient(CreateHttpClientHandler(useSocketsHttpHandler: true, useHttp2LoopbackServer: true)))
                {
                    Task <HttpResponseMessage> sendTask = client.GetAsync(server.Address);

                    await server.EstablishConnectionAsync();

                    int streamId = await server.ReadRequestHeaderAsync();

                    // Response header.
                    await server.SendDefaultResponseHeadersAsync(streamId);

                    // No data.

                    // Response trailing headers
                    await server.SendResponseHeadersAsync(streamId, isTrailingHeader : true, headers : s_trailingHeaders);

                    HttpResponseMessage response = await sendTask;
                    Assert.Equal(HttpStatusCode.OK, response.StatusCode);
                    Assert.Equal <byte>(Array.Empty <byte>(), await response.Content.ReadAsByteArrayAsync());
                    Assert.Contains("amazingtrailer", response.TrailingHeaders.GetValues("MyCoolTrailerHeader"));
                    Assert.Contains("World", response.TrailingHeaders.GetValues("Hello"));
                }
        }
        public async Task AltSvc_ResponseFrame_UpgradeFrom20_Success()
        {
            using Http2LoopbackServer firstServer  = Http2LoopbackServer.CreateServer();
            using Http3LoopbackServer secondServer = new Http3LoopbackServer();
            using HttpClient client = CreateHttpClient(CreateHttpClientHandler(HttpVersion.Version30));

            Task <HttpResponseMessage> firstResponseTask = client.GetAsync(firstServer.Address);

            using (Http2LoopbackConnection connection = await firstServer.EstablishConnectionAsync())
            {
                int streamId = await connection.ReadRequestHeaderAsync();

                await connection.SendDefaultResponseHeadersAsync(streamId);

                await connection.WriteFrameAsync(new AltSvcFrame("", $"h3={secondServer.Address.IdnHost}:{secondServer.Address.Port}", streamId));

                await connection.SendResponseDataAsync(streamId, Array.Empty <byte>(), true);
            }

            HttpResponseMessage firstResponse = await firstResponseTask;

            Assert.True(firstResponse.IsSuccessStatusCode);

            await AltSvc_Upgrade_Success(firstServer, secondServer, client);
        }
        public async Task AltSvc_ConnectionFrame_UpgradeFrom20_Success()
        {
            // [ActiveIssue("https://github.com/dotnet/runtime/issues/54050")]
            if (UseQuicImplementationProvider == QuicImplementationProviders.Mock)
            {
                return;
            }

            using Http2LoopbackServer firstServer  = Http2LoopbackServer.CreateServer();
            using Http3LoopbackServer secondServer = CreateHttp3LoopbackServer();
            using HttpClient client = CreateHttpClient(HttpVersion.Version20);

            Task <HttpResponseMessage> firstResponseTask = client.GetAsync(firstServer.Address);
            Task serverTask = Task.Run(async() =>
            {
                using Http2LoopbackConnection connection = await firstServer.EstablishConnectionAsync();

                int streamId = await connection.ReadRequestHeaderAsync();
                await connection.WriteFrameAsync(new AltSvcFrame($"https://{firstServer.Address.IdnHost}:{firstServer.Address.Port}", $"h3=\"{secondServer.Address.IdnHost}:{secondServer.Address.Port}\"", streamId: 0));
                await connection.SendDefaultResponseAsync(streamId);
            });

            await new[] { firstResponseTask, serverTask }.WhenAllOrAnyFailed(30_000);

            HttpResponseMessage firstResponse = firstResponseTask.Result;

            Assert.True(firstResponse.IsSuccessStatusCode);

            await AltSvc_Upgrade_Success(firstServer, secondServer, client);
        }
Example #5
0
        public async Task Http2GetAsync_TrailerHeaders_TrailingHeaderNoBody()
        {
            using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
                using (HttpClient client = CreateHttpClient())
                {
                    Task <HttpResponseMessage> sendTask = client.GetAsync(server.Address);

                    Http2LoopbackConnection connection = await server.EstablishConnectionAsync();

                    int streamId = await connection.ReadRequestHeaderAsync();

                    // Response header.
                    await connection.SendDefaultResponseHeadersAsync(streamId);

                    await connection.SendResponseHeadersAsync(streamId, endStream : true, isTrailingHeader : true, headers : TrailingHeaders);

                    HttpResponseMessage response = await sendTask;
                    Assert.Equal(HttpStatusCode.OK, response.StatusCode);

                    var trailingHeaders = GetTrailingHeaders(response);
                    Assert.Equal(TrailingHeaders.Count, trailingHeaders.Count());
                    Assert.Contains("amazingtrailer", trailingHeaders.GetValues("MyCoolTrailerHeader"));
                    Assert.Contains("World", trailingHeaders.GetValues("Hello"));
                }
        }
Example #6
0
        public async Task Http2GetAsync_NoTrailingHeaders_EmptyCollection()
        {
            using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
                using (HttpClient client = CreateHttpClient())
                {
                    Task <HttpResponseMessage> sendTask = client.GetAsync(server.Address);

                    Http2LoopbackConnection connection = await server.EstablishConnectionAsync();

                    int streamId = await connection.ReadRequestHeaderAsync();

                    // Response header.
                    await connection.SendDefaultResponseHeadersAsync(streamId);

                    // Response data.
                    await connection.WriteFrameAsync(MakeDataFrame(streamId, DataBytes, endStream : true));

                    // Server doesn't send trailing header frame.
                    HttpResponseMessage response = await sendTask;
                    Assert.Equal(HttpStatusCode.OK, response.StatusCode);

                    var trailingHeaders = GetTrailingHeaders(response);
                    Assert.NotNull(trailingHeaders);
                    Assert.Equal(0, trailingHeaders.Count());
                }
        }
        public async Task Http2GetAsyncResponseHeadersReadOption_TrailingHeaders_Available()
        {
            using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
                using (HttpClient client = CreateHttpClient())
                {
                    Task <HttpResponseMessage> sendTask = client.GetAsync(server.Address, HttpCompletionOption.ResponseHeadersRead);

                    Http2LoopbackConnection connection = await server.EstablishConnectionAsync();

                    int streamId = await connection.ReadRequestHeaderAsync();

                    // Response header.
                    await connection.SendDefaultResponseHeadersAsync(streamId);

                    // Response data, missing Trailers.
                    await connection.WriteFrameAsync(MakeDataFrame(streamId, DataBytes));

                    HttpResponseMessage response = await sendTask;
                    Assert.Equal(HttpStatusCode.OK, response.StatusCode);

                    // Pending read on the response content.
                    var trailingHeaders = GetTrailingHeaders(response);
                    Assert.True(trailingHeaders == null || trailingHeaders.Count() == 0);

                    Stream stream = await response.Content.ReadAsStreamAsync(TestAsync);

                    Byte[] data = new Byte[100];
                    await stream.ReadAsync(data, 0, data.Length);

                    // Intermediate test - haven't reached stream EOF yet.
                    trailingHeaders = GetTrailingHeaders(response);
                    Assert.True(trailingHeaders == null || trailingHeaders.Count() == 0);

                    // Finish data stream and write out trailing headers.
                    await connection.WriteFrameAsync(MakeDataFrame(streamId, DataBytes));

                    await connection.SendResponseHeadersAsync(streamId, endStream : true, isTrailingHeader : true, headers : TrailingHeaders);

                    // Read data until EOF is reached
                    while (stream.Read(data, 0, data.Length) != 0)
                    {
                        ;
                    }

                    trailingHeaders = GetTrailingHeaders(response);
                    Assert.Equal(TrailingHeaders.Count, trailingHeaders.Count());
                    Assert.Contains("amazingtrailer", trailingHeaders.GetValues("MyCoolTrailerHeader"));
                    Assert.Contains("World", trailingHeaders.GetValues("Hello"));

                    // Read when already zero. Trailers shouldn't be changed.
                    stream.Read(data, 0, data.Length);

                    trailingHeaders = GetTrailingHeaders(response);
                    Assert.Equal(TrailingHeaders.Count, trailingHeaders.Count());
                }
        }
Example #8
0
        public async Task ReadAndWriteAfterServerHasSentEndStream_Success()
        {
            TaskCompletionSource <Stream> requestStreamTcs  = new TaskCompletionSource <Stream>(TaskCreationOptions.RunContinuationsAsynchronously);
            TaskCompletionSource <object> completeStreamTcs = new TaskCompletionSource <object>(TaskCreationOptions.RunContinuationsAsynchronously);

            using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
                using (HttpClient client = CreateHttpClient())
                {
                    HttpRequestMessage message = new HttpRequestMessage(HttpMethod.Post, server.Address);
                    message.Version = new Version(2, 0);
                    message.Content = new StreamingContent(async s =>
                    {
                        await s.WriteAsync(new byte[50]);

                        requestStreamTcs.SetResult(s);

                        await completeStreamTcs.Task;
                    });

                    Task serverActions = RunServer();

                    HttpResponseMessage response = await client.SendAsync(message, HttpCompletionOption.ResponseHeadersRead);

                    Assert.Equal(HttpStatusCode.OK, response.StatusCode);

                    await serverActions;

                    Stream requestStream  = await requestStreamTcs.Task;
                    Stream responseStream = await response.Content.ReadAsStreamAsync();

                    // Successfully because endstream hasn't been read yet.
                    await requestStream.WriteAsync(new byte[50]);

                    byte[] buffer    = new byte[50];
                    int    readCount = await responseStream.ReadAsync(buffer, 0, buffer.Length);

                    Assert.Equal(DataBytes.Length, readCount);

                    readCount = await responseStream.ReadAsync(buffer, 0, buffer.Length);

                    Assert.Equal(0, readCount);

                    async Task RunServer()
                    {
                        Http2LoopbackConnection connection = await server.EstablishConnectionAsync();

                        int streamId = await connection.ReadRequestHeaderAsync(expectEndOfStream : false);

                        await connection.SendDefaultResponseHeadersAsync(streamId, endStream : false);

                        await connection.WriteFrameAsync(MakeDataFrame(streamId, DataBytes, endStream : true));
                    };
                }
        }
Example #9
0
        public async Task AfterReadResponseServerError_ClientRead()
        {
            TaskCompletionSource <Stream> requestStreamTcs  = new TaskCompletionSource <Stream>(TaskCreationOptions.RunContinuationsAsynchronously);
            TaskCompletionSource <object> completeStreamTcs = new TaskCompletionSource <object>(TaskCreationOptions.RunContinuationsAsynchronously);

            using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
                using (HttpClient client = CreateHttpClient())
                {
                    HttpRequestMessage message = new HttpRequestMessage(HttpMethod.Post, server.Address);
                    message.Version = new Version(2, 0);
                    message.Content = new StreamingContent(async s =>
                    {
                        requestStreamTcs.SetResult(s);

                        await completeStreamTcs.Task;
                    });

                    Task <HttpResponseMessage> sendTask = client.SendAsync(message, HttpCompletionOption.ResponseHeadersRead);

                    Http2LoopbackConnection connection = await server.EstablishConnectionAsync();

                    Stream requestStream = await requestStreamTcs.Task;
                    await requestStream.WriteAsync(new byte[50]);

                    int streamId = await connection.ReadRequestHeaderAsync(expectEndOfStream : false);

                    Frame frame = await connection.ReadDataFrameAsync();

                    // Response header.
                    await connection.SendDefaultResponseHeadersAsync(streamId);

                    // Response data.
                    await connection.WriteFrameAsync(MakeDataFrame(streamId, DataBytes, endStream : false));

                    HttpResponseMessage response = await sendTask;
                    Assert.Equal(HttpStatusCode.OK, response.StatusCode);

                    Stream responseStream = await response.Content.ReadAsStreamAsync();

                    // Read response data.
                    byte[] buffer    = new byte[1024];
                    int    readCount = await responseStream.ReadAsync(buffer, 0, buffer.Length);

                    Assert.Equal(DataBytes.Length, readCount);

                    // Server sends RST_STREAM.
                    await connection.WriteFrameAsync(new RstStreamFrame(FrameFlags.EndStream, 0, streamId));

                    await Assert.ThrowsAsync <IOException>(() => responseStream.ReadAsync(buffer, 0, buffer.Length));
                }
        }
Example #10
0
        private static async Task <int> EstablishConnectionAndProcessOneRequestAsync(HttpClient client, Http2LoopbackServer server)
        {
            // Establish connection and send initial request/response to ensure connection is available for subsequent use
            Task <HttpResponseMessage> sendTask = client.GetAsync(server.Address);

            await server.EstablishConnectionAsync();

            int streamId = await server.ReadRequestHeaderAsync();

            await server.SendDefaultResponseAsync(streamId);

            HttpResponseMessage response = await sendTask;

            Assert.Equal(HttpStatusCode.OK, response.StatusCode);
            Assert.Equal(0, (await response.Content.ReadAsByteArrayAsync()).Length);

            return(streamId);
        }
Example #11
0
        public async Task Http2GetAsync_MissingTrailer_TrailingHeadersAccepted(bool responseHasContentLength)
        {
            using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
                using (HttpClient client = CreateHttpClient())
                {
                    Task <HttpResponseMessage> sendTask = client.GetAsync(server.Address);

                    Http2LoopbackConnection connection = await server.EstablishConnectionAsync();

                    int streamId = await connection.ReadRequestHeaderAsync();

                    // Response header.
                    if (responseHasContentLength)
                    {
                        await connection.SendResponseHeadersAsync(streamId, endStream : false, headers : new[] { new HttpHeaderData("Content-Length", DataBytes.Length.ToString()) });
                    }
                    else
                    {
                        await connection.SendDefaultResponseHeadersAsync(streamId);
                    }

                    // Response data, missing Trailers.
                    await connection.WriteFrameAsync(MakeDataFrame(streamId, DataBytes));

                    // Additional trailing header frame.
                    await connection.SendResponseHeadersAsync(streamId, isTrailingHeader : true, headers : TrailingHeaders, endStream : true);

                    HttpResponseMessage response = await sendTask;
                    Assert.Equal(HttpStatusCode.OK, response.StatusCode);

                    var trailingHeaders = GetTrailingHeaders(response);
                    Assert.Equal(TrailingHeaders.Count, trailingHeaders.Count());
                    Assert.Contains("amazingtrailer", trailingHeaders.GetValues("MyCoolTrailerHeader"));
                    Assert.Contains("World", trailingHeaders.GetValues("Hello"));
                }
        }
        private async Task EstablishConnectionAsync(Http2LoopbackServer server)
        {
            _connection = await server.EstablishConnectionAsync();

            _incomingFramesTask = ProcessIncomingFramesAsync(_incomingFramesCts.Token);
        }
Example #13
0
        public async Task WriteRequestAfterReadResponse()
        {
            TaskCompletionSource <object> tcs = new TaskCompletionSource <object>(TaskCreationOptions.RunContinuationsAsynchronously);

            using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
                using (HttpClient client = CreateHttpClient())
                {
                    HttpRequestMessage message = new HttpRequestMessage(HttpMethod.Post, server.Address);
                    message.Version = new Version(2, 0);
                    message.Content = new StreamingContent(async s =>
                    {
                        await s.WriteAsync(new byte[50]);

                        await tcs.Task;

                        await s.WriteAsync(new byte[50]);
                    }, length: null);

                    Task <HttpResponseMessage> sendTask = client.SendAsync(message, HttpCompletionOption.ResponseHeadersRead);

                    Http2LoopbackConnection connection = await server.EstablishConnectionAsync();

                    int streamId = await connection.ReadRequestHeaderAsync(expectEndOfStream : false);

                    Frame frame = await connection.ReadDataFrameAsync();

                    // Response header.
                    await connection.SendDefaultResponseHeadersAsync(streamId);

                    // Response data.
                    await connection.WriteFrameAsync(MakeDataFrame(streamId, DataBytes, endStream : false));

                    HttpResponseMessage response = await sendTask;
                    Assert.Equal(HttpStatusCode.OK, response.StatusCode);

                    using Stream responseStream = await response.Content.ReadAsStreamAsync();

                    // Read response data.
                    byte[] buffer    = new byte[1024];
                    int    readCount = await responseStream.ReadAsync(buffer, 0, buffer.Length);

                    Assert.Equal(DataBytes.Length, readCount);

                    // Finish sending request data.
                    tcs.SetResult(null);

                    frame = await connection.ReadDataFrameAsync();

                    // Response data.
                    await connection.WriteFrameAsync(MakeDataFrame(streamId, DataBytes, endStream : true));

                    // Finish reading response data.
                    readCount = await responseStream.ReadAsync(buffer, 0, buffer.Length);

                    Assert.Equal(DataBytes.Length, readCount);

                    readCount = await responseStream.ReadAsync(buffer, 0, buffer.Length);

                    Assert.Equal(0, readCount);
                }
        }
Example #14
0
        public async Task BackwardsCompatibility_DowngradeToHttp11()
        {
            TaskCompletionSource <object> completeStreamTcs = new TaskCompletionSource <object>(TaskCreationOptions.RunContinuationsAsynchronously);

            using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
                using (HttpClient client = CreateHttpClient())
                {
                    HttpRequestMessage message = new HttpRequestMessage(HttpMethod.Post, server.Address);
                    message.Version = new Version(2, 0);
                    message.Content = new StreamingContent(async s =>
                    {
                        await completeStreamTcs.Task;
                    });

                    Task <HttpResponseMessage> sendTask = client.SendAsync(message, HttpCompletionOption.ResponseHeadersRead);

                    // If WinHTTP doesn't support streaming a request without a length then it will fallback
                    // to HTTP/1.1. This is pretty weird behavior but we keep it for backwards compatibility.
                    Exception ex = await Assert.ThrowsAsync <Exception>(async() => await server.EstablishConnectionAsync());

                    Assert.Equal("HTTP/1.1 request sent to HTTP/2 connection.", ex.Message);

                    completeStreamTcs.SetResult(null);
                }
        }