Пример #1
0
        void ReadPushPromiseFrame(IChannelHandlerContext ctx, IByteBuffer payload, int payloadEndIndex, IHttp2FrameListener listener)
        {
            int pushPromiseStreamId = _streamId;
            int padding             = ReadPadding(payload);

            VerifyPadding(padding);
            int promisedStreamId = Http2CodecUtil.ReadUnsignedInt(payload);

            // Create a handler that invokes the listener when the header block is complete.
            _headersContinuation = new PushPromiseFrameHeadersContinuation(this,
                                                                           ctx, pushPromiseStreamId, padding, promisedStreamId);

            // Process the initial fragment, invoking the listener's callback if end of headers.
            int dataLength = LengthWithoutTrailingPadding(payloadEndIndex - payload.ReaderIndex, padding);

            _headersContinuation.ProcessFragment(_flags.EndOfHeaders(), payload, dataLength, listener);
            ResetHeadersContinuationIfEnd(_flags.EndOfHeaders());
        }
Пример #2
0
        void ReadHeadersFrame(IChannelHandlerContext ctx, IByteBuffer payload, int payloadEndIndex, IHttp2FrameListener listener)
        {
            int        headersStreamId = _streamId;
            Http2Flags headersFlags    = _flags;
            int        padding         = ReadPadding(payload);

            VerifyPadding(padding);

            // The callback that is invoked is different depending on whether priority information
            // is present in the headers frame.
            if (headersFlags.PriorityPresent())
            {
                long word1            = payload.ReadUnsignedInt();
                bool exclusive        = (word1 & 0x80000000L) != 0;
                int  streamDependency = (int)(uint)(word1 & 0x7FFFFFFFL);
                if (streamDependency == headersStreamId)
                {
                    ThrowHelper.ThrowStreamError_AStreamCannotDependOnItself(headersStreamId);
                }

                short weight    = (short)(payload.ReadByte() + 1);
                int   lenToRead = LengthWithoutTrailingPadding(payloadEndIndex - payload.ReaderIndex, padding);

                // Create a handler that invokes the listener when the header block is complete.
                _headersContinuation = new PriorityHeadersFrameHeadersContinuation(this,
                                                                                   ctx, headersStreamId, padding, streamDependency, weight, exclusive, headersFlags);

                // Process the initial fragment, invoking the listener's callback if end of headers.
                _headersContinuation.ProcessFragment(headersFlags.EndOfHeaders(), payload, lenToRead, listener);
                ResetHeadersContinuationIfEnd(headersFlags.EndOfHeaders());
                return;
            }

            // The priority fields are not present in the frame. Prepare a continuation that invokes
            // the listener callback without priority information.
            _headersContinuation = new HeadersFrameHeadersContinuation(this,
                                                                       ctx, headersStreamId, padding, headersFlags);

            // Process the initial fragment, invoking the listener's callback if end of headers.
            int dataLength = LengthWithoutTrailingPadding(payloadEndIndex - payload.ReaderIndex, padding);

            _headersContinuation.ProcessFragment(headersFlags.EndOfHeaders(), payload, dataLength, listener);
            ResetHeadersContinuationIfEnd(headersFlags.EndOfHeaders());
        }
