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 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 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); } }
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 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))); } } }
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 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); } }
public async Task ClosedStream_FrameReceived_ResetsStream() { 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(); await server.ReadRequestHeaderAsync(); // 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. Frame receivedFrame = await server.ReadFrameAsync(TimeSpan.FromSeconds(30)); Assert.Equal(FrameType.RstStream, receivedFrame.Type); await Assert.ThrowsAsync <HttpRequestException>(async() => await sendTask); } }
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 Http2_StreamResetByServer_RequestFails() { 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(); 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); // This currently throws an IOException. await Assert.ThrowsAsync <HttpRequestException>(async() => await sendTask); } }
public async Task Http2GetAsync_MissingTrailer_TrailingHeadersAccepted() { using (var server = Http2LoopbackServer.CreateServer()) using (var 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); // Response data, missing Trailers. await server.WriteFrameAsync(MakeDataFrame(streamId, s_dataBytes)); // Additional trailing header frame. await server.SendResponseHeadersAsync(streamId, isTrailingHeader : true, headers : s_trailingHeaders, endStream : true); HttpResponseMessage response = await sendTask; Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal(s_trailingHeaders.Count, response.TrailingHeaders.Count()); Assert.Contains("amazingtrailer", response.TrailingHeaders.GetValues("MyCoolTrailerHeader")); Assert.Contains("World", response.TrailingHeaders.GetValues("Hello")); } }
public async Task DataFrame_PaddingOnly_ResetsStream() { 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(); 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[0], FrameFlags.Padded, 10, 1); await server.WriteFrameAsync(invalidFrame); await Assert.ThrowsAsync <HttpRequestException>(async() => await sendTask); // Receive a RST_STREAM frame. receivedFrame = await server.ReadFrameAsync(TimeSpan.FromSeconds(30)); Assert.Equal(FrameType.RstStream, receivedFrame.Type); } }
public async Task Http2_InitialSettings_SentAndAcked() { 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(); // Receive the initial client settings frame. Frame receivedFrame = await server.ReadFrameAsync(TimeSpan.FromSeconds(30)); Assert.Equal(FrameType.Settings, receivedFrame.Type); // Send the initial server settings frame. Frame emptySettings = new Frame(0, FrameType.Settings, FrameFlags.None, 0); await server.WriteFrameAsync(emptySettings).ConfigureAwait(false); // Receive the server settings frame ACK. receivedFrame = await server.ReadFrameAsync(TimeSpan.FromSeconds(30)); Assert.Equal(FrameType.Settings, receivedFrame.Type); Assert.True(receivedFrame.AckFlag); } }
public async Task DataFrame_TooLong_ConnectionError() { 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(); 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); } }
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 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")); } }
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); }
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); } }
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 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); } }
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); } }
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 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()); } }
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)); }; } }
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)); } }
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")); } }
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); } }
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); } }