public async Task Http2GetAsync_TrailingHeaders_NoData_EmptyResponseObserved()
        {
            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);

                    // No data.

                    // Response trailing headers
                    await connection.SendResponseHeadersAsync(streamId, isTrailingHeader : true, headers : TrailingHeaders);

                    HttpResponseMessage response = await sendTask;
                    Assert.Equal(HttpStatusCode.OK, response.StatusCode);
                    Assert.Equal <byte>(Array.Empty <byte>(), await response.Content.ReadAsByteArrayAsync());

                    var trailingHeaders = GetTrailingHeaders(response);
                    Assert.Contains("amazingtrailer", trailingHeaders.GetValues("MyCoolTrailerHeader"));
                    Assert.Contains("World", trailingHeaders.GetValues("Hello"));
                }
        }
Пример #2
0
        public async Task AltSvc_ResponseFrame_UpgradeFrom20_Success()
        {
            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.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);
        }
Пример #3
0
        public async Task DataFrame_TooLong_ConnectionError()
        {
            HttpClientHandler handler = CreateHttpClientHandler();

            handler.ServerCertificateCustomValidationCallback = TestHelper.AllowAllCertificates;
            TestHelper.EnsureHttp2Feature(handler);

            using (var server = Http2LoopbackServer.CreateServer())
                using (var client = new HttpClient(handler))
                {
                    Task sendTask = client.GetAsync(server.Address);

                    await server.AcceptConnectionAsync();

                    await server.SendConnectionPrefaceAsync();

                    // Receive the request header frame.
                    Frame receivedFrame = await server.ReadFrameAsync(TimeSpan.FromSeconds(30));

                    // Send a malformed frame.
                    DataFrame invalidFrame = new DataFrame(new byte[Frame.MaxFrameLength + 1], FrameFlags.None, 0, 0);
                    await server.WriteFrameAsync(invalidFrame);

                    // As this is a connection level error, the client should see the request fail.
                    await Assert.ThrowsAsync <HttpRequestException>(async() => await sendTask);

                    // The server should receive a GOAWAY frame.
                    receivedFrame = await server.ReadFrameAsync(TimeSpan.FromSeconds(30));

                    Assert.Equal(FrameType.GoAway, receivedFrame.Type);
                }
        }
