public async Task TlsHandshakeRejectsTlsLessThan12() { await using (var server = new TestServer(context => { var tlsFeature = context.Features.Get <ITlsApplicationProtocolFeature>(); Assert.NotNull(tlsFeature); Assert.Equal(tlsFeature.ApplicationProtocol, SslApplicationProtocol.Http2.Protocol); return(context.Response.WriteAsync("hello world " + context.Request.Protocol)); }, new TestServiceContext(LoggerFactory), listenOptions => { listenOptions.Protocols = HttpProtocols.Http2; listenOptions.UseHttps(_x509Certificate2, httpsOptions => { #pragma warning disable SYSLIB0039 // TLS 1.0 and 1.1 are obsolete httpsOptions.SslProtocols = SslProtocols.Tls11 | SslProtocols.Tls12; #pragma warning restore SYSLIB0039 }); })) { using (var connection = server.CreateConnection()) { var sslStream = new SslStream(connection.Stream); await sslStream.AuthenticateAsClientAsync(new SslClientAuthenticationOptions { TargetHost = "localhost", RemoteCertificateValidationCallback = (_, __, ___, ____) => true, ApplicationProtocols = new List <SslApplicationProtocol> { SslApplicationProtocol.Http2, SslApplicationProtocol.Http11 }, #pragma warning disable SYSLIB0039 // TLS 1.0 and 1.1 are obsolete EnabledSslProtocols = SslProtocols.Tls11, // Intentionally less than the required 1.2 #pragma warning restore SYSLIB0039 }, CancellationToken.None); var reader = PipeReaderFactory.CreateFromStream(PipeOptions.Default, sslStream, CancellationToken.None); await WaitForConnectionErrorAsync(reader, ignoreNonGoAwayFrames : false, expectedLastStreamId : 0, expectedErrorCode : Http2ErrorCode.INADEQUATE_SECURITY); reader.Complete(); } } }
private async Task ProcessEventStream(IDuplexPipe application, HttpResponseMessage response, CancellationToken cancellationToken) { Log.StartReceive(_logger); using (response) using (var stream = await response.Content.ReadAsStreamAsync()) { var options = new PipeOptions(pauseWriterThreshold: 0, resumeWriterThreshold: 0); var reader = PipeReaderFactory.CreateFromStream(options, stream, cancellationToken); try { while (true) { var result = await reader.ReadAsync(); var buffer = result.Buffer; var consumed = buffer.Start; var examined = buffer.End; try { if (result.IsCanceled) { Log.ReceiveCanceled(_logger); break; } if (!buffer.IsEmpty) { Log.ParsingSSE(_logger, buffer.Length); var parseResult = _parser.ParseMessage(buffer, out consumed, out examined, out var message); FlushResult flushResult = default; switch (parseResult) { case ServerSentEventsMessageParser.ParseResult.Completed: Log.MessageToApplication(_logger, message.Length); flushResult = await _application.Output.WriteAsync(message); _parser.Reset(); break; case ServerSentEventsMessageParser.ParseResult.Incomplete: if (result.IsCompleted) { throw new FormatException("Incomplete message."); } break; } // We canceled in the middle of applying back pressure // or if the consumer is done if (flushResult.IsCanceled || flushResult.IsCompleted) { Log.EventStreamEnded(_logger); break; } } else if (result.IsCompleted) { break; } } finally { reader.AdvanceTo(consumed, examined); } } } catch (Exception ex) { _error = ex; } finally { _application.Output.Complete(_error); Log.ReceiveStopped(_logger); reader.Complete(); } } }