/* https://tools.ietf.org/html/rfc7540#section-4.1
         +-----------------------------------------------+
         |                 Length (24)                   |
         +---------------+---------------+---------------+
         |   Type (8)    |   Flags (8)   |
         +-+-------------+---------------+-------------------------------+
         |R|                 Stream Identifier (31)                      |
         +=+=============================================================+
         |                   Frame Payload (0...)                      ...
         +---------------------------------------------------------------+
         */
        internal static void WriteHeader(Http2Frame frame, PipeWriter output)
        {
            var buffer = output.GetSpan(Http2FrameReader.HeaderLength);

            Bitshifter.WriteUInt24BigEndian(buffer, (uint)frame.PayloadLength);
            buffer = buffer.Slice(3);

            buffer[0] = (byte)frame.Type;
            buffer[1] = frame.Flags;
            buffer    = buffer.Slice(2);

            Bitshifter.WriteUInt31BigEndian(buffer, (uint)frame.StreamId);

            output.Advance(Http2FrameReader.HeaderLength);
        }
        /* https://tools.ietf.org/html/rfc7540#section-6.8
         +-+-------------------------------------------------------------+
         |R|                  Last-Stream-ID (31)                        |
         +-+-------------------------------------------------------------+
         |                      Error Code (32)                          |
         +---------------------------------------------------------------+
         |                  Additional Debug Data (*)                    | (not implemented)
         +---------------------------------------------------------------+
         */
        public Task WriteGoAwayAsync(int lastStreamId, Http2ErrorCode errorCode)
        {
            lock (_writeLock)
            {
                _outgoingFrame.PrepareGoAway(lastStreamId, errorCode);
                WriteHeaderUnsynchronized();

                var buffer = _outputWriter.GetSpan(8);
                Bitshifter.WriteUInt31BigEndian(buffer, (uint)lastStreamId);
                buffer = buffer.Slice(4);
                BinaryPrimitives.WriteUInt32BigEndian(buffer, (uint)errorCode);
                _outputWriter.Advance(8);

                return(TimeFlushUnsynchronizedAsync());
            }
        }
        /* https://tools.ietf.org/html/rfc7540#section-6.9
         +-+-------------------------------------------------------------+
         |R|              Window Size Increment (31)                     |
         +-+-------------------------------------------------------------+
         */
        public Task WriteWindowUpdateAsync(int streamId, int sizeIncrement)
        {
            lock (_writeLock)
            {
                if (_completed)
                {
                    return(Task.CompletedTask);
                }

                _outgoingFrame.PrepareWindowUpdate(streamId, sizeIncrement);
                WriteHeaderUnsynchronized();
                var buffer = _outputWriter.GetSpan(4);
                Bitshifter.WriteUInt31BigEndian(buffer, (uint)sizeIncrement);
                _outputWriter.Advance(4);
                return(TimeFlushUnsynchronizedAsync());
            }
        }
        public const int SettingSize = 6; // 2 bytes for the id, 4 bytes for the value.

        public static bool TryReadFrame(ref ReadOnlySequence <byte> buffer, Http2Frame frame, uint maxFrameSize, out ReadOnlySequence <byte> framePayload)
        {
            framePayload = ReadOnlySequence <byte> .Empty;

            if (buffer.Length < HeaderLength)
            {
                return(false);
            }

            var headerSlice = buffer.Slice(0, HeaderLength);
            var header      = headerSlice.ToSpan();

            var payloadLength = (int)Bitshifter.ReadUInt24BigEndian(header);

            if (payloadLength > maxFrameSize)
            {
                throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorFrameOverLimit(payloadLength, maxFrameSize), Http2ErrorCode.FRAME_SIZE_ERROR);
            }

            // Make sure the whole frame is buffered
            var frameLength = HeaderLength + payloadLength;

            if (buffer.Length < frameLength)
            {
                return(false);
            }

            frame.PayloadLength = payloadLength;
            frame.Type          = (Http2FrameType)header[TypeOffset];
            frame.Flags         = header[FlagsOffset];
            frame.StreamId      = (int)Bitshifter.ReadUInt31BigEndian(header.Slice(StreamIdOffset));

            var extendedHeaderLength = ReadExtendedFields(frame, buffer);

            // The remaining payload minus the extra fields
            framePayload = buffer.Slice(HeaderLength + extendedHeaderLength, payloadLength - extendedHeaderLength);
            buffer       = buffer.Slice(framePayload.End);

            return(true);
        }