Пример #4
0
        public async Task AltSvc_Header_Upgrade_Success(Version fromVersion)
        {
            // The test makes a request to a HTTP/1 or HTTP/2 server first, which supplies an Alt-Svc header pointing to the second server.
            using GenericLoopbackServer firstServer =
                      fromVersion.Major switch
                  {
                      1 => new LoopbackServer(new LoopbackServer.Options { UseSsl = true }),
                      2 => Http2LoopbackServer.CreateServer(),
                      _ => throw new Exception("Unknown HTTP version.")
                  };

            // The second request is expected to come in on this HTTP/3 server.
            using var secondServer = new Http3LoopbackServer();

            using HttpClient client = CreateHttpClient();

            Task <HttpResponseMessage> firstResponseTask = client.GetAsync(firstServer.Address);
            Task serverTask = firstServer.AcceptConnectionSendResponseAndCloseAsync(additionalHeaders: new[]
            {
                new HttpHeaderData("Alt-Svc", $"h3=\"{secondServer.Address.IdnHost}:{secondServer.Address.Port}\"")
            });

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

            using HttpResponseMessage firstResponse = firstResponseTask.Result;
            Assert.True(firstResponse.IsSuccessStatusCode);

            await AltSvc_Upgrade_Success(firstServer, secondServer, client);
        }
        public async Task HeadersFrame_IdleStream_ConnectionError()
        {
            if (IsWinHttpHandler)
            {
                // WinHTTP does not treat this as an error, it seems to ignore the HEADERS frame.
                return;
            }

            HttpClientHandler handler = CreateHttpClientHandler();

            handler.ServerCertificateCustomValidationCallback = TestHelper.AllowAllCertificates;

            using (var server = Http2LoopbackServer.CreateServer())
                using (var client = new HttpClient(handler))
                {
                    Task sendTask = client.GetAsync(server.Address);

                    await server.EstablishConnectionAsync();

                    int streamId = await server.ReadRequestHeaderAsync();

                    // Send a headers frame on stream 5, which is in the idle state.
                    await server.SendDefaultResponseHeadersAsync(5);

                    // As this is a connection level error, the client should see the request fail.
                    await Assert.ThrowsAsync <HttpRequestException>(async() => await sendTask);
                }
        }
        public async Task EmptyResponse_FrameReceived_ConnectionError()
        {
            HttpClientHandler handler = CreateHttpClientHandler();

            handler.ServerCertificateCustomValidationCallback = TestHelper.AllowAllCertificates;

            using (var server = Http2LoopbackServer.CreateServer())
                using (var client = new HttpClient(handler))
                {
                    Task <HttpResponseMessage> sendTask = client.GetAsync(server.Address);

                    await server.EstablishConnectionAsync();

                    int streamId = await server.ReadRequestHeaderAsync();

                    // Send empty response.
                    await server.SendDefaultResponseAsync(streamId);

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

                    // Send a frame on the now-closed stream.
                    DataFrame invalidFrame = new DataFrame(new byte[10], FrameFlags.None, 0, streamId);
                    await server.WriteFrameAsync(invalidFrame);

                    if (!IsWinHttpHandler)
                    {
                        // The client should close the connection as this is a fatal connection level error.
                        Assert.Null(await server.ReadFrameAsync(TimeSpan.FromSeconds(30)));
                    }
                }
        }
        public async Task Http2_StreamResetByServerAfterPartialBodySent_RequestFails()
        {
            HttpClientHandler handler = CreateHttpClientHandler();

            handler.ServerCertificateCustomValidationCallback = TestHelper.AllowAllCertificates;

            using (var server = Http2LoopbackServer.CreateServer())
                using (var client = new HttpClient(handler))
                {
                    Task <HttpResponseMessage> sendTask = client.GetAsync(server.Address);

                    await server.EstablishConnectionAsync();

                    int streamId = await server.ReadRequestHeaderAsync();

                    // Send response headers and partial response body
                    await server.SendDefaultResponseHeadersAsync(streamId);

                    DataFrame dataFrame = new DataFrame(new byte[10], FrameFlags.None, 0, streamId);
                    await server.WriteFrameAsync(dataFrame);

                    // Send a reset stream frame so that the stream moves to a terminal state.
                    RstStreamFrame resetStream = new RstStreamFrame(FrameFlags.None, 0x2, streamId);
                    await server.WriteFrameAsync(resetStream);

                    await Assert.ThrowsAsync <HttpRequestException>(async() => await sendTask);
                }
        }
        public async Task DataFrame_IdleStream_ConnectionError()
        {
            if (IsWinHttpHandler)
            {
                // WinHTTP does not treat this as an error, it seems to ignore the invalid frame.
                return;
            }

            HttpClientHandler handler = CreateHttpClientHandler();

            handler.ServerCertificateCustomValidationCallback = TestHelper.AllowAllCertificates;

            using (var server = Http2LoopbackServer.CreateServer())
                using (var client = new HttpClient(handler))
                {
                    Task <HttpResponseMessage> sendTask = client.GetAsync(server.Address);

                    await server.EstablishConnectionAsync();

                    await server.ReadRequestHeaderAsync();

                    // Send a data frame on stream 5, which is in the idle state.
                    DataFrame invalidFrame = new DataFrame(new byte[10], FrameFlags.None, 0, 5);
                    await server.WriteFrameAsync(invalidFrame);

                    // As this is a connection level error, the client should see the request fail.
                    await Assert.ThrowsAsync <HttpRequestException>(async() => await sendTask);
                }
        }
        public async Task Http2_StreamResetByServerBeforeHeadersSent_RequestFails()
        {
            if (IsWinHttpHandler)
            {
                // WinHTTP does not genenerate an exception here.
                // It seems to ignore a RST_STREAM sent before headers are sent, and continue to wait for HEADERS.
                return;
            }

            HttpClientHandler handler = CreateHttpClientHandler();

            handler.ServerCertificateCustomValidationCallback = TestHelper.AllowAllCertificates;

            using (var server = Http2LoopbackServer.CreateServer())
                using (var client = new HttpClient(handler))
                {
                    Task <HttpResponseMessage> sendTask = client.GetAsync(server.Address);

                    await server.EstablishConnectionAsync();

                    int streamId = await server.ReadRequestHeaderAsync();

                    // Send a reset stream frame so that the stream moves to a terminal state.
                    RstStreamFrame resetStream = new RstStreamFrame(FrameFlags.None, 0x2, streamId);
                    await server.WriteFrameAsync(resetStream);

                    await Assert.ThrowsAsync <HttpRequestException>(async() => await sendTask);
                }
        }
