public async Task<Http2Stream> Get () { await lockStreams.WaitAsync ().ConfigureAwait (false); var stream = new Http2Stream (flowControlManager, GetNextIdentifier ()); streams.Add (stream.StreamIdentifer, stream); lockStreams.Release (); return stream; }
private async Task ProcessHeadersFrame(FrameHeader frameHeader) { Debug.Assert(frameHeader.Type == FrameType.Headers); bool endStream = frameHeader.EndStreamFlag; int streamId = frameHeader.StreamId; Http2Stream http2Stream = GetStream(streamId); if (http2Stream == null) { _incomingBuffer.Discard(frameHeader.Length); throw new Http2ProtocolException(Http2ProtocolErrorCode.StreamClosed); } // TODO: Figure out how to cache this delegate. // Probably want to pass a state object to Decode. HPackDecoder.HeaderCallback headerCallback = http2Stream.OnResponseHeader; _hpackDecoder.Decode(GetFrameData(_incomingBuffer.ActiveSpan.Slice(0, frameHeader.Length), frameHeader.PaddedFlag, frameHeader.PriorityFlag), headerCallback); _incomingBuffer.Discard(frameHeader.Length); while (!frameHeader.EndHeadersFlag) { frameHeader = await ReadFrameAsync().ConfigureAwait(false); if (frameHeader.Type != FrameType.Continuation || frameHeader.StreamId != streamId) { throw new Http2ProtocolException(Http2ProtocolErrorCode.ProtocolError); } _hpackDecoder.Decode(_incomingBuffer.ActiveSpan.Slice(0, frameHeader.Length), headerCallback); _incomingBuffer.Discard(frameHeader.Length); } _hpackDecoder.CompleteDecode(); http2Stream.OnResponseHeadersComplete(endStream); if (endStream) { RemoveStream(http2Stream); } }
public override ValueTask WriteAsync(ReadOnlyMemory <byte> buffer, CancellationToken cancellationToken) { Http2Stream http2Stream = _http2Stream; if (http2Stream == null || !http2Stream._shouldSendRequestBody) { return(new ValueTask(Task.FromException(new ObjectDisposedException(nameof(Http2WriteStream))))); } // TODO: until #9071 is fixed if (http2Stream._abortException is OperationCanceledException oce) { throw new OperationCanceledException(oce.Message, oce, oce.CancellationToken); } return(new ValueTask(http2Stream.SendDataAsync(buffer, cancellationToken))); }
public async Task<Http2Stream> Get (uint streamIdentifier) { await lockStreams.WaitAsync ().ConfigureAwait (false); Http2Stream stream = null; if (!streams.ContainsKey (streamIdentifier)) { stream = new Http2Stream (flowControlManager, streamIdentifier); streams.Add (streamIdentifier, stream); } else { stream = streams [streamIdentifier]; } lockStreams.Release (); return stream; }
private void AjdustWindowStatic(int bytesConsumed, Http2Stream stream) { _deliveredBytes += bytesConsumed; if (_deliveredBytes < StreamWindowThreshold) { return; } int windowUpdateIncrement = _deliveredBytes; _deliveredBytes = 0; Http2Connection connection = stream.Connection; Task sendWindowUpdateTask = connection.SendWindowUpdateAsync(stream.StreamId, windowUpdateIncrement); connection.LogExceptions(sendWindowUpdateTask); }
public void Http2StreamFeatureCollectionDoesNotIncludeMinRateFeatures() { var http2Stream = new Http2Stream(new Http2StreamContext { ServiceContext = new TestServiceContext(), ConnectionFeatures = new FeatureCollection(), TimeoutControl = Mock.Of <ITimeoutControl>(), Transport = Mock.Of <IDuplexPipe>(), ServerPeerSettings = new Http2PeerSettings(), ClientPeerSettings = new Http2PeerSettings(), }); var http2StreamCollection = (IFeatureCollection)http2Stream; Assert.Null(http2StreamCollection.Get <IHttpMinRequestBodyDataRateFeature>()); Assert.Null(http2StreamCollection.Get <IHttpMinResponseDataRateFeature>()); Assert.NotNull(_collection.Get <IHttpMinRequestBodyDataRateFeature>()); Assert.NotNull(_collection.Get <IHttpMinResponseDataRateFeature>()); }
public override Task FlushAsync(CancellationToken cancellationToken) { if (cancellationToken.IsCancellationRequested) { return(Task.FromCanceled(cancellationToken)); } Http2Stream http2Stream = _http2Stream; if (http2Stream == null) { return(Task.CompletedTask); } // In order to flush this stream's previous writes, we need to flush the connection. We // really only need to do any work here if the connection's buffer has any pending writes // from this stream, but we currently lack a good/efficient/safe way of doing that. return(http2Stream._connection.FlushAsync(cancellationToken)); }
public Http2OutputProducer(Http2Stream stream, Http2StreamContext context) { _stream = stream; _frameWriter = context.FrameWriter; _memoryPool = context.MemoryPool; _log = context.ServiceContext.Log; var scheduleInline = context.ServiceContext.Scheduler == PipeScheduler.Inline; _pipe = CreateDataPipe(_memoryPool, scheduleInline); _pipeWriter = new ConcurrentPipeWriter(_pipe.Writer, _memoryPool, _dataWriterLock); _pipeReader = _pipe.Reader; // No need to pass in timeoutControl here, since no minDataRates are passed to the TimingPipeFlusher. // The minimum output data rate is enforced at the connection level by Http2FrameWriter. _flusher = new TimingPipeFlusher(timeoutControl: null, _log); _flusher.Initialize(_pipeWriter); _streamWindow = context.ClientPeerSettings.InitialWindowSize; }
public override ValueTask<int> ReadAsync(Memory<byte> destination, CancellationToken cancellationToken) { Http2Stream http2Stream = _http2Stream; if (http2Stream == null) { return new ValueTask<int>(Task.FromException<int>(new ObjectDisposedException(nameof(Http2ReadStream)))); } if (http2Stream._abortException != null) { return new ValueTask<int>(Task.FromException<int>(new IOException(SR.net_http_client_execution_error, http2Stream._abortException))); } if (cancellationToken.IsCancellationRequested) { return new ValueTask<int>(Task.FromCanceled<int>(cancellationToken)); } return http2Stream.ReadDataAsync(destination, cancellationToken); }
public async Task<Http2Stream> Get(uint streamIdentifier) { await lockStreams.WaitAsync().ConfigureAwait(false); Http2Stream stream = null; if (!streams.ContainsKey(streamIdentifier)) { stream = new Http2Stream(flowControlManager, streamIdentifier); streams.Add(streamIdentifier, stream); } else { stream = streams[streamIdentifier]; } lockStreams.Release(); return stream; }
public Http2OutputProducer(Http2Stream stream, Http2StreamContext context, StreamOutputFlowControl flowControl) { _stream = stream; _frameWriter = context.FrameWriter; _flowControl = flowControl; _memoryPool = context.MemoryPool; _log = context.ServiceContext.Log; _pipe = CreateDataPipe(_memoryPool); _pipeWriter = new ConcurrentPipeWriter(_pipe.Writer, _memoryPool, _dataWriterLock); _pipeReader = _pipe.Reader; // No need to pass in timeoutControl here, since no minDataRates are passed to the TimingPipeFlusher. // The minimum output data rate is enforced at the connection level by Http2FrameWriter. _flusher = new TimingPipeFlusher(timeoutControl: null, _log); _flusher.Initialize(_pipeWriter); _dataWriteProcessingTask = ProcessDataWrites(); }
private Http2Stream GetWithIdentifier(uint streamIdentifier, StreamGetCallback cb) { lockStreams.WaitOne(); Http2Stream stream = null; if (!streams.ContainsKey(streamIdentifier)) { stream = new Http2Stream(flowControlManager, streamIdentifier); streams.Add(streamIdentifier, stream); } else { stream = streams[streamIdentifier]; } lockStreams.Release(); cb?.Invoke(stream); return(stream); }
protected override void Dispose(bool disposing) { Http2Stream http2Stream = Interlocked.Exchange(ref _http2Stream, null); if (http2Stream == null) { return; } if (disposing) { if (http2Stream._state != StreamState.Aborted && http2Stream._state != StreamState.Complete) { // If we abort response stream before endOfStream, let server know. IgnoreExceptions(http2Stream._connection.SendRstStreamAsync(http2Stream._streamId, Http2ProtocolErrorCode.Cancel)); } http2Stream.Dispose(); } base.Dispose(disposing); }
public HttpProtocolFeatureCollectionTests() { var context = new Http2StreamContext { ServiceContext = new TestServiceContext(), ConnectionFeatures = new FeatureCollection(), TimeoutControl = Mock.Of <ITimeoutControl>(), Transport = Mock.Of <IDuplexPipe>(), ServerPeerSettings = new Http2PeerSettings(), ClientPeerSettings = new Http2PeerSettings(), }; _httpConnectionContext = context; _http1Connection = new TestHttp1Connection(context); _http1Connection.Reset(); _collection = _http1Connection; var http2Stream = new Http2Stream(context); http2Stream.Reset(); _http2Collection = http2Stream; }
public void AdjustWindow(int bytesConsumed, Http2Stream stream) { Debug.Assert(_lastWindowUpdate != default); // Make sure Start() has been invoked, otherwise we should not be receiving DATA. Debug.Assert(bytesConsumed > 0); Debug.Assert(_deliveredBytes < StreamWindowThreshold); if (!stream.ExpectResponseData) { // We are not expecting any more data (because we've either completed or aborted). // So no need to send any more WINDOW_UPDATEs. return; } if (WindowScalingEnabled) { AdjustWindowDynamic(bytesConsumed, stream); } else { AjdustWindowStatic(bytesConsumed, stream); } }
private void SendDataTo(Http2Stream stream, byte[] binaryData) { int i = 0; Http2Logger.LogDebug("Transfer begin"); do { bool isLastData = binaryData.Length - i < Constants.MaxDataFrameContentSize; int chunkSize = stream.WindowSize > 0 ? MathEx.Min(binaryData.Length - i, Constants.MaxDataFrameContentSize, stream.WindowSize) : MathEx.Min(binaryData.Length - i, Constants.MaxDataFrameContentSize); var chunk = new byte[chunkSize]; Buffer.BlockCopy(binaryData, i, chunk, 0, chunk.Length); stream.WriteDataFrame(chunk, isLastData); i += chunkSize; } while (binaryData.Length > i); }
private void SaveDataFrame(Http2Stream stream, DataFrame dataFrame) { lock (_writeLock) { string path = stream.Headers.GetValue(":path".ToLower()); try { string pathToSave = AssemblyPath + Root + path; if (!Directory.Exists(Path.GetDirectoryName(pathToSave))) { throw new DirectoryNotFoundException("Access denied"); } _fileHelper.SaveToFile(dataFrame.Data.Array, dataFrame.Data.Offset, dataFrame.Data.Count, pathToSave, stream.ReceivedDataAmount != 0); } catch (Exception ex) { Http2Logger.LogError(ex.Message); stream.WriteDataFrame(new byte[0], true); stream.Dispose(); } stream.ReceivedDataAmount += dataFrame.FrameLength; if (dataFrame.IsEndStream) { if (!stream.EndStreamSent) { //send terminator stream.WriteDataFrame(new byte[0], true); Http2Logger.LogDebug("Terminator was sent"); } _fileHelper.RemoveStream(AssemblyPath + Root + path); } } }
private async Task GetWaiterTask(CancellationToken cancellationToken) { var vt = new ValueTask(this, _waitSource.Version).AsTask(); using (cancellationToken.Register(s => { Http2Stream stream = (Http2Stream)s; bool signalWaiter; lock (stream.SyncObject) { signalWaiter = stream._hasWaiter; stream._hasWaiter = false; } if (signalWaiter) { stream._waitSource.SetException(new OperationCanceledException()); } }, this)) { await vt.ConfigureAwait(false); } CancellationHelper.ThrowIfCancellationRequested(cancellationToken); }
public void ActiveStreamsSuccessful() { var handshakeResult = new Dictionary <string, object>(); var session = new Http2Session(null, ConnectionEnd.Client, true, true, handshakeResult); var testCollection = session.ActiveStreams; var fm = new FlowControlManager(session); testCollection[1] = new Http2Stream(null, 1, null, fm, null); testCollection[2] = new Http2Stream(null, 2, null, fm, null); testCollection[3] = new Http2Stream(null, 3, null, fm, null); testCollection[4] = new Http2Stream(null, 4, null, fm, null); fm.DisableStreamFlowControl(testCollection[2]); fm.DisableStreamFlowControl(testCollection[4]); Assert.Equal(testCollection.NonFlowControlledStreams.Count, 2); Assert.Equal(testCollection.FlowControlledStreams.Count, 2); bool gotException = false; try { testCollection[4] = new Http2Stream(null, 3, null, fm, null); } catch (ArgumentException) { gotException = true; } Assert.Equal(gotException, true); testCollection.Remove(4); Assert.Equal(testCollection.Count, 3); Assert.Equal(testCollection.ContainsKey(4), false); }
private void ProcessWindowUpdateFrame(FrameHeader frameHeader) { Debug.Assert(frameHeader.Type == FrameType.WindowUpdate); if (frameHeader.Length != FrameHeader.WindowUpdateLength) { throw new Http2ProtocolException(Http2ProtocolErrorCode.FrameSizeError); } int amount = BinaryPrimitives.ReadInt32BigEndian(_incomingBuffer.ActiveSpan) & 0x7FFFFFFF; Debug.Assert(amount >= 0); if (amount == 0) { throw new Http2ProtocolException(Http2ProtocolErrorCode.ProtocolError); } _incomingBuffer.Discard(frameHeader.Length); if (frameHeader.StreamId == 0) { _connectionWindow.AdjustCredit(amount); } else { Http2Stream http2Stream = GetStream(frameHeader.StreamId); if (http2Stream == null) { // Don't wait for completion, which could happen asynchronously. Task ignored = SendRstStreamAsync(frameHeader.StreamId, Http2ProtocolErrorCode.StreamClosed); return; } http2Stream.OnWindowUpdate(amount); } }
/// <summary> /// Builds the headers frame. /// </summary> /// <param name="stream">The stream.</param> /// <param name="headers">The headers.</param> /// <param name="final">if set to <c>true</c> than this frame is final for the stream.</param> /// <returns>Headers frame.</returns> public ControlFrame BuildHeadersFrame(Http2Stream stream, ProtocolHeaders headers, bool final) { ControlFrame frame = BuildControlFrame(FrameType.Headers, stream, headers); frame.IsFinal = final; return frame; }
public Http2MessageBody(Http2Stream context) : base(context) { _context = context; ExtendedConnect = _context.IsExtendedConnectRequest; }
/// <summary> /// Initializes a new instance of the <see cref="RSTEventArgs"/> class. /// </summary> /// <param name="stream">The stream.</param> /// <param name="reason">The reason for RST.</param> public RSTEventArgs(Http2Stream stream, StatusCode reason) : base(stream) { this.Reason = reason; }
/// <summary> /// Initializes a new instance of the <see cref="StreamErrorEventArgs"/> class. /// </summary> /// <param name="stream">The stream.</param> /// <param name="exeption">The exeption.</param> public StreamErrorEventArgs(Http2Stream stream, Exception exeption) : base(stream) { this.Exeption = exeption; }
public Http2MessageBody(Http2Stream context) : base(context) { _context = context; }
/// <summary> /// Builds the data frame. /// </summary> /// <param name="stream">The stream.</param> /// <param name="data">The data.</param> /// <returns>Returns DataFrame.</returns> public DataFrame BuildDataFrame(Http2Stream stream, ProtocolData data) { return(this.BuildDataFrame(stream, data, false)); }
/// <summary> /// Disables the stream flow control. /// Flow control cant be enabled once disabled /// </summary> /// <param name="stream">The stream.</param> public void DisableStreamFlowControl(Http2Stream stream) { if (stream == null) throw new ArgumentNullException("stream is null"); _streamDictionary.DisableFlowControl(stream); }
public void NewStreamOpenedHandler(Http2Stream stream) { _flowControlledSession.SessionWindowSize += StreamsInitialWindowSize; }
/// <summary> /// Initializes a new instance of the <see cref="StreamEventArgs"/> class. /// </summary> /// <param name="stream">The stream.</param> public StreamEventArgs(Http2Stream stream) { this.Stream = stream; }
public ResponseStream(Http2Stream stream, Action onFirstWrite) { _stream = stream; _onFirstWrite = onFirstWrite; }
/// <summary> /// Initializes a new instance of the <see cref="StreamDataEventArgs"/> class. /// </summary> /// <param name="stream">The stream.</param> /// <param name="data">The data.</param> /// <param name="isFin">final flag.</param> public StreamDataEventArgs(Http2Stream stream, ProtocolData data, bool isFin) : base(stream) { this.Data = data; this.IsFin = isFin; }
/// <summary> /// Ends the response in case of error. /// </summary> /// <param name="stream">The stream.</param> /// <param name="ex">The caught exception.</param> private void EndResponse(Http2Stream stream, Exception ex) { Http2Logger.LogDebug("Error processing request:\r\n" + ex); // TODO: What if the response has already started? WriteStatus(stream, StatusCode.Code500InternalServerError, true); }
public RequestSentEventArgs(Http2Stream stream) { Stream = stream; }
public FrameReceivedEventArgs(Http2Stream stream, Frame frame) { Stream = stream; Frame = frame; }
/// <summary> /// Overrides request processing logic. /// </summary> /// <param name="stream">The stream.</param> /// <param name="frame">The request header frame.</param> /// <returns></returns> protected override void ProcessRequest(Http2Stream stream, Frame frame) { /* 12 -> 8.1.3.1 * All HTTP/2 requests MUST include exactly one valid value for the * ":method", ":scheme", and ":path" header fields, unless this is a * CONNECT request (Section 8.3). An HTTP request that omits mandatory * header fields is malformed (Section 8.1.3.5). */ if (stream.Headers.GetValue(CommonHeaders.Method) == null || stream.Headers.GetValue(CommonHeaders.Path) == null || stream.Headers.GetValue(CommonHeaders.Scheme) == null) { stream.WriteRst(ResetStatusCode.ProtocolError); stream.Close(ResetStatusCode.ProtocolError); return; } Task.Factory.StartNew(async() => { try { var context = new Http2OwinMessageContext(stream); var contextEnv = context.OwinContext.Environment; PushFunc pushDelegate = null; pushDelegate = async pairs => { var promisedStream = CreateStream(); //assume that we have already received endStream promisedStream.HalfClosedLocal = true; stream.WritePushPromise(pairs, promisedStream.Id); var headers = new HeadersList(pairs); promisedStream.Headers.AddRange(headers); var http2MsgCtx = new Http2OwinMessageContext(promisedStream); var http2PushCtx = http2MsgCtx.OwinContext; http2PushCtx.Set(CommonOwinKeys.ServerPushFunc, pushDelegate); //pass add info from parent to child context. This info can store //reference table for example or something els that should be passed from //client request into child push requests. if (contextEnv.ContainsKey(CommonOwinKeys.AdditionalInfo)) { http2PushCtx.Set(CommonOwinKeys.AdditionalInfo, contextEnv[CommonOwinKeys.AdditionalInfo]); } await _next(http2PushCtx); http2MsgCtx.FinishResponse(); }; context.OwinContext.Set(CommonOwinKeys.ServerPushFunc, pushDelegate); context.OwinContext.Set(CommonOwinKeys.EnableServerPush, _isPushEnabled); await _next(context.OwinContext); context.FinishResponse(); } catch (Exception ex) { EndResponse(stream, ex); } }); }
/// <summary> /// Check if stream is flowcontrolled. /// </summary> /// <param name="stream">The stream to check.</param> /// <returns> /// <c>true</c> if the stream is flow controlled; otherwise, <c>false</c>. /// </returns> public bool IsStreamFlowControlled(Http2Stream stream) { return _streamCollection.IsStreamFlowControlled(stream); }
public override int Read(Span <byte> destination) { Http2Stream http2Stream = _http2Stream ?? throw new ObjectDisposedException(nameof(Http2ReadStream)); return(http2Stream.ReadData(destination)); }
public void StreamClosedHandler(Http2Stream stream) { _flowControlledSession.SessionWindowSize -= stream.WindowSize; }
/// <summary> /// Builds the SYN_REPLY frame. /// </summary> /// <param name="stream">The stream.</param> /// <param name="headers">The headers.</param> /// <returns>SYN_REPLY frame.</returns> public ControlFrame BuildSynReplyFrame(Http2Stream stream, ProtocolHeaders headers) { return BuildControlFrame(FrameType.SynReply, stream, headers); }
/// <summary> /// Builds the SYN_REPLY frame. /// </summary> /// <param name="stream">The stream.</param> /// <param name="headers">The headers.</param> /// <returns>SYN_REPLY frame.</returns> public ControlFrame BuildSynReplyFrame(Http2Stream stream, ProtocolHeaders headers) { var frame = BuildControlFrame(FrameType.SynReply, stream, headers); frame.StreamId = stream.StreamId; frame.Length = sizeof(Int32) + sizeof(Int32); // sizeof(StreamId) + sizeof(numberOfEntries) return frame; }
/// <summary> /// Builds the SYN_STREAM frame. /// </summary> /// <param name="stream">The stream.</param> /// <param name="headers">The headers.</param> /// <param name="final">Indicates that stream is not going to send any more data.</param> /// <returns>SYN_STREAM frame.</returns> public ControlFrame BuildSynStreamFrame(Http2Stream stream, ProtocolHeaders headers, bool final) { ControlFrame frame = BuildControlFrame(FrameType.SynStream, stream, headers); frame.Priority = SYNStreamPriority; frame.IsFinal = final; return frame; }
public void OnStreamCompleted(Http2Stream stream) { }
public WindowUpdateFrame BuildWindowUpdateFrame(Http2Stream stream, Int64 deltaSize) { WindowUpdateFrame frame = new WindowUpdateFrame(stream.StreamId, deltaSize); frame.Flags = 0; frame.Length = 8; return frame; }
public void NewStreamOpenedHandler(Http2Stream stream) { if (stream == null) throw new ArgumentNullException("stream is null"); _flowControlledSession.SessionWindowSize += StreamsInitialWindowSize; }
/// <summary> /// Check if stream is flowcontrolled. /// </summary> /// <param name="stream">The stream to check.</param> /// <returns> /// <c>true</c> if the stream is flow controlled; otherwise, <c>false</c>. /// </returns> public bool IsStreamFlowControlled(Http2Stream stream) { if (stream == null) throw new ArgumentNullException("stream is null"); return _streamDictionary.IsStreamFlowControlled(stream); }
/// <summary> /// Initializes a new instance of the <see cref="HeadersEventArgs"/> class. /// </summary> /// <param name="stream">The stream.</param> /// <param name="headers">The headers.</param> public HeadersEventArgs(Http2Stream stream, ProtocolHeaders headers) : base(stream) { this.Headers = headers; }
/// <summary> /// Builds the data frame. /// </summary> /// <param name="stream">The stream.</param> /// <param name="data">The data.</param> /// <returns>Returns DataFrame.</returns> public DataFrame BuildDataFrame(Http2Stream stream, ProtocolData data) { return this.BuildDataFrame(stream, data, false); }
/// <summary> /// Disables the stream flow control. /// Flow control cant be enabled once disabled /// </summary> /// <param name="stream">The stream.</param> public void DisableStreamFlowControl(Http2Stream stream) { _streamCollection.DisableFlowControl(stream); }
/// <summary> /// Builds the control frame. /// </summary> /// <param name="type">The frame type.</param> /// <param name="stream">The Http2 stream object.</param> /// <param name="headers">The headers.</param> /// <returns>Returns Control frame object.</returns> private static ControlFrame BuildControlFrame(FrameType type, Http2Stream stream, ProtocolHeaders headers) { ControlFrame frame = new ControlFrame(headers); frame.StreamId = stream.StreamId; frame.Type = type; frame.Priority = ControlPriority; return frame; }
public void StreamClosedHandler(Http2Stream stream) { if (stream == null) throw new ArgumentNullException("stream is null"); _flowControlledSession.SessionWindowSize -= stream.WindowSize; }
/// <summary> /// Builds the RST Frame. /// </summary> /// <param name="stream">The stream.</param> /// <param name="reason">The reason for RST.</param> /// <returns>RST frame.</returns> public ControlFrame BuildRSTFrame(Http2Stream stream, StatusCode reason) { ControlFrame frame = new ControlFrame(); frame.StreamId = stream.StreamId; frame.Type = FrameType.RTS; frame.StatusCode = reason; frame.Priority = RSTPriority; return frame; }
/// <summary> /// Builds the data frame. /// </summary> /// <param name="stream">The stream.</param> /// <param name="data">The data.</param> /// <param name="final">if set to <c>true</c> than this frame is final for the stream.</param> /// <returns>returns DataFrame.</returns> public DataFrame BuildDataFrame(Http2Stream stream, ProtocolData data, bool final) { DataFrame frame = BuildDataFrame(stream.StreamId, data); frame.IsFinal = final; return frame; }
public Http2WriteStream(Http2Stream http2Stream) { Debug.Assert(http2Stream != null); _http2Stream = http2Stream; }
public ControlFrame BuildSettingsFrame(Http2Stream stream) { //TODO Add more logic at building settings frame var frame = BuildControlFrame(FrameType.Settings, stream, null); frame.SettingsHeaders = null; frame.Length = 4; frame.NumberOfEntries = 0; return frame; }