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 async Task UseClientCertOnHttp2_OSSupportsIt_Success() { using X509Certificate2 clientCert = Test.Common.Configuration.Certificates.GetClientCertificate(); await Http2LoopbackServer.CreateClientAndServerAsync( async address => { var handler = new WinHttpHandler(); handler.ServerCertificateValidationCallback = CustomServerCertificateValidationCallback; handler.ClientCertificates.Add(clientCert); handler.ClientCertificateOption = ClientCertificateOption.Manual; using (var client = new HttpClient(handler)) using (HttpResponseMessage response = await client.SendAsync(new HttpRequestMessage(HttpMethod.Get, address) { Version = HttpVersion20.Value })) { Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.True(_validationCallbackHistory.WasCalled); Assert.NotEmpty(_validationCallbackHistory.CertificateChain); Assert.Equal(Test.Common.Configuration.Certificates.GetServerCertificate(), _validationCallbackHistory.CertificateChain[0]); } }, async s => { await using (Http2LoopbackConnection connection = await s.EstablishConnectionAsync().ConfigureAwait(false)) { SslStream sslStream = connection.Stream as SslStream; Assert.NotNull(sslStream); Assert.True(sslStream.IsMutuallyAuthenticated); Assert.Equal(clientCert, sslStream.RemoteCertificate); int streamId = await connection.ReadRequestHeaderAsync(); await connection.SendDefaultResponseAsync(streamId); } }, new Http2Options { ClientCertificateRequired = true }); }
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 HPack_HeaderEncoding(string headerName, string expectedValue, byte[] expectedEncoding) { await Http2LoopbackServer.CreateClientAndServerAsync( async uri => { using HttpClient client = CreateHttpClient(); using HttpRequestMessage request = new HttpRequestMessage(); request.Method = HttpMethod.Post; request.RequestUri = uri; request.Version = HttpVersion.Version20; request.Content = new StringContent("testing 123"); request.Headers.Add(LiteralHeaderName, LiteralHeaderValue); (await client.SendAsync(request)).Dispose(); }, async server => { Http2LoopbackConnection connection = await server.EstablishConnectionAsync(); (int streamId, HttpRequestData requestData) = await connection.ReadAndParseRequestHeaderAsync(); HttpHeaderData header = requestData.Headers.Single(x => x.Name == headerName); Assert.Equal(expectedValue, header.Value); Assert.True(expectedEncoding.AsSpan().SequenceEqual(header.Raw)); await connection.SendDefaultResponseAsync(streamId); }); }
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 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 ConnectAsync_VersionSupported_Success() { 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; using var handler = CreateSocketsHttpHandler(allowAllCertificates: true); await cws.ConnectAsync(uri, new HttpMessageInvoker(handler), cts.Token); } }, async server => { Http2LoopbackConnection connection = await server.EstablishConnectionAsync(new SettingsEntry { SettingId = SettingId.EnableConnect, Value = 1 }); (int streamId, HttpRequestData requestData) = await connection.ReadAndParseRequestHeaderAsync(readBody: false); await connection.SendResponseHeadersAsync(streamId, endStream: false, HttpStatusCode.OK); }, new Http2Options() { WebSocketEndpoint = true } ); }
public async Task ConnectAsync_VersionNotSupported_Throws() { await Http2LoopbackServer.CreateClientAndServerAsync(async uri => { using (var clientSocket = new ClientWebSocket()) using (var cts = new CancellationTokenSource(TimeOutMilliseconds)) { clientSocket.Options.HttpVersion = HttpVersion.Version20; clientSocket.Options.HttpVersionPolicy = Http.HttpVersionPolicy.RequestVersionExact; using var handler = CreateSocketsHttpHandler(allowAllCertificates: true); Task t = clientSocket.ConnectAsync(uri, new HttpMessageInvoker(handler), cts.Token); var ex = await Assert.ThrowsAnyAsync <WebSocketException>(() => t); Assert.IsType <HttpRequestException>(ex.InnerException); Assert.True(ex.InnerException.Data.Contains("SETTINGS_ENABLE_CONNECT_PROTOCOL")); } }, async server => { Http2LoopbackConnection connection = await server.EstablishConnectionAsync(new SettingsEntry { SettingId = SettingId.EnableConnect, Value = 0 }); }, new Http2Options() { WebSocketEndpoint = true } ); }
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_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 Http2GetAsync_NoTrailingHeaders_EmptyCollection() { using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer()) using (HttpClient client = CreateHttpClient()) { Task <HttpResponseMessage> sendTask = client.GetAsync(server.Address); Http2LoopbackConnection connection = await server.EstablishConnectionAsync(); int streamId = await connection.ReadRequestHeaderAsync(); // Response header. await connection.SendDefaultResponseHeadersAsync(streamId); // Response data. await connection.WriteFrameAsync(MakeDataFrame(streamId, DataBytes, endStream : true)); // Server doesn't send trailing header frame. HttpResponseMessage response = await sendTask; Assert.Equal(HttpStatusCode.OK, response.StatusCode); var trailingHeaders = GetTrailingHeaders(response); Assert.NotNull(trailingHeaders); Assert.Equal(0, trailingHeaders.Count()); } }
public async Task Http2GetAsyncResponseHeadersReadOption_TrailingHeaders_Available() { using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer()) using (HttpClient client = CreateHttpClient()) { Task <HttpResponseMessage> sendTask = client.GetAsync(server.Address, HttpCompletionOption.ResponseHeadersRead); Http2LoopbackConnection connection = await server.EstablishConnectionAsync(); int streamId = await connection.ReadRequestHeaderAsync(); // Response header. await connection.SendDefaultResponseHeadersAsync(streamId); // Response data, missing Trailers. await connection.WriteFrameAsync(MakeDataFrame(streamId, DataBytes)); HttpResponseMessage response = await sendTask; Assert.Equal(HttpStatusCode.OK, response.StatusCode); // Pending read on the response content. var trailingHeaders = GetTrailingHeaders(response); Assert.True(trailingHeaders == null || trailingHeaders.Count() == 0); Stream stream = await response.Content.ReadAsStreamAsync(TestAsync); Byte[] data = new Byte[100]; await stream.ReadAsync(data, 0, data.Length); // Intermediate test - haven't reached stream EOF yet. trailingHeaders = GetTrailingHeaders(response); Assert.True(trailingHeaders == null || trailingHeaders.Count() == 0); // Finish data stream and write out trailing headers. await connection.WriteFrameAsync(MakeDataFrame(streamId, DataBytes)); await connection.SendResponseHeadersAsync(streamId, endStream : true, isTrailingHeader : true, headers : TrailingHeaders); // Read data until EOF is reached while (stream.Read(data, 0, data.Length) != 0) { ; } trailingHeaders = GetTrailingHeaders(response); Assert.Equal(TrailingHeaders.Count, trailingHeaders.Count()); Assert.Contains("amazingtrailer", trailingHeaders.GetValues("MyCoolTrailerHeader")); Assert.Contains("World", trailingHeaders.GetValues("Hello")); // Read when already zero. Trailers shouldn't be changed. stream.Read(data, 0, data.Length); trailingHeaders = GetTrailingHeaders(response); Assert.Equal(TrailingHeaders.Count, trailingHeaders.Count()); } }
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 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 } ); }
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); }
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); } }
private async Task EstablishConnectionAsync(Http2LoopbackServer server) { _connection = await server.EstablishConnectionAsync(); _incomingFramesTask = ProcessIncomingFramesAsync(_incomingFramesCts.Token); }