Пример #10
0
        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);
        }
Пример #11
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);
                }
        }
Пример #12
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);

            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 ResetResponseStream_FrameReceived_ConnectionError()
        {
            HttpClientHandler handler = CreateHttpClientHandler();

            handler.ServerCertificateCustomValidationCallback = TestHelper.AllowAllCertificates;

            using (var server = Http2LoopbackServer.CreateServer())
                using (var client = new HttpClient(handler))
                {
                    Task <HttpResponseMessage> sendTask = client.GetAsync(server.Address);

                    await server.EstablishConnectionAsync();

                    int streamId = await server.ReadRequestHeaderAsync();

                    await server.SendDefaultResponseHeadersAsync(streamId);

                    // Send a reset stream frame so that stream 1 moves to a terminal state.
                    RstStreamFrame resetStream = new RstStreamFrame(FrameFlags.None, 0x1, streamId);
                    await server.WriteFrameAsync(resetStream);

                    await Assert.ThrowsAsync <HttpRequestException>(async() => await sendTask);

                    // Send a frame on the now-closed stream.
                    DataFrame invalidFrame = new DataFrame(new byte[10], FrameFlags.None, 0, streamId);
                    await server.WriteFrameAsync(invalidFrame);

                    if (!IsWinHttpHandler)
                    {
                        // The client should close the connection as this is a fatal connection level error.
                        Assert.Null(await server.ReadFrameAsync(TimeSpan.FromSeconds(30)));
                    }
                }
        }
Пример #14
0
        public async Task ClosedStream_FrameReceived_ResetsStream()
        {
            HttpClientHandler handler = CreateHttpClientHandler();

            handler.ServerCertificateCustomValidationCallback = TestHelper.AllowAllCertificates;
            TestHelper.EnsureHttp2Feature(handler);

            using (var server = Http2LoopbackServer.CreateServer())
                using (var client = new HttpClient(handler))
                {
                    Task sendTask = client.GetAsync(server.Address);

                    await server.AcceptConnectionAsync();

                    await server.SendConnectionPrefaceAsync();

                    // Receive the request header frame.
                    Frame receivedFrame = await server.ReadFrameAsync(TimeSpan.FromSeconds(30));

                    // Send a reset stream frame so that stream 1 moves to a terminal state.
                    RstStreamFrame resetStream = new RstStreamFrame(FrameFlags.Padded, 0x1, 1);
                    await server.WriteFrameAsync(resetStream);

                    // Send a frame on the now-closed stream.
                    DataFrame invalidFrame = new DataFrame(new byte[10], FrameFlags.Padded, 10, 1);
                    await server.WriteFrameAsync(invalidFrame);

                    // Receive a RST_STREAM frame.
                    receivedFrame = await server.ReadFrameAsync(TimeSpan.FromSeconds(30));

                    Assert.Equal(FrameType.RstStream, receivedFrame.Type);

                    await Assert.ThrowsAsync <HttpRequestException>(async() => await sendTask);
                }
        }
Пример #15
0
        public async Task Http2_ServerSendsValidSettingsValues_Success()
        {
            HttpClientHandler handler = CreateHttpClientHandler();

            handler.ServerCertificateCustomValidationCallback = TestHelper.AllowAllCertificates;

            using (var server = Http2LoopbackServer.CreateServer())
                using (var client = new HttpClient(handler))
                {
                    Task <HttpResponseMessage> sendTask = client.GetAsync(server.Address);

                    // Send a bunch of valid SETTINGS values (that won't interfere with processing requests)
                    await server.EstablishConnectionAsync(
                        new SettingsEntry { SettingId = SettingId.HeaderTableSize, Value = 0 },
                        new SettingsEntry { SettingId = SettingId.HeaderTableSize, Value = 1 },
                        new SettingsEntry { SettingId = SettingId.HeaderTableSize, Value = 345678 },
                        new SettingsEntry { SettingId = SettingId.InitialWindowSize, Value = 0 },
                        new SettingsEntry { SettingId = SettingId.InitialWindowSize, Value = 1 },
                        new SettingsEntry { SettingId = SettingId.InitialWindowSize, Value = 4567890 },
                        new SettingsEntry { SettingId = SettingId.MaxConcurrentStreams, Value = 1 },
                        new SettingsEntry { SettingId = SettingId.MaxFrameSize, Value = 16384 },
                        new SettingsEntry { SettingId = SettingId.MaxFrameSize, Value = 16777215 },
                        new SettingsEntry { SettingId = SettingId.MaxHeaderListSize, Value = 0 },
                        new SettingsEntry { SettingId = SettingId.MaxHeaderListSize, Value = 10000000 },
                        new SettingsEntry { SettingId = (SettingId)5678, Value = 1234 });

                    int streamId = await server.ReadRequestHeaderAsync();

                    await server.SendDefaultResponseAsync(streamId);

                    HttpResponseMessage response = await sendTask;
                    Assert.Equal(HttpStatusCode.OK, response.StatusCode);
                }
        }