Пример #3
0
        /// <summary>
        /// Writes as many continuation frames as needed until <paramref name="headerBlock"/> are consumed.
        /// </summary>
        /// <param name="ctx"></param>
        /// <param name="streamId"></param>
        /// <param name="headerBlock"></param>
        /// <param name="promiseAggregator"></param>
        /// <returns></returns>
        Task WriteContinuationFramesAsync(IChannelHandlerContext ctx, int streamId,
                                          IByteBuffer headerBlock, SimplePromiseAggregator promiseAggregator)
        {
            Http2Flags flags = new Http2Flags();

            if (headerBlock.IsReadable())
            {
                // The frame header (and padding) only changes on the last frame, so allocate it once and re-use
                int         fragmentReadableBytes = Math.Min(headerBlock.ReadableBytes, _maxFrameSize);
                IByteBuffer buf = ctx.Allocator.Buffer(Http2CodecUtil.ContinuationFrameHeaderLength);
                Http2CodecUtil.WriteFrameHeaderInternal(buf, fragmentReadableBytes, Http2FrameTypes.Continuation, flags, streamId);

                do
                {
                    fragmentReadableBytes = Math.Min(headerBlock.ReadableBytes, _maxFrameSize);
                    IByteBuffer fragment = headerBlock.ReadRetainedSlice(fragmentReadableBytes);

                    if (headerBlock.IsReadable())
                    {
                        _ = ctx.WriteAsync(buf.Retain(), promiseAggregator.NewPromise());
                    }
                    else
                    {
                        // The frame header is different for the last frame, so re-allocate and release the old buffer
                        flags = flags.EndOfHeaders(true);
                        _     = buf.Release();
                        buf   = ctx.Allocator.Buffer(Http2CodecUtil.ContinuationFrameHeaderLength);
                        Http2CodecUtil.WriteFrameHeaderInternal(buf, fragmentReadableBytes, Http2FrameTypes.Continuation, flags, streamId);
                        _ = ctx.WriteAsync(buf, promiseAggregator.NewPromise());
                    }

                    _ = ctx.WriteAsync(fragment, promiseAggregator.NewPromise());
                }while (headerBlock.IsReadable());
            }

            return(promiseAggregator.Task);
        }
Пример #4
0
        Task WriteHeadersInternal(IChannelHandlerContext ctx, int streamId,
                                  IHttp2Headers headers, int padding, bool endOfStream, bool hasPriority,
                                  int streamDependency, short weight, bool exclusive, IPromise promise)
        {
            IByteBuffer             headerBlock       = null;
            SimplePromiseAggregator promiseAggregator = new SimplePromiseAggregator(promise);

            try
            {
                if ((uint)(streamId - 1) > SharedConstants.TooBigOrNegative)
                {
                    ThrowHelper.ThrowArgumentException_Positive(ExceptionArgument.StreamID);
                }
                if (hasPriority)
                {
                    if (streamDependency < 0)
                    {
                        ThrowHelper.ThrowArgumentException_PositiveOrZero(ExceptionArgument.StreamDependency);
                    }
                    Http2CodecUtil.VerifyPadding(padding);
                    VerifyWeight(weight);
                }

                // Encode the entire header block.
                headerBlock = ctx.Allocator.Buffer();
                _headersEncoder.EncodeHeaders(streamId, headers, headerBlock);

                Http2Flags flags =
                    new Http2Flags().EndOfStream(endOfStream).PriorityPresent(hasPriority).PaddingPresent(padding > 0);

                // Read the first fragment (possibly everything).
                int         nonFragmentBytes  = padding + flags.GetNumPriorityBytes();
                int         maxFragmentLength = _maxFrameSize - nonFragmentBytes;
                IByteBuffer fragment          = headerBlock.ReadRetainedSlice(Math.Min(headerBlock.ReadableBytes, maxFragmentLength));

                // Set the end of headers flag for the first frame.
                _ = flags.EndOfHeaders(!headerBlock.IsReadable());

                int         payloadLength = fragment.ReadableBytes + nonFragmentBytes;
                IByteBuffer buf           = ctx.Allocator.Buffer(Http2CodecUtil.HeadersFrameHeaderLength);
                Http2CodecUtil.WriteFrameHeaderInternal(buf, payloadLength, Http2FrameTypes.Headers, flags, streamId);
                WritePaddingLength(buf, padding);

                if (hasPriority)
                {
                    _ = buf.WriteInt(exclusive ? (int)(uint)(0x80000000L | streamDependency) : streamDependency);

                    // Adjust the weight so that it fits into a single byte on the wire.
                    _ = buf.WriteByte(weight - 1);
                }

                _ = ctx.WriteAsync(buf, promiseAggregator.NewPromise());

                // Write the first fragment.
                _ = ctx.WriteAsync(fragment, promiseAggregator.NewPromise());

                // Write out the padding, if any.
                if (PaddingBytes(padding) > 0)
                {
                    _ = ctx.WriteAsync(ZeroBuffer.Slice(0, PaddingBytes(padding)), promiseAggregator.NewPromise());
                }

                if (!flags.EndOfHeaders())
                {
                    _ = WriteContinuationFramesAsync(ctx, streamId, headerBlock, promiseAggregator);
                }
            }
            catch (Http2Exception e)
            {
                promiseAggregator.SetException(e);
            }
            catch (Exception t)
            {
                promiseAggregator.SetException(t);
                _ = promiseAggregator.DoneAllocatingPromises();
                throw;
            }
            finally
            {
                _ = (headerBlock?.Release());
            }

            _ = promiseAggregator.DoneAllocatingPromises();
            return(promiseAggregator.Task);
        }