示例#5
0
        private static int ReadExtendedFields(Http2Frame frame, ReadOnlySequence <byte> readableBuffer)
        {
            // Copy in any extra fields for the given frame type
            var extendedHeaderLength = GetPayloadFieldsLength(frame);

            if (extendedHeaderLength > frame.PayloadLength)
            {
                throw new Http2ConnectionErrorException(
                          CoreStrings.FormatHttp2ErrorUnexpectedFrameLength(frame.Type, expectedLength: extendedHeaderLength), Http2ErrorCode.FRAME_SIZE_ERROR);
            }

            var extendedHeaders = readableBuffer.Slice(HeaderLength, extendedHeaderLength).ToSpan();

            // Parse frame type specific fields
            switch (frame.Type)
            {
            /*
             +---------------+
             |Pad Length? (8)|
             +---------------+-----------------------------------------------+
             |                            Data (*)                         ...
             +---------------------------------------------------------------+
             |                           Padding (*)                       ...
             +---------------------------------------------------------------+
             */
            case Http2FrameType.DATA:     // Variable 0 or 1
                frame.DataPadLength = frame.DataHasPadding ? extendedHeaders[0] : (byte)0;
                break;

            /* https://tools.ietf.org/html/rfc7540#section-6.2
             +---------------+
             |Pad Length? (8)|
             +-+-------------+-----------------------------------------------+
             |E|                 Stream Dependency? (31)                     |
             +-+-------------+-----------------------------------------------+
             |  Weight? (8)  |
             +-+-------------+-----------------------------------------------+
             |                   Header Block Fragment (*)                 ...
             +---------------------------------------------------------------+
             |                           Padding (*)                       ...
             +---------------------------------------------------------------+
             */
            case Http2FrameType.HEADERS:
                if (frame.HeadersHasPadding)
                {
                    frame.HeadersPadLength = extendedHeaders[0];
                    extendedHeaders        = extendedHeaders.Slice(1);
                }
                else
                {
                    frame.HeadersPadLength = 0;
                }

                if (frame.HeadersHasPriority)
                {
                    frame.HeadersStreamDependency = (int)Bitshifter.ReadUInt31BigEndian(extendedHeaders);
                    frame.HeadersPriorityWeight   = extendedHeaders.Slice(4)[0];
                }
                else
                {
                    frame.HeadersStreamDependency = 0;
                    frame.HeadersPriorityWeight   = 0;
                }
                break;

            /* https://tools.ietf.org/html/rfc7540#section-6.8
             +-+-------------------------------------------------------------+
             |R|                  Last-Stream-ID (31)                        |
             +-+-------------------------------------------------------------+
             |                      Error Code (32)                          |
             +---------------------------------------------------------------+
             |                  Additional Debug Data (*)                    |
             +---------------------------------------------------------------+
             */
            case Http2FrameType.GOAWAY:
                frame.GoAwayLastStreamId = (int)Bitshifter.ReadUInt31BigEndian(extendedHeaders);
                frame.GoAwayErrorCode    = (Http2ErrorCode)BinaryPrimitives.ReadUInt32BigEndian(extendedHeaders.Slice(4));
                break;

            /* https://tools.ietf.org/html/rfc7540#section-6.3
             +-+-------------------------------------------------------------+
             |E|                  Stream Dependency (31)                     |
             +-+-------------+-----------------------------------------------+
             |   Weight (8)  |
             +-+-------------+
             */
            case Http2FrameType.PRIORITY:
                frame.PriorityStreamDependency = (int)Bitshifter.ReadUInt31BigEndian(extendedHeaders);
                frame.PriorityWeight           = extendedHeaders.Slice(4)[0];
                break;

            /* https://tools.ietf.org/html/rfc7540#section-6.4
             +---------------------------------------------------------------+
             |                        Error Code (32)                        |
             +---------------------------------------------------------------+
             */
            case Http2FrameType.RST_STREAM:
                frame.RstStreamErrorCode = (Http2ErrorCode)BinaryPrimitives.ReadUInt32BigEndian(extendedHeaders);
                break;

            /* https://tools.ietf.org/html/rfc7540#section-6.9
             +-+-------------------------------------------------------------+
             |R|              Window Size Increment (31)                     |
             +-+-------------------------------------------------------------+
             */
            case Http2FrameType.WINDOW_UPDATE:
                frame.WindowUpdateSizeIncrement = (int)Bitshifter.ReadUInt31BigEndian(extendedHeaders);
                break;

            case Http2FrameType.PING:         // Opaque payload 8 bytes long
            case Http2FrameType.SETTINGS:     // Settings are general payload
            case Http2FrameType.CONTINUATION: // None
            case Http2FrameType.PUSH_PROMISE: // Not implemented frames are ignored at this phase
            default:
                return(0);
            }

            return(extendedHeaderLength);
        }