Пример #16
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());
                }
        }
Пример #17
0
        public async Task Http2_ZeroLengthResponseBody_Success()
        {
            HttpClientHandler handler = CreateHttpClientHandler();

            handler.ServerCertificateCustomValidationCallback = TestHelper.AllowAllCertificates;

            using (var server = Http2LoopbackServer.CreateServer())
                using (var client = new HttpClient(handler))
                {
                    Task <HttpResponseMessage> sendTask = client.GetAsync(server.Address);

                    await server.EstablishConnectionAsync();

                    int streamId = await server.ReadRequestHeaderAsync();

                    await server.SendDefaultResponseHeadersAsync(streamId);

                    // Send zero-length body
                    var frame = new DataFrame(new byte[0], FrameFlags.EndStream, 0, streamId);
                    await server.WriteFrameAsync(frame);

                    HttpResponseMessage response = await sendTask;
                    Assert.Equal(HttpStatusCode.OK, response.StatusCode);
                    Assert.Equal(0, (await response.Content.ReadAsByteArrayAsync()).Length);
                }
        }
Пример #18
0
        public async Task Http2GetAsync_MissingTrailer_TrailingHeadersAccepted()
        {
            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, 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"));
                }
        }
Пример #19
0
        public async Task CompletedResponse_FrameReceived_ConnectionError()
        {
            HttpClientHandler handler = CreateHttpClientHandler();

            handler.ServerCertificateCustomValidationCallback = TestHelper.AllowAllCertificates;

            using (var server = Http2LoopbackServer.CreateServer())
                using (var client = new HttpClient(handler))
                {
                    Task <HttpResponseMessage> sendTask = client.GetAsync(server.Address);

                    await server.EstablishConnectionAsync();

                    server.IgnoreWindowUpdates();
                    int streamId = await server.ReadRequestHeaderAsync();

                    // Send response and end stream.
                    await server.SendDefaultResponseHeadersAsync(streamId);

                    DataFrame dataFrame = new DataFrame(new byte[10], FrameFlags.EndStream, 0, streamId);
                    await server.WriteFrameAsync(dataFrame);

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

                    // Send a frame on the now-closed stream.
                    DataFrame invalidFrame = new DataFrame(new byte[10], FrameFlags.None, 0, streamId);
                    await server.WriteFrameAsync(invalidFrame);

                    // The server should close the connection as this is a fatal connection level error.
                    Exception ex = await Assert.ThrowsAsync <Exception>(async() => await server.ReadFrameAsync(TimeSpan.FromSeconds(30)));

                    Assert.Equal("Connection stream closed while attempting to read frame header.", ex.Message);
                }
        }
Пример #20
0
        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());
                }
        }
Пример #21
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));
                    };
                }
        }
Пример #22
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));
                }
        }
Пример #23
0
        public async Task Http2_ClientPreface_Sent()
        {
            HttpClientHandler handler = CreateHttpClientHandler();

            handler.ServerCertificateCustomValidationCallback = TestHelper.AllowAllCertificates;

            using (var server = Http2LoopbackServer.CreateServer())
                using (var client = new HttpClient(handler))
                {
                    Task sendTask = client.GetAsync(server.Address);

                    string connectionPreface = await server.AcceptConnectionAsync();

                    Assert.Equal("PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n", connectionPreface);
                }
        }
        public async Task Http2GetAsyncResponseHeadersReadOption_TrailingHeaders_Available()
        {
            using (var server = Http2LoopbackServer.CreateServer())
                using (var client = new HttpClient(CreateHttpClientHandler(useSocketsHttpHandler: true, useHttp2LoopbackServer: true)))
                {
                    Task <HttpResponseMessage> sendTask = client.GetAsync(server.Address, HttpCompletionOption.ResponseHeadersRead);

                    await server.EstablishConnectionAsync();

                    int streamId = await server.ReadRequestHeaderAsync();

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

                    // Response data, missing Trailers.
                    await server.WriteFrameAsync(MakeDataFrame(streamId, s_dataBytes));

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

                    // Pending read on the response content.
                    Assert.Empty(response.TrailingHeaders);

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

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

                    // Intermediate test - haven't reached stream EOF yet.
                    Assert.Empty(response.TrailingHeaders);

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

                    await server.SendResponseHeadersAsync(streamId, endStream : true, isTrailingHeader : true, headers : s_trailingHeaders);

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

                    Assert.Equal(s_trailingHeaders.Count, response.TrailingHeaders.Count());
                    Assert.Contains("amazingtrailer", response.TrailingHeaders.GetValues("MyCoolTrailerHeader"));
                    Assert.Contains("World", response.TrailingHeaders.GetValues("Hello"));
                }
        }
