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 AltSvc_ResponseFrame_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.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 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 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 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")); } }
public Task BadRttPingResponse_RequestShouldFail(int mode) { return(Http2LoopbackServer.CreateClientAndServerAsync(async uri => { using var handler = CreateHttpClientHandler(); using HttpClient client = CreateHttpClient(handler); HttpRequestException exception = await Assert.ThrowsAsync <HttpRequestException>(() => client.GetAsync(uri)); _output.WriteLine(exception.Message + exception.StatusCode); }, async server => { Http2LoopbackConnection connection = await server.EstablishConnectionAsync(); (int streamId, _) = await connection.ReadAndParseRequestHeaderAsync(); await connection.SendDefaultResponseHeadersAsync(streamId); PingFrame pingFrame = await connection.ReadPingAsync(); // expect an RTT PING if (mode == 0) { // Invalid PING payload await connection.SendPingAckAsync(-6666); // send an invalid PING response } else { // Unexpected PING response await connection.SendPingAckAsync(pingFrame.Data); // send an valid PING response await connection.SendPingAckAsync(pingFrame.Data - 1); // send a second unexpected PING response } await connection.SendResponseDataAsync(streamId, new byte[] { 1, 2, 3 }, true); // otherwise fine response }, NoAutoPingResponseHttp2Options)); }
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 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")); } }
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); } }