Ejemplo n.º 1
0
        /// <summary>
        /// If padding is present in the payload, reads the next byte as padding. The padding also includes the one byte
        /// width of the pad length field. Otherwise, returns zero.
        /// </summary>
        /// <param name="payload"></param>
        /// <returns></returns>
        int ReadPadding(IByteBuffer payload)
        {
            if (!_flags.PaddingPresent())
            {
                return(0);
            }

            return(payload.ReadByte() + 1);
        }
Ejemplo n.º 2
0
        public virtual Task WriteDataAsync(IChannelHandlerContext ctx, int streamId, IByteBuffer data, int padding, bool endOfStream, IPromise promise)
        {
            SimplePromiseAggregator promiseAggregator = new SimplePromiseAggregator(promise);
            IByteBuffer             frameHeader       = null;

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

                int        remainingData = data.ReadableBytes;
                Http2Flags flags         = new Http2Flags();
                _ = flags.EndOfStream(false);
                _ = flags.PaddingPresent(false);
                // Fast path to write frames of payload size maxFrameSize first.
                if (remainingData > _maxFrameSize)
                {
                    frameHeader = ctx.Allocator.Buffer(Http2CodecUtil.FrameHeaderLength);
                    Http2CodecUtil.WriteFrameHeaderInternal(frameHeader, _maxFrameSize, Http2FrameTypes.Data, flags, streamId);
                    do
                    {
                        // Write the header.
                        _ = ctx.WriteAsync(frameHeader.RetainedSlice(), promiseAggregator.NewPromise());

                        // Write the payload.
                        _ = ctx.WriteAsync(data.ReadRetainedSlice(_maxFrameSize), promiseAggregator.NewPromise());

                        remainingData -= _maxFrameSize;
                        // Stop iterating if remainingData ==  _maxFrameSize so we can take care of reference counts below.
                    }while (remainingData > _maxFrameSize);
                }

                if (0u >= (uint)padding)
                {
                    // Write the header.
                    if (frameHeader is object)
                    {
                        _           = frameHeader.Release();
                        frameHeader = null;
                    }

                    IByteBuffer frameHeader2 = ctx.Allocator.Buffer(Http2CodecUtil.FrameHeaderLength);
                    _ = flags.EndOfStream(endOfStream);
                    Http2CodecUtil.WriteFrameHeaderInternal(frameHeader2, remainingData, Http2FrameTypes.Data, flags, streamId);
                    _ = ctx.WriteAsync(frameHeader2, promiseAggregator.NewPromise());

                    // Write the payload.
                    IByteBuffer lastFrame = data.ReadSlice(remainingData);
                    data = null;
                    _    = ctx.WriteAsync(lastFrame, promiseAggregator.NewPromise());
                }
                else
                {
                    if (remainingData != _maxFrameSize)
                    {
                        if (frameHeader is object)
                        {
                            _           = frameHeader.Release();
                            frameHeader = null;
                        }
                    }
                    else
                    {
                        remainingData -= _maxFrameSize;
                        // Write the header.
                        IByteBuffer lastFrame;
                        if (frameHeader is null)
                        {
                            lastFrame = ctx.Allocator.Buffer(Http2CodecUtil.FrameHeaderLength);
                            Http2CodecUtil.WriteFrameHeaderInternal(lastFrame, _maxFrameSize, Http2FrameTypes.Data, flags, streamId);
                        }
                        else
                        {
                            lastFrame   = frameHeader.Slice();
                            frameHeader = null;
                        }

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

                        // Write the payload.
                        lastFrame = data.ReadableBytes != _maxFrameSize?data.ReadSlice(_maxFrameSize) : data;

                        data = null;
                        _    = ctx.WriteAsync(lastFrame, promiseAggregator.NewPromise());
                    }

                    do
                    {
                        int frameDataBytes    = Math.Min(remainingData, _maxFrameSize);
                        int framePaddingBytes = Math.Min(padding, Math.Max(0, (_maxFrameSize - 1) - frameDataBytes));

                        // Decrement the remaining counters.
                        padding       -= framePaddingBytes;
                        remainingData -= frameDataBytes;

                        // Write the header.
                        IByteBuffer frameHeader2 = ctx.Allocator.Buffer(Http2CodecUtil.DataFrameHeaderLength);
                        _ = flags.EndOfStream(endOfStream && 0u >= (uint)remainingData && 0u >= (uint)padding);
                        _ = flags.PaddingPresent(framePaddingBytes > 0);
                        Http2CodecUtil.WriteFrameHeaderInternal(frameHeader2, framePaddingBytes + frameDataBytes, Http2FrameTypes.Data, flags, streamId);
                        WritePaddingLength(frameHeader2, framePaddingBytes);
                        _ = ctx.WriteAsync(frameHeader2, promiseAggregator.NewPromise());

                        // Write the payload.
                        if (frameDataBytes != 0)
                        {
                            if (0u >= (uint)remainingData)
                            {
                                IByteBuffer lastFrame = data.ReadSlice(frameDataBytes);
                                data = null;
                                _    = ctx.WriteAsync(lastFrame, promiseAggregator.NewPromise());
                            }
                            else
                            {
                                _ = ctx.WriteAsync(data.ReadRetainedSlice(frameDataBytes), promiseAggregator.NewPromise());
                            }
                        }

                        // Write the frame padding.
                        if (PaddingBytes(framePaddingBytes) > 0)
                        {
                            _ = ctx.WriteAsync(
                                ZeroBuffer.Slice(0, PaddingBytes(framePaddingBytes)),
                                promiseAggregator.NewPromise());
                        }
                    }while (remainingData != 0 || padding != 0);
                }
            }
            catch (Exception cause)
            {
                if (frameHeader is object)
                {
                    _ = frameHeader.Release();
                }

                // Use a try/finally here in case the data has been released before calling this method. This is not
                // necessary above because we internally allocate frameHeader.
                try
                {
                    if (data is object)
                    {
                        _ = data.Release();
                    }
                }
                finally
                {
                    promiseAggregator.SetException(cause);
                    _ = promiseAggregator.DoneAllocatingPromises();
                }

                return(promiseAggregator.Task);
            }

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