Пример #25
0
        public async Task ReceiveNoThrowAfterSend_NoSsl(bool useHandler)
        {
            var serverMessage = new byte[] { 4, 5, 6 };
            await Http2LoopbackServer.CreateClientAndServerAsync(async uri =>
            {
                using (var cws = new ClientWebSocket())
                    using (var cts = new CancellationTokenSource(TimeOutMilliseconds))
                    {
                        cws.Options.HttpVersion       = HttpVersion.Version20;
                        cws.Options.HttpVersionPolicy = Http.HttpVersionPolicy.RequestVersionExact;
                        if (useHandler)
                        {
                            var handler = new SocketsHttpHandler();
                            await cws.ConnectAsync(uri, new HttpMessageInvoker(handler), cts.Token);
                        }
                        else
                        {
                            await cws.ConnectAsync(uri, cts.Token);
                        }

                        await cws.SendAsync(new byte[] { 2, 3, 4 }, WebSocketMessageType.Binary, true, cts.Token);

                        var readBuffer = new byte[serverMessage.Length];
                        await cws.ReceiveAsync(readBuffer, cts.Token);
                        Assert.Equal(serverMessage, readBuffer);
                    }
            },
                                                                 async server =>
            {
                Http2LoopbackConnection connection = await server.EstablishConnectionAsync(new SettingsEntry {
                    SettingId = SettingId.EnableConnect, Value = 1
                });
                (int streamId, HttpRequestData requestData) = await connection.ReadAndParseRequestHeaderAsync(readBody: false);
                // send status 200 OK to establish websocket
                await connection.SendResponseHeadersAsync(streamId, endStream: false).ConfigureAwait(false);

                // send reply
                byte binaryMessageType  = 2;
                var prefix              = new byte[] { binaryMessageType, (byte)serverMessage.Length };
                byte[] constructMessage = prefix.Concat(serverMessage).ToArray();
                await connection.SendResponseDataAsync(streamId, constructMessage, endStream: false);
            }, new Http2Options()
            {
                WebSocketEndpoint = true, UseSsl = false
            }
                                                                 );
        }
Пример #26
0
        public async Task Http2_ServerSendsInvalidSettingsValue_ProtocolError(SettingId settingId, uint value)
        {
            HttpClientHandler handler = CreateHttpClientHandler();

            handler.ServerCertificateCustomValidationCallback = TestHelper.AllowAllCertificates;

            using (var server = Http2LoopbackServer.CreateServer())
                using (var client = new HttpClient(handler))
                {
                    Task sendTask = client.GetAsync(server.Address);

                    // Send invalid initial SETTINGS value
                    await server.EstablishConnectionAsync(new SettingsEntry { SettingId = settingId, Value = value });

                    await Assert.ThrowsAsync <HttpRequestException>(async() => await sendTask);
                }
        }
