public void WriteHeadersFrame(HeadersList headers, bool isEndStream, bool isEndHeaders) { if (headers == null) { throw new ArgumentNullException("headers is null"); } if (Closed) { return; } var frame = new HeadersFrame(_id, true) { IsEndHeaders = isEndHeaders, IsEndStream = isEndStream, Headers = headers, }; _writeQueue.WriteFrame(frame); if (frame.IsEndStream) { HalfClosedLocal = true; } else if (ReservedLocal) { HalfClosedRemote = true; } if (OnFrameSent != null) { OnFrameSent(this, new FrameSentEventArgs(frame)); } }
public void WriteHeadersFrame(HeadersList headers, bool isEndStream) { Headers = headers; byte[] headerBytes = _compressionProc.Compress(headers); var frame = new HeadersFrame(_id, headerBytes, Priority) { IsEndHeaders = true, IsEndStream = isEndStream, }; if (frame.IsEndStream) { EndStreamSent = true; } _writeQueue.WriteFrame(frame); if (OnFrameSent != null) { OnFrameSent(this, new FrameSentArgs(frame)); } }
private async Task <int> ReadRequestHeaderAsync(bool expectEndOfStream = true, CancellationToken cancellationToken = default) { HeadersFrame frame = await ReadRequestHeaderFrameAsync(expectEndOfStream, cancellationToken); return(frame.StreamId); }
private void HandleHeaders(HeadersFrame headersFrame, out Http2Stream stream) { Http2Logger.LogDebug("HEADERS frame: stream id={0}, payload len={1}, has pad={2}, pad high={3}, pad low={4}, " + "end stream={5}, has priority={6}, exclusive={7}, dependency={8}, weight={9}", headersFrame.StreamId, headersFrame.PayloadLength, headersFrame.HasPadding, headersFrame.PadHigh, headersFrame.PadLow, headersFrame.IsEndStream, headersFrame.HasPriority, headersFrame.Exclusive, headersFrame.StreamDependency, headersFrame.Weight); /* 12 -> 6.2 * HEADERS frames MUST be associated with a stream. If a HEADERS frame * is received whose stream identifier field is 0x0, the recipient MUST * respond with a connection error of type PROTOCOL_ERROR. */ if (headersFrame.StreamId == 0) { throw new ProtocolError(ResetStatusCode.ProtocolError, "Incoming headers frame with stream id=0"); } var serializedHeaders = new byte[headersFrame.CompressedHeaders.Count]; Buffer.BlockCopy(headersFrame.CompressedHeaders.Array, headersFrame.CompressedHeaders.Offset, serializedHeaders, 0, serializedHeaders.Length); var decompressedHeaders = _comprProc.Decompress(serializedHeaders); var headers = new HeadersList(decompressedHeaders); foreach (var header in headers) { Http2Logger.LogDebug("{1}={2}", headersFrame.StreamId, header.Key, header.Value); } headersFrame.Headers.AddRange(headers); var sequence = _headersSequences.Find(headersFrame.StreamId); if (sequence == null) { sequence = new HeadersSequence(headersFrame.StreamId, headersFrame); _headersSequences.Add(sequence); } else { sequence.AddHeaders(headersFrame); } if (headersFrame.HasPriority) { //TODO: Priority was deprecated, now we need to use Dependency and Weight //sequence.Priority = headersFrame.Priority; } if (!sequence.IsComplete) { stream = null; return; } stream = GetStream(headersFrame.StreamId); if (stream.Idle) { stream = CreateStream(sequence); ValidateHeaders(stream); } else if (stream.ReservedRemote) { stream = CreateStream(sequence); stream.HalfClosedLocal = true; ValidateHeaders(stream); } else if (stream.Opened || stream.HalfClosedLocal) { stream.Headers = sequence.Headers;//Modify by the last accepted frame ValidateHeaders(stream); } else if (stream.HalfClosedRemote) { throw new ProtocolError(ResetStatusCode.ProtocolError, "headers for half closed remote stream"); } else { throw new Http2StreamNotFoundException(headersFrame.StreamId); } }
/// <summary> /// Process a header frame request. /// </summary> /// <param name="httpContext">The current http context.</param> /// <param name="headerFrame">The header frame.</param> /// <param name="stream">The selected stream context.</param> /// <param name="canPassContext">Can the data be sent to the client context.</param> private static void ProcessHeaderFrameRequest(Nequeo.Net.Http2.HttpContext httpContext, HeadersFrame headerFrame, out ContextStream stream, out bool canPassContext) { // The data can be sent to the client // through the http context session. canPassContext = false; /* HEADERS frames MUST be associated with a stream. If a HEADERS frame * is received whose stream identifier field is 0x0, the recipient MUST * respond with a connection error of type PROTOCOL_ERROR. */ if (headerFrame.StreamId == 0) { throw new ProtocolError(ErrorCodeRegistry.Protocol_Error, "Incoming headers frame with stream id is equal to 0."); } // Attempt to get the sepcific stream. stream = httpContext.GetStream(headerFrame.StreamId); if (stream == null) { throw new MaxConcurrentStreamsLimitException(); } // Get the number of compressed headers. var serializedHeaders = new byte[headerFrame.CompressedHeaders.Count]; // Copy the compressed frame. Buffer.BlockCopy(headerFrame.CompressedHeaders.Array, headerFrame.CompressedHeaders.Offset, serializedHeaders, 0, serializedHeaders.Length); // Decompress the compressed headers. HeadersList decompressedHeaders = new HeaderCompression().Decompress(serializedHeaders); HeadersList headers = new HeadersList(decompressedHeaders); // Add the list of headers. foreach (KeyValuePair <string, string> header in headers) { stream.HttpRequest.OriginalHeaders.Add(new NameValue() { Name = header.Key, Value = header.Value }); } // Determine if all headers have been found. if (headerFrame.IsEndHeaders) { // The end of the headers has been found. stream.HttpRequest.HeadersFound = true; } bool wasValidated = false; // Check the current stream state. if (stream.Idle) { // Validate all the headers. httpContext.ValidateHeaders(stream); wasValidated = true; } else if (stream.ReservedRemote) { // Validate all the headers. stream.HalfClosedLocal = true; httpContext.ValidateHeaders(stream); wasValidated = true; } else if (stream.Opened || stream.HalfClosedLocal) { // Validate all the headers. httpContext.ValidateHeaders(stream); wasValidated = true; } else if (stream.HalfClosedRemote) { // Half closed remote stream. throw new ProtocolError(ErrorCodeRegistry.Protocol_Error, "Header for half closed remote stream."); } else { // Stream has no state error. throw new StreamNotFoundException(headerFrame.StreamId); } // If the headers where validated. if (wasValidated) { // If headers have been found. if (stream.HttpRequest.HeadersFound) { // Set the current stream id httpContext.StreamId = stream.StreamId; stream.HttpRequest.IsEndOfData = headerFrame.IsEndStream; // Get the request resources. RequestResource resource = Nequeo.Net.Http2.Utility.GetRequestResource(stream.HttpRequest.OriginalHeaders); // Assign the http request content. stream.HttpRequest.ReadRequestHeaders(stream.HttpRequest.OriginalHeaders, resource); // If this is the last bit of data // that has been sent then sent // the data to the client context. if (headerFrame.IsEndStream) { canPassContext = true; } } } }