Exemplo n.º 1
0
            public async Task RunAsync()
            {
                var endpoint = new IPEndPoint(IPAddress.Loopback, 5001);

                _logger.LogInformation($"Connecting to '{endpoint}'.");

                await using var context = await _connectionFactory.ConnectAsync(endpoint);

                _logger.LogInformation($"Connected to '{endpoint}'. Starting TLS handshake.");

                var memoryPool        = context.Features.Get <IMemoryPoolFeature>()?.MemoryPool;
                var inputPipeOptions  = new StreamPipeReaderOptions(memoryPool, memoryPool.GetMinimumSegmentSize(), memoryPool.GetMinimumAllocSize(), leaveOpen: true);
                var outputPipeOptions = new StreamPipeWriterOptions(pool: memoryPool, leaveOpen: true);

                await using var sslDuplexPipe = new SslDuplexPipe(context.Transport, inputPipeOptions, outputPipeOptions);
                await using var sslStream     = sslDuplexPipe.Stream;

                var originalTransport = context.Transport;

                context.Transport = sslDuplexPipe;

                try
                {
                    await sslStream.AuthenticateAsClientAsync(new SslClientAuthenticationOptions
                    {
                        TargetHost = "localhost",
                        RemoteCertificateValidationCallback = (_, __, ___, ____) => true,
                        ApplicationProtocols = new List <SslApplicationProtocol> {
                            SslApplicationProtocol.Http2
                        },
                        EnabledSslProtocols = SslProtocols.Tls12,
                    }, CancellationToken.None);

                    _logger.LogInformation($"TLS handshake completed successfully.");

                    var http2Utilities = new Http2Utilities(context);

                    await http2Utilities.InitializeConnectionAsync();

                    _logger.LogInformation("Initialized http2 connection. Starting stream 1.");

                    await http2Utilities.StartStreamAsync(1, Http2Utilities._browserRequestHeaders, endStream : true);

                    var headersFrame = await http2Utilities.ReceiveFrameAsync();

                    Trace.Assert(headersFrame.Type == Http2FrameType.HEADERS);
                    Trace.Assert((headersFrame.Flags & (byte)Http2HeadersFrameFlags.END_HEADERS) != 0);
                    Trace.Assert((headersFrame.Flags & (byte)Http2HeadersFrameFlags.END_STREAM) == 0);

                    _logger.LogInformation("Received headers in a single frame.");

                    var decodedHeaders = http2Utilities.DecodeHeaders(headersFrame);

                    foreach (var header in decodedHeaders)
                    {
                        _logger.LogInformation($"{header.Key}: {header.Value}");
                    }

                    var dataFrame = await http2Utilities.ReceiveFrameAsync();

                    Trace.Assert(dataFrame.Type == Http2FrameType.DATA);
                    Trace.Assert((dataFrame.Flags & (byte)Http2DataFrameFlags.END_STREAM) == 0);

                    _logger.LogInformation("Received data in a single frame.");

                    _logger.LogInformation(Encoding.UTF8.GetString(dataFrame.Payload.ToArray()));

                    var trailersFrame = await http2Utilities.ReceiveFrameAsync();

                    Trace.Assert(trailersFrame.Type == Http2FrameType.HEADERS);
                    Trace.Assert((trailersFrame.Flags & (byte)Http2DataFrameFlags.END_STREAM) == 1);

                    _logger.LogInformation("Received trailers in a single frame.");

                    http2Utilities._decodedHeaders.Clear();

                    var decodedTrailers = http2Utilities.DecodeHeaders(trailersFrame);

                    foreach (var header in decodedHeaders)
                    {
                        _logger.LogInformation($"{header.Key}: {header.Value}");
                    }

                    await http2Utilities.StopConnectionAsync(expectedLastStreamId : 1, ignoreNonGoAwayFrames : false);

                    _logger.LogInformation("Connection stopped.");
                }
                finally
                {
                    context.Transport = originalTransport;
                }
            }