public DuplexPipeStreamAdapter(IDuplexPipe duplexPipe, StreamPipeReaderOptions readerOptions, StreamPipeWriterOptions writerOptions, Func <Stream, TStream> createStream) : base(duplexPipe.Input, duplexPipe.Output, throwOnCancelled : true) { Stream = createStream(this); var inputOptions = new PipeOptions(pool: readerOptions.Pool, readerScheduler: PipeScheduler.ThreadPool, writerScheduler: PipeScheduler.Inline, pauseWriterThreshold: 1, resumeWriterThreshold: 1, minimumSegmentSize: readerOptions.Pool.GetMinimumSegmentSize(), useSynchronizationContext: false); var outputOptions = new PipeOptions(pool: writerOptions.Pool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, pauseWriterThreshold: 1, resumeWriterThreshold: 1, minimumSegmentSize: writerOptions.MinimumBufferSize, useSynchronizationContext: false); _minAllocBufferSize = writerOptions.MinimumBufferSize; _input = new Pipe(inputOptions); // We're using a pipe here because the HTTP/2 stack in Kestrel currently makes assumptions // about when it is ok to write to the PipeWriter. This should be reverted back to PipeWriter.Create once // those patterns are fixed. _output = new Pipe(outputOptions); }
protected override async Task ExecuteAsync(CancellationToken cancellationToken) { _logger.LogInformation("Worker started"); _payloadReadyEvent.Wait(cancellationToken); _payloadReadyEvent.Reset(); while (!cancellationToken.IsCancellationRequested) { _logger.LogInformation("Worker running at: {time}", DateTimeOffset.UtcNow); if (!File.Exists(Constants.EXPECTED_ZIP_FILE_NAME)) { // The package hasn't arrived yet _logger.LogDebug("Compressed payload not found {filename}", Constants.EXPECTED_ZIP_FILE_NAME); await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken); continue; } using ZipArchive zipArchive = ZipFile.OpenRead(Constants.EXPECTED_ZIP_FILE_NAME); ZipArchiveEntry dataEntry = zipArchive.Entries.SingleOrDefault(); Stream zipEntryStream = dataEntry.Open(); StreamPipeReaderOptions streamOptions = new StreamPipeReaderOptions(bufferSize: MINIMUM_BUFFER_SIZE); PipeReader pipeReader = PipeReader.Create(zipEntryStream, streamOptions); while (true) { _logger.LogDebug("Reading stream into pipe buffer"); ReadResult result = await pipeReader.ReadAsync(cancellationToken); ReadOnlySequence <byte> buffer = result.Buffer; // Notify the PipeReader how much buffer was used pipeReader.AdvanceTo(buffer.Start, buffer.End); if (!result.IsCompleted) { continue; } _logger.LogDebug("Payload read"); JsonDocument documentFromBuffer = InspectBuffer(buffer); _ = await _payloadChannel.AddPayloadAsync(documentFromBuffer, cancellationToken); break; } await pipeReader.CompleteAsync(); await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken); return; } if (cancellationToken.IsCancellationRequested) { _logger.LogWarning("Operation cancelled"); } }
public async Task CompletingReturnsUnconsumedMemoryToPool() { using (var pool = new DisposeTrackingBufferPool()) { var options = new StreamPipeReaderOptions(pool: pool, bufferSize: 4096, minimumReadSize: 1024); // 2 full segments var stream = new MemoryStream(new byte[options.BufferSize * 3]); PipeReader reader = PipeReader.Create(stream, options); while (true) { ReadResult readResult = await reader.ReadAsync(); reader.AdvanceTo(readResult.Buffer.Start, readResult.Buffer.End); if (readResult.IsCompleted) { break; } } Assert.Equal(4, pool.CurrentlyRentedBlocks); reader.Complete(); Assert.Equal(0, pool.CurrentlyRentedBlocks); Assert.Equal(4, pool.DisposedBlocks); } }
public SslStreamDuplexPipe( IDuplexPipe transport, StreamPipeReaderOptions readerOptions, StreamPipeWriterOptions writerOptions, Func <Stream, SslStream> factory) : base(transport, readerOptions, writerOptions, factory) { }
public async Task CanReadMultipleTimes() { // This needs to run inline to synchronize the reader and writer TaskCompletionSource <object> waitForRead = null; var protocol = new TestProtocol(); async Task DoAsyncRead(PipeReader reader, int[] bufferSizes) { var index = 0; while (true) { var readResult = await reader.ReadAsync().ConfigureAwait(false); if (readResult.IsCompleted) { break; } Assert.Equal(bufferSizes[index], readResult.Buffer.Length); reader.AdvanceTo(readResult.Buffer.End); index++; waitForRead?.TrySetResult(null); } reader.Complete(); } async Task DoAsyncWrites(PipeWriter writer, int[] bufferSizes) { for (var i = 0; i < bufferSizes.Length; i++) { writer.WriteEmpty(protocol, bufferSizes[i]); waitForRead = new TaskCompletionSource <object>(); await writer.FlushAsync().ConfigureAwait(false); await waitForRead.Task; } writer.Complete(); } // We're using the pipe here as a way to pump bytes into the reader asynchronously var pipe = new Pipe(); var options = new StreamPipeReaderOptions(bufferSize: 4096); var reader = new MessagePipeReader(PipeReader.Create(pipe.Reader.AsStream(), options), protocol); var writes = new[] { 4096, 1024, 123, 4096, 100 }; var readingTask = DoAsyncRead(reader, writes); var writingTask = DoAsyncWrites(pipe.Writer, writes); await readingTask; await writingTask; pipe.Reader.Complete(); }
public DuplexPipeStreamAdapter(IDuplexPipe duplexPipe, StreamPipeReaderOptions readerOptions, StreamPipeWriterOptions writerOptions, Func <Stream, TStream> createStream) : base(duplexPipe.Input, duplexPipe.Output) { var stream = createStream(this); Stream = stream; Input = PipeReader.Create(stream, readerOptions); Output = PipeWriter.Create(stream, writerOptions); }
public void StreamPipeReaderOptions_Ctor_Defaults() { var options = new StreamPipeReaderOptions(); Assert.Same(MemoryPool <byte> .Shared, options.Pool); Assert.Equal(4096, options.BufferSize); Assert.Equal(1024, options.MinimumReadSize); Assert.False(options.LeaveOpen); }
public SeatidStream(Stream inputStream, Stream outputStream) { var readerOpts = new StreamPipeReaderOptions(); _reader = PipeReader.Create(inputStream, readerOpts); var writerOptions = new StreamPipeWriterOptions(leaveOpen: true); _writer = PipeWriter.Create(outputStream, writerOptions); _outStream = outputStream; _inStream = inputStream; }
public void StreamPipeReaderOptions_Ctor_Roundtrip() { using (var pool = new TestMemoryPool()) { var options = new StreamPipeReaderOptions(pool: pool, bufferSize: 1234, minimumReadSize: 5678, leaveOpen: true); Assert.Same(pool, options.Pool); Assert.Equal(1234, options.BufferSize); Assert.Equal(5678, options.MinimumReadSize); Assert.True(options.LeaveOpen); } }
public void Setup() { _midLevelParser = new GraphQlResponseParser(); _lowLevelParser = new LowLevelGraphQlResponseParser(); _stream = JsonStreamFactory.CreateGraphQlResponseStream(); _emptyStream = JsonStreamFactory.CreateEmptyGraphQlResponseStream(); // needed for benchmarking to avoid stream closure // passed in as argument since under normal use we won't need to allocate this and can allow the stream to close _streamPipeReaderOptions = new StreamPipeReaderOptions(leaveOpen: true); }
public static StreamPipeReaderOptions ReaderOptionsCreator(MemoryPool <byte> memoryPool) { var inputPipeOptions = new StreamPipeReaderOptions ( pool: memoryPool, bufferSize: memoryPool.MaxBufferSize, minimumReadSize: memoryPool.MaxBufferSize / 2, leaveOpen: true ); return(inputPipeOptions); }
public async Task OnConnectionAsync(ConnectionContext context) { var inputStream = context.Transport.Input.AsStream(); var outputStream = context.Transport.Output.AsStream(); var protocol = new TlsServerProtocol(inputStream, outputStream, new Org.BouncyCastle.Security.SecureRandom()); protocol.Accept(new BlazeTlsServer(_options)); var sslStream = protocol.Stream; var memoryPool = context.Features.Get <IMemoryPoolFeature>()?.MemoryPool; var inputPipeOptions = new StreamPipeReaderOptions ( pool: memoryPool, bufferSize: memoryPool.GetMinimumSegmentSize(), minimumReadSize: memoryPool.GetMinimumAllocSize(), leaveOpen: true ); var outputPipeOptions = new StreamPipeWriterOptions ( pool: memoryPool, leaveOpen: true ); var sslDuplexPipe = new DuplexPipeStreamAdapter <Stream>(context.Transport, inputPipeOptions, outputPipeOptions, sslStream); var originalTransport = context.Transport; try { context.Transport = sslDuplexPipe; // Disposing the stream will dispose the sslDuplexPipe await using (sslStream) await using (sslDuplexPipe) { await _next(context).ConfigureAwait(false); // Dispose the inner stream (SslDuplexPipe) before disposing the SslStream // as the duplex pipe can hit an ODE as it still may be writing. } } finally { context.Transport = originalTransport; } }
public async Task ConsumingSegmentsReturnsMemoryToPool() { using (var pool = new DisposeTrackingBufferPool()) { var options = new StreamPipeReaderOptions(pool: pool, bufferSize: 4096, minimumReadSize: 1024); // 2 full segments var stream = new MemoryStream(new byte[options.BufferSize * 2]); PipeReader reader = PipeReader.Create(stream, options); ReadResult readResult = await reader.ReadAsync(); ReadOnlySequence <byte> buffer = readResult.Buffer; Assert.Equal(1, pool.CurrentlyRentedBlocks); Assert.Equal(options.BufferSize, buffer.Length); reader.AdvanceTo(buffer.Start, buffer.End); readResult = await reader.ReadAsync(); buffer = readResult.Buffer; Assert.Equal(options.BufferSize * 2, buffer.Length); Assert.Equal(2, pool.CurrentlyRentedBlocks); reader.AdvanceTo(buffer.Start, buffer.End); readResult = await reader.ReadAsync(); buffer = readResult.Buffer; Assert.Equal(options.BufferSize * 2, buffer.Length); // We end up allocating a 3rd block here since we don't know ahead of time that // it's the last one Assert.Equal(3, pool.CurrentlyRentedBlocks); reader.AdvanceTo(buffer.Slice(buffer.Start, 4096).End, buffer.End); Assert.Equal(2, pool.CurrentlyRentedBlocks); Assert.Equal(1, pool.DisposedBlocks); readResult = await reader.ReadAsync(); buffer = readResult.Buffer; Assert.Equal(options.BufferSize, buffer.Length); reader.AdvanceTo(buffer.Slice(buffer.Start, 4096).End, buffer.End); // All of the blocks get returned here since we hit the first case of emptying the entire list Assert.Equal(0, pool.CurrentlyRentedBlocks); Assert.Equal(3, pool.DisposedBlocks); reader.Complete(); } }
public DuplexPipeStreamAdapter(IDuplexPipe duplexPipe, StreamPipeReaderOptions readerOptions, StreamPipeWriterOptions writerOptions, Func <Stream, TStream> createStream) : base(duplexPipe.Input, duplexPipe.Output, throwOnCancelled : true) { Stream = createStream(this); var inputOptions = new PipeOptions(pool: readerOptions.Pool, readerScheduler: PipeScheduler.ThreadPool, writerScheduler: PipeScheduler.Inline, pauseWriterThreshold: 1, resumeWriterThreshold: 1, minimumSegmentSize: readerOptions.Pool.GetMinimumSegmentSize(), useSynchronizationContext: false); _minAllocBufferSize = writerOptions.MinimumBufferSize; _input = new Pipe(inputOptions); Output = PipeWriter.Create(Stream, writerOptions); }
private SslDuplexPipe CreateSslDuplexPipe(IDuplexPipe transport, MemoryPool <byte> memoryPool) { var inputPipeOptions = new StreamPipeReaderOptions ( pool: memoryPool, bufferSize: memoryPool.GetMinimumSegmentSize(), minimumReadSize: memoryPool.GetMinimumAllocSize(), leaveOpen: true ); var outputPipeOptions = new StreamPipeWriterOptions ( pool: memoryPool, leaveOpen: true ); return(new SslDuplexPipe(transport, inputPipeOptions, outputPipeOptions, _sslStreamFactory)); }
public async Task ReadWithDifferentSettings(int bytesInBuffer, int bufferSize, int minimumReadSize, int[] readBufferSizes) { var options = new StreamPipeReaderOptions(bufferSize: bufferSize, minimumReadSize: minimumReadSize, pool: new HeapBufferPool()); var stream = new MemoryStream(Enumerable.Range(0, bytesInBuffer).Select(i => (byte)i).ToArray()); PipeReader reader = PipeReader.Create(stream, options); for (int i = 0; i < readBufferSizes.Length; i++) { ReadResult readResult = await reader.ReadAsync(); long length = readResult.Buffer.Length; Assert.Equal(readBufferSizes[i], length); reader.AdvanceTo(readResult.Buffer.End); if (length == 0) { Assert.True(readResult.IsCompleted); } } reader.Complete(); }
public async Task <UserDataModel> ParseResponseJsonAsync(Stream stream, StreamPipeReaderOptions options) { var pipeReader = PipeReader.Create(stream, options); var state = new JsonReaderState(); while (true) { var result = await pipeReader.ReadAsync(); // read from the pipe var buffer = result.Buffer; var(userDataModel, arrayIsEmpty) = ParseJson(buffer, result.IsCompleted, ref state); // read complete items from the current buffer if (result.IsCompleted || userDataModel != null || arrayIsEmpty) { pipeReader.Complete(); // mark the PipeReader as complete return(userDataModel); } pipeReader.AdvanceTo(buffer.Start, buffer.End); // only mark as examined until we have enough buffered data to read what we need } }
public async Task NewSegmentsAllocatedWhenBufferReachesMinimumReadSize() { // We're using the pipe here as a way to pump bytes into the reader asynchronously var pipe = new Pipe(); var options = new StreamPipeReaderOptions(pool: new HeapBufferPool(), bufferSize: 10, minimumReadSize: 5); PipeReader reader = PipeReader.Create(pipe.Reader.AsStream(), options); pipe.Writer.WriteEmpty(6); await pipe.Writer.FlushAsync(); ReadResult readResult = await reader.ReadAsync(); Assert.Equal(6, readResult.Buffer.Length); Assert.True(readResult.Buffer.IsSingleSegment); reader.AdvanceTo(readResult.Buffer.Start, readResult.Buffer.End); pipe.Writer.WriteEmpty(4); await pipe.Writer.FlushAsync(); readResult = await reader.ReadAsync(); Assert.Equal(10, readResult.Buffer.Length); Assert.False(readResult.Buffer.IsSingleSegment); var segments = 0; foreach (ReadOnlyMemory <byte> segment in readResult.Buffer) { segments++; } Assert.Equal(2, segments); reader.AdvanceTo(readResult.Buffer.End); reader.Complete(); pipe.Writer.Complete(); }
private async Task InnerOnConnectionAsync(ConnectionContext context) { bool certificateRequired; var feature = new Core.Internal.TlsConnectionFeature(); context.Features.Set <ITlsConnectionFeature>(feature); context.Features.Set <ITlsHandshakeFeature>(feature); var memoryPool = context.Features.Get <IMemoryPoolFeature>()?.MemoryPool; var inputPipeOptions = new StreamPipeReaderOptions ( pool: memoryPool, bufferSize: memoryPool.GetMinimumSegmentSize(), minimumReadSize: memoryPool.GetMinimumAllocSize(), leaveOpen: true ); var outputPipeOptions = new StreamPipeWriterOptions ( pool: memoryPool, leaveOpen: true ); SslDuplexPipe sslDuplexPipe = null; if (_options.ClientCertificateMode == ClientCertificateMode.NoCertificate) { sslDuplexPipe = new SslDuplexPipe(context.Transport, inputPipeOptions, outputPipeOptions); certificateRequired = false; } else { sslDuplexPipe = new SslDuplexPipe(context.Transport, inputPipeOptions, outputPipeOptions, s => new SslStream(s, leaveInnerStreamOpen: false, userCertificateValidationCallback: (sender, certificate, chain, sslPolicyErrors) => { if (certificate == null) { return(_options.ClientCertificateMode != ClientCertificateMode.RequireCertificate); } if (_options.ClientCertificateValidation == null) { if (sslPolicyErrors != SslPolicyErrors.None) { return(false); } } var certificate2 = ConvertToX509Certificate2(certificate); if (certificate2 == null) { return(false); } if (_options.ClientCertificateValidation != null) { if (!_options.ClientCertificateValidation(certificate2, chain, sslPolicyErrors)) { return(false); } } return(true); })); certificateRequired = true; } var sslStream = sslDuplexPipe.Stream; using (var cancellationTokeSource = new CancellationTokenSource(_options.HandshakeTimeout)) using (cancellationTokeSource.Token.UnsafeRegister(state => ((ConnectionContext)state).Abort(), context)) { try { // Adapt to the SslStream signature ServerCertificateSelectionCallback selector = null; if (_serverCertificateSelector != null) { selector = (sender, name) => { context.Features.Set(sslStream); var cert = _serverCertificateSelector(context, name); if (cert != null) { EnsureCertificateIsAllowedForServerAuth(cert); } return(cert); }; } var sslOptions = new SslServerAuthenticationOptions { ServerCertificate = _serverCertificate, ServerCertificateSelectionCallback = selector, ClientCertificateRequired = certificateRequired, EnabledSslProtocols = _options.SslProtocols, CertificateRevocationCheckMode = _options.CheckCertificateRevocation ? X509RevocationMode.Online : X509RevocationMode.NoCheck, ApplicationProtocols = new List <SslApplicationProtocol>() }; // This is order sensitive if ((_options.HttpProtocols & HttpProtocols.Http2) != 0) { sslOptions.ApplicationProtocols.Add(SslApplicationProtocol.Http2); // https://tools.ietf.org/html/rfc7540#section-9.2.1 sslOptions.AllowRenegotiation = false; } if ((_options.HttpProtocols & HttpProtocols.Http1) != 0) { sslOptions.ApplicationProtocols.Add(SslApplicationProtocol.Http11); } _options.OnAuthenticate?.Invoke(context, sslOptions); await sslStream.AuthenticateAsServerAsync(sslOptions, CancellationToken.None); } catch (OperationCanceledException) { _logger?.LogDebug(2, CoreStrings.AuthenticationTimedOut); await sslStream.DisposeAsync(); return; } catch (Exception ex) when(ex is IOException || ex is AuthenticationException) { _logger?.LogDebug(1, ex, CoreStrings.AuthenticationFailed); await sslStream.DisposeAsync(); return; } } feature.ApplicationProtocol = sslStream.NegotiatedApplicationProtocol.Protocol; context.Features.Set <ITlsApplicationProtocolFeature>(feature); feature.ClientCertificate = ConvertToX509Certificate2(sslStream.RemoteCertificate); feature.CipherAlgorithm = sslStream.CipherAlgorithm; feature.CipherStrength = sslStream.CipherStrength; feature.HashAlgorithm = sslStream.HashAlgorithm; feature.HashStrength = sslStream.HashStrength; feature.KeyExchangeAlgorithm = sslStream.KeyExchangeAlgorithm; feature.KeyExchangeStrength = sslStream.KeyExchangeStrength; feature.Protocol = sslStream.SslProtocol; var originalTransport = context.Transport; try { context.Transport = sslDuplexPipe; // Disposing the stream will dispose the sslDuplexPipe await using (sslStream) await using (sslDuplexPipe) { await _next(context); // Dispose the inner stream (SslDuplexPipe) before disposing the SslStream // as the duplex pipe can hit an ODE as it still may be writing. } } finally { // Restore the original so that it gets closed appropriately context.Transport = originalTransport; } }
public SslDuplexPipe(IDuplexPipe transport, StreamPipeReaderOptions readerOptions, StreamPipeWriterOptions writerOptions) : this(transport, readerOptions, writerOptions, s => new SslStream(s)) { }
private async Task InnerOnConnectionAsync(ConnectionContext context) { var feature = new TlsConnectionFeature(); context.Features.Set<ITlsConnectionFeature>(feature); context.Features.Set<ITlsHandshakeFeature>(feature); var memoryPool = context.Features.Get<IMemoryPoolFeature>()?.MemoryPool; var inputPipeOptions = new StreamPipeReaderOptions ( pool: memoryPool, bufferSize: memoryPool.GetMinimumSegmentSize(), minimumReadSize: memoryPool.GetMinimumAllocSize(), leaveOpen: true ); var outputPipeOptions = new StreamPipeWriterOptions ( pool: memoryPool, leaveOpen: true ); TlsDuplexPipe tlsDuplexPipe = null; if (_options.RemoteCertificateMode == RemoteCertificateMode.NoCertificate) { tlsDuplexPipe = new TlsDuplexPipe(context.Transport, inputPipeOptions, outputPipeOptions); } else { tlsDuplexPipe = new TlsDuplexPipe(context.Transport, inputPipeOptions, outputPipeOptions, s => new SslStream( s, leaveInnerStreamOpen: false, userCertificateValidationCallback: (sender, certificate, chain, sslPolicyErrors) => { if (certificate == null) { return _options.RemoteCertificateMode != RemoteCertificateMode.RequireCertificate; } if (_options.RemoteCertificateValidation == null) { if (sslPolicyErrors != SslPolicyErrors.None) { return false; } } var certificate2 = ConvertToX509Certificate2(certificate); if (certificate2 == null) { return false; } if (_options.RemoteCertificateValidation != null) { if (!_options.RemoteCertificateValidation(certificate2, chain, sslPolicyErrors)) { return false; } } return true; })); } var sslStream = tlsDuplexPipe.Stream; using (var cancellationTokeSource = new CancellationTokenSource(_options.HandshakeTimeout)) using (cancellationTokeSource.Token.UnsafeRegisterCancellation(state => ((ConnectionContext)state).Abort(), context)) { try { var sslOptions = new TlsClientAuthenticationOptions { ClientCertificates = new X509CertificateCollection(new[] { _certificate }), EnabledSslProtocols = _options.SslProtocols, }; _options.OnAuthenticateAsClient?.Invoke(context, sslOptions); #if NETCOREAPP await sslStream.AuthenticateAsClientAsync(sslOptions.Value, cancellationTokeSource.Token); #else await sslStream.AuthenticateAsClientAsync( sslOptions.TargetHost, sslOptions.ClientCertificates, sslOptions.EnabledSslProtocols, sslOptions.CertificateRevocationCheckMode == X509RevocationMode.Online); #endif } catch (OperationCanceledException) { _logger?.LogDebug(2, "Authentication timed out"); #if NETCOREAPP await sslStream.DisposeAsync(); #else sslStream.Dispose(); #endif return; } catch (Exception ex) when (ex is IOException || ex is AuthenticationException) { _logger?.LogDebug(1, ex, "Authentication failed"); #if NETCOREAPP await sslStream.DisposeAsync(); #else sslStream.Dispose(); #endif return; } } #if NETCOREAPP feature.ApplicationProtocol = sslStream.NegotiatedApplicationProtocol.Protocol; #endif context.Features.Set<ITlsApplicationProtocolFeature>(feature); feature.LocalCertificate = ConvertToX509Certificate2(sslStream.LocalCertificate); feature.RemoteCertificate = ConvertToX509Certificate2(sslStream.RemoteCertificate); feature.CipherAlgorithm = sslStream.CipherAlgorithm; feature.CipherStrength = sslStream.CipherStrength; feature.HashAlgorithm = sslStream.HashAlgorithm; feature.HashStrength = sslStream.HashStrength; feature.KeyExchangeAlgorithm = sslStream.KeyExchangeAlgorithm; feature.KeyExchangeStrength = sslStream.KeyExchangeStrength; feature.Protocol = sslStream.SslProtocol; var originalTransport = context.Transport; try { context.Transport = tlsDuplexPipe; // Disposing the stream will dispose the tlsDuplexPipe #if NETCOREAPP await using (sslStream) await using (tlsDuplexPipe) #else using (sslStream) using (tlsDuplexPipe) #endif { await _next(context); // Dispose the inner stream (tlsDuplexPipe) before disposing the SslStream // as the duplex pipe can hit an ODE as it still may be writing. } } finally { // Restore the original so that it gets closed appropriately context.Transport = originalTransport; } }
public PipeAdapter(Stream stream, StreamPipeReaderOptions readerOptions, StreamPipeWriterOptions writerOptions) { _stream = stream; _reader = PipeReader.Create(_stream, readerOptions); _writer = PipeWriter.Create(_stream, writerOptions); }
public DuplexPipeStreamAdapter(IDuplexPipe duplexPipe, StreamPipeReaderOptions readerOptions, StreamPipeWriterOptions writerOptions, TStream stream) { Stream = stream; Input = PipeReader.Create(stream, readerOptions); Output = PipeWriter.Create(stream, writerOptions); }
/// <summary> /// Parses an <see cref="IBObject"/> of type <typeparamref name="T"/> from the <see cref="Stream"/> asynchronously using a <see cref="PipeReader"/>. /// </summary> /// <typeparam name="T">The type of <see cref="IBObject"/> to parse as.</typeparam> public static ValueTask <T> ParseAsync <T>(this IBencodeParser parser, Stream stream, StreamPipeReaderOptions readerOptions = null, CancellationToken cancellationToken = default) where T : class, IBObject { var reader = PipeReader.Create(stream, readerOptions); return(parser.ParseAsync <T>(reader, cancellationToken)); }
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; } }
private async Task RunAsync() { try { var address = BindingAddress.Parse(Options.Url); if (!IPAddress.TryParse(address.Host, out var ip)) { ip = Dns.GetHostEntry(address.Host).AddressList.First(); } var endpoint = new IPEndPoint(ip, address.Port); _logger.LogInformation($"Connecting to '{endpoint}'."); await using var context = await _connectionFactory.ConnectAsync(endpoint); _logger.LogInformation($"Connected to '{endpoint}'."); var originalTransport = context.Transport; IAsyncDisposable sslState = null; if (address.Scheme.Equals("https", StringComparison.OrdinalIgnoreCase)) { _logger.LogInformation("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); var sslDuplexPipe = new SslDuplexPipe(context.Transport, inputPipeOptions, outputPipeOptions); var sslStream = sslDuplexPipe.Stream; sslState = sslDuplexPipe; context.Transport = sslDuplexPipe; await sslStream.AuthenticateAsClientAsync(new SslClientAuthenticationOptions { TargetHost = address.Host, RemoteCertificateValidationCallback = (_, __, ___, ____) => true, ApplicationProtocols = new List <SslApplicationProtocol> { SslApplicationProtocol.Http2 }, EnabledSslProtocols = SslProtocols.Tls12, }, CancellationToken.None); _logger.LogInformation($"TLS handshake completed successfully."); } var http2Utilities = new Http2Utilities(context, _logger, _stopTokenSource.Token); try { await Options.Scenaro(http2Utilities); } catch (Exception ex) { _logger.LogError(ex, "App error"); throw; } finally { // Unwind Https for shutdown. This must happen before the context goes out of scope or else DisposeAsync will never complete context.Transport = originalTransport; if (sslState != null) { await sslState.DisposeAsync(); } } } finally { HostApplicationLifetime.StopApplication(); } }