Пример #5
0
        public virtual Task WritePushPromiseAsync(IChannelHandlerContext ctx, int streamId,
                                                  int promisedStreamId, IHttp2Headers headers, int padding, IPromise promise)
        {
            IByteBuffer             headerBlock       = null;
            SimplePromiseAggregator promiseAggregator = new SimplePromiseAggregator(promise);

            try
            {
                if ((uint)(streamId - 1) > SharedConstants.TooBigOrNegative)
                {
                    ThrowHelper.ThrowArgumentException_Positive(ExceptionArgument.StreamID);
                }
                if (promisedStreamId <= 0)
                {
                    ThrowHelper.ThrowArgumentException_Positive(ExceptionArgument.PromisedStreamId);
                }
                Http2CodecUtil.VerifyPadding(padding);

                // Encode the entire header block into an intermediate buffer.
                headerBlock = ctx.Allocator.Buffer();
                _headersEncoder.EncodeHeaders(streamId, headers, headerBlock);

                // Read the first fragment (possibly everything).
                Http2Flags flags = new Http2Flags().PaddingPresent(padding > 0);
                // IntFieldLength is for the length of the promisedStreamId
                int         nonFragmentLength = Http2CodecUtil.IntFieldLength + padding;
                int         maxFragmentLength = _maxFrameSize - nonFragmentLength;
                IByteBuffer fragment          = headerBlock.ReadRetainedSlice(Math.Min(headerBlock.ReadableBytes, maxFragmentLength));

                _ = flags.EndOfHeaders(!headerBlock.IsReadable());

                int         payloadLength = fragment.ReadableBytes + nonFragmentLength;
                IByteBuffer buf           = ctx.Allocator.Buffer(Http2CodecUtil.PushPromiseFrameHeaderLength);
                Http2CodecUtil.WriteFrameHeaderInternal(buf, payloadLength, Http2FrameTypes.PushPromise, flags, streamId);
                WritePaddingLength(buf, padding);

                // Write out the promised stream ID.
                _ = buf.WriteInt(promisedStreamId);
                _ = ctx.WriteAsync(buf, promiseAggregator.NewPromise());

                // Write the first fragment.
                _ = ctx.WriteAsync(fragment, promiseAggregator.NewPromise());

                // Write out the padding, if any.
                if (PaddingBytes(padding) > 0)
                {
                    _ = ctx.WriteAsync(ZeroBuffer.Slice(0, PaddingBytes(padding)), promiseAggregator.NewPromise());
                }

                if (!flags.EndOfHeaders())
                {
                    _ = WriteContinuationFramesAsync(ctx, streamId, headerBlock, promiseAggregator);
                }
            }
            catch (Http2Exception e)
            {
                promiseAggregator.SetException(e);
            }
            catch (Exception t)
            {
                promiseAggregator.SetException(t);
                _ = promiseAggregator.DoneAllocatingPromises();
                throw;
            }
            finally
            {
                if (headerBlock is object)
                {
                    _ = headerBlock.Release();
                }
            }

            _ = promiseAggregator.DoneAllocatingPromises();
            return(promiseAggregator.Task);
        }