public async static Task DrainAsync(this IReadableByteStream stream) { var buf = Buffers.Pool.Rent(8 * 1024); var bytesRead = 0; try { while (true) { var res = await stream.ReadAsync(new ArraySegment <byte>(buf)); if (res.BytesRead != 0) { bytesRead += res.BytesRead; } if (res.EndOfStream) { return; } } } finally { Buffers.Pool.Return(buf); } }
async Task ValidateSettingReception( IReadableByteStream stream, Settings expectedSettings) { var header = await stream.ReadFrameHeaderWithTimeout(); Assert.Equal(FrameType.Settings, header.Type); Assert.Equal(0, header.Flags); Assert.Equal(0u, header.StreamId); Assert.Equal(expectedSettings.RequiredSize, header.Length); var setBuf = new byte[expectedSettings.RequiredSize]; await stream.ReadAllWithTimeout(new ArraySegment <byte>(setBuf)); var settings = new Settings { EnablePush = false, HeaderTableSize = 55, InitialWindowSize = 55, MaxConcurrentStreams = 55, MaxFrameSize = 55, MaxHeaderListSize = 55, }; var err = settings.UpdateFromData(new ArraySegment <byte>(setBuf)); Assert.Null(err); Assert.Equal(expectedSettings, settings); }
public async static Task CopyToAsync( this IReadableByteStream stream, IWriteableByteStream dest) { var buf = Buffers.Pool.Rent(64 * 1024); var bytesRead = 0; try { while (true) { var res = await stream.ReadAsync(new ArraySegment <byte>(buf)); if (res.BytesRead != 0) { await dest.WriteAsync(new ArraySegment <byte>(buf, 0, res.BytesRead)); bytesRead += res.BytesRead; } if (res.EndOfStream) { return; } } } finally { Buffers.Pool.Return(buf); } }
/// <summary> /// Reads the preface from the given stream and compares it to /// the expected value. /// Will throw an error if the preface could not be read or if the stream /// has finished unexpectedly. /// </summary> public static async ValueTask <DoneHandle> ReadAsync( IReadableByteStream stream, int timeoutMillis) { if (timeoutMillis < 0) { throw new ArgumentException(nameof(timeoutMillis)); } else if (timeoutMillis == 0) { // No timeout return(await ReadAsync(stream)); } var cts = new CancellationTokenSource(); var readTask = ReadAsync(stream).AsTask(); var timerTask = Task.Delay(timeoutMillis, cts.Token); var finishedTask = await Task.WhenAny(readTask, timerTask); var hasTimeout = ReferenceEquals(timerTask, finishedTask); // Cancel the timer which might be still running cts.Cancel(); cts.Dispose(); if (hasTimeout) { throw new TimeoutException(); } // No timeout occured return(readTask.Result); }
/// <summary> /// Reads a frame header from the given stream /// </summary> public static async ValueTask <FrameHeader> ReceiveAsync( IReadableByteStream stream, byte[] headerSpace) { await stream.ReadAll(new ArraySegment <byte>(headerSpace, 0, HeaderSize)); return(DecodeFrom(new ArraySegment <byte>(headerSpace, 0, HeaderSize))); }
private Connection BuildConnection( bool isServer, IReadableByteStream inputStream, IWriteAndCloseableByteStream outputStream) { ILogger logger = null; if (loggerProvider != null) { logger = loggerProvider.CreateLogger("http2Con"); } // Decrease the timeout for the preface, // as this speeds the test up var config = new ConnectionConfigurationBuilder(isServer) .UseStreamListener((s) => false) .UseClientPrefaceTimeout(200) .Build(); return(new Connection( config, inputStream, outputStream, new Connection.Options { Logger = logger, })); }
/// <summary> /// Tries to read exactly the given amount of data from a stream. /// The method will only return if all data was read, the stream /// closed or the an error happened. /// If the input is a 0 byte buffer the method will always succeed, /// even if the underlying stream was already closed. /// </summary> /// <param name="stream">The stream to read data from</param> /// <param name="buffer">The destination buffer</param> /// <returns>Awaitable task object</returns> public async static ValueTask <DoneHandle> ReadAll( this IReadableByteStream stream, ArraySegment <byte> buffer) { var array = buffer.Array; var offset = buffer.Offset; var count = buffer.Count; // Remark: This will not perform actual 0 byte reads to the underlying // stream, which means it won't detect closed streams on 0 byte reads. while (count != 0) { var segment = new ArraySegment <byte>(array, offset, count); var res = await stream.ReadAsync(segment); if (res.EndOfStream) { throw new System.IO.EndOfStreamException(); } offset += res.BytesRead; count -= res.BytesRead; } return(DoneHandle.Instance); }
public static async Task AssertSettingsAck( this IReadableByteStream stream) { var header = await stream.ReadFrameHeaderWithTimeout(); Assert.Equal(FrameType.Settings, header.Type); Assert.Equal(0, header.Length); Assert.Equal((byte)SettingsFrameFlags.Ack, header.Flags); Assert.Equal(0u, header.StreamId); }
public static async Task ReadAndDiscardSettings( this IReadableByteStream stream) { var header = await stream.ReadFrameHeaderWithTimeout(); Assert.Equal(FrameType.Settings, header.Type); Assert.InRange(header.Length, 0, 256); await stream.ReadAllWithTimeout( new ArraySegment <byte>(new byte[header.Length])); }
public HeaderReader( HPack.Decoder hpackDecoder, uint maxFrameSize, uint maxHeaderFieldsSize, IReadableByteStream reader ) { this.reader = reader; this.hpackDecoder = hpackDecoder; this.maxFrameSize = maxFrameSize; this.maxHeaderFieldsSize = maxHeaderFieldsSize; }
public static async Task ReadAndDiscardPong( this IReadableByteStream stream) { var header = await stream.ReadFrameHeaderWithTimeout(); Assert.Equal(FrameType.Ping, header.Type); Assert.Equal(8, header.Length); Assert.Equal((byte)PingFrameFlags.Ack, header.Flags); Assert.Equal(0u, header.StreamId); await stream.ReadAllWithTimeout( new ArraySegment <byte>(new byte[8])); }
public HeaderReader( Decoder hpackDecoder, uint maxFrameSize, uint maxHeaderFieldsSize, IReadableByteStream reader, ILogger logger ) { this.reader = reader; this.hpackDecoder = hpackDecoder; this.maxFrameSize = maxFrameSize; this.maxHeaderFieldsSize = maxHeaderFieldsSize; this.logger = logger; }
public static async Task <StreamReadResult> ReadWithTimeout( this IReadableByteStream stream, ArraySegment <byte> buf) { var readTask = stream.ReadAsync(buf).AsTask(); var timeoutTask = Task.Delay(ReadTimeout); var combined = Task.WhenAny(new Task[] { readTask, timeoutTask }); var done = await combined; if (done == readTask) { return(readTask.Result); } throw new TimeoutException(); }
public static async Task <byte[]> ReadAllToArrayWithTimeout( this IReadableByteStream stream) { var readTask = stream.ReadAllToArray(); var timeoutTask = Task.Delay(ReadTimeout); var combined = Task.WhenAny(new Task[] { readTask, timeoutTask }); var done = await combined; if (done == readTask) { return(readTask.Result); } throw new TimeoutException(); }
public static async Task ReadAndDiscardHeaders( this IReadableByteStream stream, uint expectedStreamId, bool expectEndOfStream) { var header = await stream.ReadFrameHeaderWithTimeout(); Assert.Equal(FrameType.Headers, header.Type); Assert.Equal(expectedStreamId, header.StreamId); var isEndOfStream = (header.Flags & (byte)HeadersFrameFlags.EndOfStream) != 0; Assert.Equal(expectEndOfStream, isEndOfStream); var hbuf = new ArraySegment <byte>(new byte[header.Length]); await stream.ReadAllWithTimeout(hbuf); }
public static async Task <FrameHeader> ReadFrameHeaderWithTimeout( this IReadableByteStream stream) { var headerSpace = new byte[FrameHeader.HeaderSize]; var readTask = FrameHeader.ReceiveAsync(stream, headerSpace).AsTask(); var timeoutTask = Task.Delay(5000); var combined = Task.WhenAny(new Task[] { readTask, timeoutTask }); var done = await combined; if (done == readTask) { return(readTask.Result); } throw new TimeoutException(); }
public static async Task AssertStreamEnd( this IReadableByteStream stream) { var headerBytes = new byte[FrameHeader.HeaderSize]; var res = await ReadWithTimeout(stream, new ArraySegment <byte>(headerBytes)); if (!res.EndOfStream) { var hdr = FrameHeader.DecodeFrom( new ArraySegment <byte>(headerBytes)); var msg = "Expected end of stream, but got " + FramePrinter.PrintFrameHeader(hdr); Assert.True(res.EndOfStream, msg); } Assert.Equal(0, res.BytesRead); }
/// <summary> /// Reads the preface from the given stream and compares it to /// the expected value. /// Will throw an error if the preface could not be read or if the stream /// has finished unexpectedly. /// </summary> public static async ValueTask <DoneHandle> ReadAsync(IReadableByteStream stream) { var buffer = new byte[Length]; await stream.ReadAll(new ArraySegment <byte>(buffer)); // Compare with the expected preface for (var i = 0; i < buffer.Length; i++) { if (buffer[i] != Bytes[i]) { throw new Exception("Invalid prefix received"); } } return(DoneHandle.Instance); }
/// <summary> /// 从给定流读取序言并将其与预期值进行比较。 /// </summary> public static async ValueTask <DoneHandle> ReadAsync(IReadableByteStream stream) { var buffer = new byte[Length]; await stream.ReadAll(new ArraySegment <byte>(buffer)); for (var i = 0; i < buffer.Length; i++) { if (buffer[i] != Bytes[i]) { throw new Exception("接收到无效前缀"); } } return(DoneHandle.Instance); }
public static async Task AssertReadTimeout( this IReadableByteStream stream) { var buf = new byte[1]; try { await stream.ReadAllWithTimeout( new ArraySegment <byte>(buf)); } catch (Exception e) { Assert.IsType <TimeoutException>(e); return; } Assert.False(true, "Expected no more data but received a byte"); }
public static async Task AssertWindowUpdate( this IReadableByteStream stream, uint expectedStreamId, int increment) { var header = await stream.ReadFrameHeaderWithTimeout(); Assert.Equal(FrameType.WindowUpdate, header.Type); Assert.Equal(WindowUpdateData.Size, header.Length); Assert.Equal(0, header.Flags); Assert.Equal(expectedStreamId, header.StreamId); var buf = new byte[WindowUpdateData.Size]; await stream.ReadAllWithTimeout(new ArraySegment <byte>(buf)); var wu = WindowUpdateData.DecodeFrom(new ArraySegment <byte>(buf)); Assert.Equal(increment, wu.WindowSizeIncrement); }
public static async Task AssertResetStreamReception( this IReadableByteStream stream, uint expectedStreamId, ErrorCode expectedErrorCode) { var hdr = await stream.ReadFrameHeaderWithTimeout(); Assert.Equal(FrameType.ResetStream, hdr.Type); Assert.Equal(expectedStreamId, hdr.StreamId); Assert.Equal(0, hdr.Flags); Assert.Equal(ResetFrameData.Size, hdr.Length); var resetBytes = new byte[hdr.Length]; await stream.ReadAllWithTimeout(new ArraySegment <byte>(resetBytes)); var resetData = ResetFrameData.DecodeFrom(new ArraySegment <byte>(resetBytes)); Assert.Equal(expectedErrorCode, resetData.ErrorCode); }
public static async Task AssertGoAwayReception( this IReadableByteStream stream, ErrorCode expectedErrorCode, uint lastStreamId) { var hdr = await stream.ReadFrameHeaderWithTimeout(); Assert.Equal(FrameType.GoAway, hdr.Type); Assert.Equal(0u, hdr.StreamId); Assert.Equal(0, hdr.Flags); Assert.InRange(hdr.Length, 8, 256); var goAwayBytes = new byte[hdr.Length]; await stream.ReadAllWithTimeout(new ArraySegment <byte>(goAwayBytes)); var goAwayData = GoAwayFrameData.DecodeFrom(new ArraySegment <byte>(goAwayBytes)); Assert.Equal(lastStreamId, goAwayData.Reason.LastStreamId); Assert.Equal(expectedErrorCode, goAwayData.Reason.ErrorCode); }
Connection BuildConnection( bool isServer, Settings settings, IReadableByteStream inputStream, IWriteAndCloseableByteStream outputStream) { var config = new ConnectionConfigurationBuilder(isServer) .UseSettings(settings) .UseStreamListener((s) => false) .Build(); return(new Connection( config, inputStream, outputStream, new Connection.Options { Logger = loggerProvider.CreateLogger("http2Con"), })); }
public static async Task ReadAndDiscardData( this IReadableByteStream stream, uint expectedStreamId, bool expectEndOfStream, int?expectedAmount) { var header = await stream.ReadFrameHeaderWithTimeout(); Assert.Equal(FrameType.Data, header.Type); Assert.Equal(expectedStreamId, header.StreamId); var isEndOfStream = (header.Flags & (byte)DataFrameFlags.EndOfStream) != 0; Assert.Equal(expectEndOfStream, isEndOfStream); if (expectedAmount.HasValue) { Assert.Equal(expectedAmount.Value, header.Length); } var dataBuf = new ArraySegment <byte>(new byte[header.Length]); await stream.ReadAllWithTimeout(dataBuf); }
public static async Task <byte[]> ReadAllToArray( this IReadableByteStream stream) { var totalBuf = new MemoryStream(); var buf = new byte[16 * 1024]; while (true) { var res = await stream.ReadAsync(new ArraySegment <byte>(buf)); if (res.BytesRead > 0) { totalBuf.Write(buf, 0, res.BytesRead); } if (res.EndOfStream) { return(totalBuf.ToArray()); } } }
static async Task <byte[]> ReadAllToArray( this IReadableByteStream stream) { var readBuffer = Buffers.Pool.Rent(ReadBufferSize); using (var memoryStream = new MemoryStream()) { while (true) { var streamReadResult = await stream.ReadAsync(new ArraySegment <byte>(readBuffer)); if (streamReadResult.BytesRead > 0) { memoryStream.Write(readBuffer, 0, streamReadResult.BytesRead); } if (streamReadResult.EndOfStream) { return(memoryStream.ToArray()); } } } }
public async static ValueTask <DoneHandle> ReadAll( this IReadableByteStream stream, ArraySegment <byte> buffer) { var array = buffer.Array; var offset = buffer.Offset; var count = buffer.Count; while (count != 0) { var segment = new ArraySegment <byte>(array, offset, count); var res = await stream.ReadAsync(segment); if (res.EndOfStream) { throw new System.IO.EndOfStreamException(); } offset += res.BytesRead; count -= res.BytesRead; } return(DoneHandle.Instance); }
public HttpStream(IReadableByteStream stream) { _stream = stream; }
/// <summary> /// 在双向流的顶部创建新的HTTP/2连接 /// </summary> /// <param name="config"></param> /// <param name="inputStream"></param> /// <param name="outputStream"></param> /// <param name="options"></param> public Connection(ConnectionConfiguration config, IReadableByteStream inputStream, IWriteAndCloseableByteStream outputStream, Options?options = null) { if (config == null) { throw new ArgumentNullException(nameof(config)); } this.config = config; if (!config.IsServer) { clientState = new ClientState(); } localSettings = config.Settings; localSettings.EnablePush = false; if (IsServer && options?.ServerUpgradeRequest != null) { serverUpgradeRequest = options.Value.ServerUpgradeRequest; if (!serverUpgradeRequest.IsValid) { throw new ArgumentException( "ServerUpgradeRequest无效.\n" + "无效的HTTP/1升级请求必须被拒绝"); } else { remoteSettings = serverUpgradeRequest.Settings; } } if (inputStream == null) { throw new ArgumentNullException(nameof(inputStream)); } if (outputStream == null) { throw new ArgumentNullException(nameof(outputStream)); } this.inputStream = inputStream; shared.Mutex = new object(); shared.streamMap = new Dictionary <uint, StreamImpl>(); shared.LastOutgoingStreamId = 0u; shared.LastIncomingStreamId = 0u; shared.GoAwaySent = false; shared.Closed = false; shared.PingState = null; if (!IsServer && options?.ClientUpgradeRequest != null) { var upgrade = options.Value.ClientUpgradeRequest; if (!upgrade.IsValid) { throw new ArgumentException( "ClientUpgradeRequest无效。\n" + "无效的升级请求必须被HTTP/1处理程序拒绝"); } localSettings = upgrade.Settings; var newStream = new StreamImpl( this, 1u, StreamState.HalfClosedLocal, (int)localSettings.InitialWindowSize); shared.streamMap[1u] = newStream; shared.LastOutgoingStreamId = 1u; var setStream = upgrade.UpgradeRequestStreamTcs.TrySetResult(newStream); } var dynTableSizeLimit = Math.Min(localSettings.HeaderTableSize, int.MaxValue); writer = new ConnectionWriter( this, outputStream, new ConnectionWriter.Options { MaxFrameSize = (int)remoteSettings.MaxFrameSize, MaxHeaderListSize = (int)remoteSettings.MaxHeaderListSize, InitialWindowSize = (int)remoteSettings.InitialWindowSize, DynamicTableSizeLimit = (int)dynTableSizeLimit, }, new HPack.Encoder.Options { DynamicTableSize = (int)remoteSettings.HeaderTableSize, HuffmanStrategy = config.HuffmanStrategy, } ); nrUnackedSettings++; headerReader = new HeaderReader( new HPack.Decoder(new HPack.Decoder.Options { DynamicTableSizeLimit = (int)dynTableSizeLimit, BufferPool = config.BufferPool, }), localSettings.MaxFrameSize, localSettings.MaxHeaderListSize, inputStream ); readerDone = Task.Run(() => this.RunReaderAsync()); }