Пример #1
0
        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));
            }
        }
Пример #2
0
        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);
        }
Пример #4
0
        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);
            }
        }
Пример #5
0
        /// <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;
                    }
                }
            }
        }