Пример #27
0
        public async Task CompletedResponse_FrameReceived_ResetsStream()
        {
            HttpClientHandler handler = CreateHttpClientHandler();

            handler.ServerCertificateCustomValidationCallback = TestHelper.AllowAllCertificates;

            using (var server = Http2LoopbackServer.CreateServer())
                using (var client = new HttpClient(handler))
                {
                    Task <HttpResponseMessage> sendTask = client.GetAsync(server.Address);

                    await server.EstablishConnectionAsync();

                    server.IgnoreWindowUpdates();
                    int streamId = await server.ReadRequestHeaderAsync();

                    // Send response and end stream.
                    await server.SendDefaultResponseHeadersAsync(streamId);

                    DataFrame dataFrame = new DataFrame(new byte[10], FrameFlags.EndStream, 0, streamId);
                    await server.WriteFrameAsync(dataFrame);

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

                    // Send a frame on the now-closed stream.
                    DataFrame invalidFrame = new DataFrame(new byte[10], FrameFlags.None, 0, streamId);
                    await server.WriteFrameAsync(invalidFrame);

                    // Receive a RST_STREAM frame.
                    Frame receivedFrame = await server.ReadFrameAsync(TimeSpan.FromSeconds(30));

                    Assert.Equal(FrameType.RstStream, receivedFrame.Type);
                    Assert.Equal(streamId, receivedFrame.StreamId);

                    // Connection should still be usable.
                    sendTask = client.GetAsync(server.Address);
                    streamId = await server.ReadRequestHeaderAsync();

                    await server.SendDefaultResponseAsync(streamId);

                    response = await sendTask;
                    Assert.Equal(HttpStatusCode.OK, response.StatusCode);
                }
        }
        public async Task InitialHttp2StreamWindowSize_SentInSettingsFrame()
        {
            const int WindowSize = 123456;

            using Http2LoopbackServer server = Http2LoopbackServer.CreateServer();
            using var handler = CreateHttpClientHandler();
            GetUnderlyingSocketsHttpHandler(handler).InitialHttp2StreamWindowSize = WindowSize;
            using HttpClient client = CreateHttpClient(handler);

            Task <HttpResponseMessage> clientTask = client.GetAsync(server.Address);
            Http2LoopbackConnection    connection = await server.AcceptConnectionAsync().ConfigureAwait(false);

            SettingsFrame clientSettingsFrame = await connection.ReadSettingsAsync().ConfigureAwait(false);

            SettingsEntry entry = clientSettingsFrame.Entries.First(e => e.SettingId == SettingId.InitialWindowSize);

            Assert.Equal(WindowSize, (int)entry.Value);
        }
Пример #29
0
        public async Task Http2_DataSentBeforeServerPreface_ProtocolError()
        {
            HttpClientHandler handler = CreateHttpClientHandler();

            handler.ServerCertificateCustomValidationCallback = TestHelper.AllowAllCertificates;

            using (var server = Http2LoopbackServer.CreateServer())
                using (var client = new HttpClient(handler))
                {
                    Task sendTask = client.GetAsync(server.Address);

                    await server.AcceptConnectionAsync();

                    // Send a frame despite not having sent the server connection preface.
                    DataFrame invalidFrame = new DataFrame(new byte[10], FrameFlags.Padded, 10, 1);
                    await server.WriteFrameAsync(invalidFrame);

                    await Assert.ThrowsAsync <HttpRequestException>(async() => await sendTask);
                }
        }
Пример #30
0
        public async Task ResetResponseStream_FrameReceived_ResetsStream()
        {
            HttpClientHandler handler = CreateHttpClientHandler();

            handler.ServerCertificateCustomValidationCallback = TestHelper.AllowAllCertificates;

            using (var server = Http2LoopbackServer.CreateServer())
                using (var client = new HttpClient(handler))
                {
                    Task <HttpResponseMessage> sendTask = client.GetAsync(server.Address);

                    await server.EstablishConnectionAsync();

                    int streamId = await server.ReadRequestHeaderAsync();

                    // Send a reset stream frame so that stream 1 moves to a terminal state.
                    RstStreamFrame resetStream = new RstStreamFrame(FrameFlags.None, 0x1, streamId);
                    await server.WriteFrameAsync(resetStream);

                    await Assert.ThrowsAsync <HttpRequestException>(async() => await sendTask);

                    // Send a frame on the now-closed stream.
                    DataFrame invalidFrame = new DataFrame(new byte[10], FrameFlags.None, 0, streamId);
                    await server.WriteFrameAsync(invalidFrame);

                    // Receive a RST_STREAM frame.
                    Frame receivedFrame = await server.ReadFrameAsync(TimeSpan.FromSeconds(30));

                    Assert.Equal(FrameType.RstStream, receivedFrame.Type);
                    Assert.Equal(streamId, receivedFrame.StreamId);

                    // Connection should still be usable.
                    sendTask = client.GetAsync(server.Address);
                    streamId = await server.ReadRequestHeaderAsync();

                    await server.SendDefaultResponseAsync(streamId);

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