/* https://tools.ietf.org/html/rfc7540#section-6.3 +-+-------------------------------------------------------------+ |E| Stream Dependency (31) | +-+-------------+-----------------------------------------------+ | Weight (8) | +-+-------------+ */ public Task SendPriorityAsync(int streamId, int streamDependency = 0) { var outputWriter = _pair.Application.Output; var priorityFrame = new Http2Frame(); priorityFrame.PreparePriority(streamId, streamDependency: streamDependency, exclusive: false, weight: 0); var payload = new byte[priorityFrame.PayloadLength].AsSpan(); Bitshifter.WriteUInt31BigEndian(payload, (uint)streamDependency); payload[4] = 0; // Weight Http2FrameWriter.WriteHeader(priorityFrame, outputWriter); return(SendAsync(payload)); }
/* 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, preserveHighestBit: false); output.Advance(Http2FrameReader.HeaderLength); }
public async Task SendSettingsWithInvalidStreamIdAsync(int streamId) { var writableBuffer = _pair.Application.Output; var frame = new Http2Frame(); frame.PrepareSettings(Http2SettingsFrameFlags.NONE); frame.StreamId = streamId; var settings = _clientSettings.GetNonProtocolDefaults(); var payload = new byte[settings.Count * Http2FrameReader.SettingSize]; frame.PayloadLength = payload.Length; Http2FrameWriter.WriteSettings(settings, payload); Http2FrameWriter.WriteHeader(frame, writableBuffer); await SendAsync(payload); }
internal async Task <bool> SendContinuationAsync(int streamId, Http2ContinuationFrameFlags flags, IEnumerable <KeyValuePair <string, string> > headers) { var outputWriter = _pair.Application.Output; var frame = new Http2Frame(); frame.PrepareContinuation(flags, streamId); var buffer = _headerEncodingBuffer.AsMemory(); var done = _hpackEncoder.BeginEncode(headers, buffer.Span, out var length); frame.PayloadLength = length; WriteHeader(frame, outputWriter); await SendAsync(buffer.Span.Slice(0, length)); return(done); }
protected async Task <bool> SendContinuationAsync(int streamId, Http2ContinuationFrameFlags flags) { var outputWriter = _pair.Application.Output; var frame = new Http2Frame(); frame.PrepareContinuation(flags, streamId); var buffer = _headerEncodingBuffer.AsMemory(); var done = _hpackEncoder.Encode(buffer.Span, out var length); frame.PayloadLength = length; Http2FrameWriter.WriteHeader(frame, outputWriter); await SendAsync(buffer.Span.Slice(0, length)); return(done); }
protected Task SendSettingsWithInvalidParameterValueAsync(Http2SettingsParameter parameter, uint value) { var frame = new Http2Frame(Http2Limits.MinAllowedMaxFrameSize); frame.PrepareSettings(Http2SettingsFrameFlags.NONE); frame.PayloadLength = 6; frame.Payload[0] = (byte)((ushort)parameter >> 8); frame.Payload[1] = (byte)(ushort)parameter; frame.Payload[2] = (byte)(value >> 24); frame.Payload[3] = (byte)(value >> 16); frame.Payload[4] = (byte)(value >> 8); frame.Payload[5] = (byte)value; return(SendAsync(frame.Raw)); }
public static void WriteStartStream(this PipeWriter writer, int streamId, Span <byte> headerData, bool endStream) { var frame = new Http2Frame(); frame.PrepareHeaders(Http2HeadersFrameFlags.NONE, streamId); frame.PayloadLength = headerData.Length; frame.HeadersFlags = Http2HeadersFrameFlags.END_HEADERS; if (endStream) { frame.HeadersFlags |= Http2HeadersFrameFlags.END_STREAM; } Http2FrameWriter.WriteHeader(frame, writer); writer.Write(headerData); }
protected Task StartStreamAsync(int streamId, IEnumerable <KeyValuePair <string, string> > headers, bool endStream) { var writableBuffer = _pair.Application.Output; var tcs = new TaskCompletionSource <object>(TaskCreationOptions.RunContinuationsAsynchronously); _runningStreams[streamId] = tcs; var frame = new Http2Frame(); frame.PrepareHeaders(Http2HeadersFrameFlags.NONE, streamId); var buffer = _headerEncodingBuffer.AsSpan(); var done = _hpackEncoder.BeginEncode(headers, buffer, out var length); frame.PayloadLength = length; if (done) { frame.HeadersFlags = Http2HeadersFrameFlags.END_HEADERS; } if (endStream) { frame.HeadersFlags |= Http2HeadersFrameFlags.END_STREAM; } Http2FrameWriter.WriteHeader(frame, writableBuffer); writableBuffer.Write(buffer.Slice(0, length)); while (!done) { frame.PrepareContinuation(Http2ContinuationFrameFlags.NONE, streamId); done = _hpackEncoder.Encode(buffer, out length); frame.PayloadLength = length; if (done) { frame.ContinuationFlags = Http2ContinuationFrameFlags.END_HEADERS; } Http2FrameWriter.WriteHeader(frame, writableBuffer); writableBuffer.Write(buffer.Slice(0, length)); } return(FlushAsync(writableBuffer)); }
public async Task WriteHeader_UnsetsReservedBit() { // Arrange var pipe = new Pipe(new PipeOptions(_dirtyMemoryPool, PipeScheduler.Inline, PipeScheduler.Inline)); var frame = new Http2Frame(); frame.PreparePing(Http2PingFrameFlags.NONE); // Act Http2FrameWriter.WriteHeader(frame, pipe.Writer); await pipe.Writer.FlushAsync(); // Assert var payload = await pipe.Reader.ReadForLengthAsync(Http2FrameReader.HeaderLength); Assert.Equal(new byte[] { 0x00, 0x00, 0x00, 0x00 }, payload.Skip(5).Take(4).ToArray()); }
public Task StartStreamAsync(int streamId, IEnumerable <KeyValuePair <string, string> > headers, bool endStream) { var writableBuffer = _pair.Application.Output; var frame = new Http2Frame(); frame.PrepareHeaders(Http2HeadersFrameFlags.NONE, streamId); var buffer = _headerEncodingBuffer.AsSpan(); var headersEnumerator = GetHeadersEnumerator(headers); var done = HPackHeaderWriter.BeginEncodeHeaders(headersEnumerator, buffer, out var length); frame.PayloadLength = length; if (done) { frame.HeadersFlags = Http2HeadersFrameFlags.END_HEADERS; } if (endStream) { frame.HeadersFlags |= Http2HeadersFrameFlags.END_STREAM; } WriteHeader(frame, writableBuffer); writableBuffer.Write(buffer.Slice(0, length)); while (!done) { frame.PrepareContinuation(Http2ContinuationFrameFlags.NONE, streamId); done = HPackHeaderWriter.ContinueEncodeHeaders(headersEnumerator, buffer, out length); frame.PayloadLength = length; if (done) { frame.ContinuationFlags = Http2ContinuationFrameFlags.END_HEADERS; } WriteHeader(frame, writableBuffer); writableBuffer.Write(buffer.Slice(0, length)); } return(FlushAsync(writableBuffer)); }
public async Task SendIncompleteContinuationFrameAsync(int streamId) { var outputWriter = _pair.Application.Output; var frame = new Http2Frame(); frame.PrepareContinuation(Http2ContinuationFrameFlags.END_HEADERS, streamId); frame.PayloadLength = 3; var payload = new byte[3]; // Set up an incomplete Literal Header Field w/ Incremental Indexing frame, // with an incomplete new name payload[0] = 0; payload[1] = 2; payload[2] = (byte)'a'; WriteHeader(frame, outputWriter); await SendAsync(payload); }
internal async Task SendSettingsWithInvalidParameterValueAsync(Http2SettingsParameter parameter, uint value) { var writableBuffer = _pair.Application.Output; var frame = new Http2Frame(); frame.PrepareSettings(Http2SettingsFrameFlags.NONE); frame.PayloadLength = 6; var payload = new byte[Http2FrameReader.SettingSize]; payload[0] = (byte)((ushort)parameter >> 8); payload[1] = (byte)(ushort)parameter; payload[2] = (byte)(value >> 24); payload[3] = (byte)(value >> 16); payload[4] = (byte)(value >> 8); payload[5] = (byte)value; WriteHeader(frame, writableBuffer); await SendAsync(payload); }
public async Task SendInvalidHeadersFrameAsync(int streamId, int payloadLength, byte padLength) { Assert.True(padLength >= payloadLength, $"{nameof(padLength)} must be greater than or equal to {nameof(payloadLength)} to create an invalid frame."); var outputWriter = _pair.Application.Output; var frame = new Http2Frame(); frame.PrepareHeaders(Http2HeadersFrameFlags.PADDED, streamId); frame.PayloadLength = payloadLength; var payload = new byte[payloadLength]; if (payloadLength > 0) { payload[0] = padLength; } WriteHeader(frame, outputWriter); await SendAsync(payload); }
public async Task SendDataWithPaddingAsync(int streamId, Memory <byte> data, byte padLength, bool endStream) { var outputWriter = _pair.Application.Output; var frame = new Http2Frame(); frame.PrepareData(streamId, padLength); frame.PayloadLength = data.Length + 1 + padLength; if (endStream) { frame.DataFlags |= Http2DataFrameFlags.END_STREAM; } WriteHeader(frame, outputWriter); outputWriter.GetSpan(1)[0] = padLength; outputWriter.Advance(1); await SendAsync(data.Span); await SendAsync(new byte[padLength]); }
public Task SendInvalidDataFrameAsync(int streamId, int frameLength, byte padLength) { Assert.True(padLength >= frameLength, $"{nameof(padLength)} must be greater than or equal to {nameof(frameLength)} to create an invalid frame."); var outputWriter = _pair.Application.Output; var frame = new Http2Frame(); frame.PrepareData(streamId); frame.DataFlags = Http2DataFrameFlags.PADDED; frame.PayloadLength = frameLength; var payload = new byte[frameLength]; if (frameLength > 0) { payload[0] = padLength; } WriteHeader(frame, outputWriter); return(SendAsync(payload)); }
public static void WriteStartStream(this PipeWriter writer, int streamId, Http2HeadersEnumerator headers, HPackEncoder hpackEncoder, byte[] headerEncodingBuffer, bool endStream) { var frame = new Http2Frame(); frame.PrepareHeaders(Http2HeadersFrameFlags.NONE, streamId); var buffer = headerEncodingBuffer.AsSpan(); var done = hpackEncoder.BeginEncode(headers, buffer, out var length); frame.PayloadLength = length; if (done) { frame.HeadersFlags = Http2HeadersFrameFlags.END_HEADERS; } if (endStream) { frame.HeadersFlags |= Http2HeadersFrameFlags.END_STREAM; } Http2FrameWriter.WriteHeader(frame, writer); writer.Write(buffer.Slice(0, length)); while (!done) { frame.PrepareContinuation(Http2ContinuationFrameFlags.NONE, streamId); done = hpackEncoder.Encode(buffer, out length); frame.PayloadLength = length; if (done) { frame.ContinuationFlags = Http2ContinuationFrameFlags.END_HEADERS; } Http2FrameWriter.WriteHeader(frame, writer); writer.Write(buffer.Slice(0, length)); } }
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(SharedStrings.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); }
/* https://tools.ietf.org/html/rfc7540#section-6.2 +---------------+ |Pad Length? (8)| +-+-------------+-----------------------------------------------+ |E| Stream Dependency? (31) | +-+-------------+-----------------------------------------------+ | Weight? (8) | +-+-------------+-----------------------------------------------+ | Header Block Fragment (*) ... +---------------------------------------------------------------+ | Padding (*) ... +---------------------------------------------------------------+ */ protected Task SendHeadersWithPaddingAndPriorityAsync(int streamId, IEnumerable <KeyValuePair <string, string> > headers, byte padLength, byte priority, int streamDependency, bool endStream) { var writableBuffer = _pair.Application.Output; var tcs = new TaskCompletionSource <object>(TaskCreationOptions.RunContinuationsAsynchronously); _runningStreams[streamId] = tcs; var frame = new Http2Frame(); frame.PrepareHeaders(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.PADDED | Http2HeadersFrameFlags.PRIORITY, streamId); frame.HeadersPadLength = padLength; frame.HeadersPriorityWeight = priority; frame.HeadersStreamDependency = streamDependency; var extendedHeaderLength = 6; // pad length + stream dependency + weight var buffer = _headerEncodingBuffer.AsSpan(); var extendedHeader = buffer.Slice(0, extendedHeaderLength); extendedHeader[0] = padLength; Bitshifter.WriteUInt31BigEndian(extendedHeader.Slice(1), (uint)streamDependency); extendedHeader[5] = priority; var payload = buffer.Slice(extendedHeaderLength, buffer.Length - padLength - extendedHeaderLength); _hpackEncoder.BeginEncode(headers, payload, out var length); var padding = buffer.Slice(extendedHeaderLength + length, padLength); padding.Fill(0); frame.PayloadLength = extendedHeaderLength + length + padLength; if (endStream) { frame.HeadersFlags |= Http2HeadersFrameFlags.END_STREAM; } Http2FrameWriter.WriteHeader(frame, writableBuffer); writableBuffer.Write(buffer.Slice(0, frame.PayloadLength)); return(FlushAsync(writableBuffer)); }
protected async Task StartStreamAsync(int streamId, IEnumerable <KeyValuePair <string, string> > headers, bool endStream) { var tcs = new TaskCompletionSource <object>(TaskCreationOptions.RunContinuationsAsynchronously); _runningStreams[streamId] = tcs; var frame = new Http2Frame(Http2Limits.MinAllowedMaxFrameSize); frame.PrepareHeaders(Http2HeadersFrameFlags.NONE, streamId); var done = _hpackEncoder.BeginEncode(headers, frame.HeadersPayload, out var length); frame.PayloadLength = length; if (done) { frame.HeadersFlags = Http2HeadersFrameFlags.END_HEADERS; } if (endStream) { frame.HeadersFlags |= Http2HeadersFrameFlags.END_STREAM; } await SendAsync(frame.Raw); while (!done) { frame.PrepareContinuation(Http2ContinuationFrameFlags.NONE, streamId); done = _hpackEncoder.Encode(frame.HeadersPayload, out length); frame.PayloadLength = length; if (done) { frame.ContinuationFlags = Http2ContinuationFrameFlags.END_HEADERS; } await SendAsync(frame.Raw); } }
protected async Task SendHeadersWithPaddingAsync(int streamId, IEnumerable <KeyValuePair <string, string> > headers, byte padLength, bool endStream) { var tcs = new TaskCompletionSource <object>(TaskCreationOptions.RunContinuationsAsynchronously); _runningStreams[streamId] = tcs; var frame = new Http2Frame(Http2Limits.MinAllowedMaxFrameSize); frame.PrepareHeaders(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.PADDED, streamId); frame.HeadersPadLength = padLength; _hpackEncoder.BeginEncode(headers, frame.HeadersPayload, out var length); frame.PayloadLength = 1 + length + padLength; frame.Payload.Slice(1 + length).Fill(0); if (endStream) { frame.HeadersFlags |= Http2HeadersFrameFlags.END_STREAM; } await SendAsync(frame.Raw); }
protected async Task SendHeadersWithPriorityAsync(int streamId, IEnumerable <KeyValuePair <string, string> > headers, byte priority, int streamDependency, bool endStream) { var tcs = new TaskCompletionSource <object>(TaskCreationOptions.RunContinuationsAsynchronously); _runningStreams[streamId] = tcs; var frame = new Http2Frame(Http2Limits.MinAllowedMaxFrameSize); frame.PrepareHeaders(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.PRIORITY, streamId); frame.HeadersPriorityWeight = priority; frame.HeadersStreamDependency = streamDependency; _hpackEncoder.BeginEncode(headers, frame.HeadersPayload, out var length); frame.PayloadLength = 5 + length; if (endStream) { frame.HeadersFlags |= Http2HeadersFrameFlags.END_STREAM; } await SendAsync(frame.Raw); }
public virtual void GlobalSetup() { _memoryPool = PinnedBlockMemoryPoolFactory.Create(); _httpFrame = new Http2Frame(); var options = new PipeOptions(_memoryPool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false); _connectionPair = DuplexPipe.CreateConnectionPair(options, options); _httpRequestHeaders = new HttpRequestHeaders(); _httpRequestHeaders[HeaderNames.Method] = new StringValues("GET"); _httpRequestHeaders[HeaderNames.Path] = new StringValues("/"); _httpRequestHeaders[HeaderNames.Scheme] = new StringValues("http"); _httpRequestHeaders[HeaderNames.Authority] = new StringValues("localhost:80"); _headersBuffer = new byte[1024 * 16]; _hpackEncoder = new DynamicHPackEncoder(); var serviceContext = TestContextFactory.CreateServiceContext( serverOptions: new KestrelServerOptions(), dateHeaderValueManager: new DateHeaderValueManager(), systemClock: new MockSystemClock()); serviceContext.DateHeaderValueManager.OnHeartbeat(default);
/* https://tools.ietf.org/html/rfc7540#section-6.2 +---------------+ |Pad Length? (8)| +-+-------------+-----------------------------------------------+ |E| Stream Dependency? (31) | +-+-------------+-----------------------------------------------+ | Weight? (8) | +-+-------------+-----------------------------------------------+ | Header Block Fragment (*) ... +---------------------------------------------------------------+ | Padding (*) ... +---------------------------------------------------------------+ */ public Task SendHeadersWithPaddingAndPriorityAsync(int streamId, IEnumerable <KeyValuePair <string, string> > headers, byte padLength, byte priority, int streamDependency, bool endStream) { var writableBuffer = _pair.Application.Output; var frame = new Http2Frame(); frame.PrepareHeaders(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.PADDED | Http2HeadersFrameFlags.PRIORITY, streamId); frame.HeadersPadLength = padLength; frame.HeadersPriorityWeight = priority; frame.HeadersStreamDependency = streamDependency; var extendedHeaderLength = 6; // pad length + stream dependency + weight var buffer = _headerEncodingBuffer.AsSpan(); var extendedHeader = buffer.Slice(0, extendedHeaderLength); extendedHeader[0] = padLength; Bitshifter.WriteUInt31BigEndian(extendedHeader.Slice(1), (uint)streamDependency); extendedHeader[5] = priority; var payload = buffer.Slice(extendedHeaderLength, buffer.Length - padLength - extendedHeaderLength); HPackHeaderWriter.BeginEncodeHeaders(GetHeadersEnumerator(headers), payload, out var length); var padding = buffer.Slice(extendedHeaderLength + length, padLength); padding.Clear(); frame.PayloadLength = extendedHeaderLength + length + padLength; if (endStream) { frame.HeadersFlags |= Http2HeadersFrameFlags.END_STREAM; } WriteHeader(frame, writableBuffer); writableBuffer.Write(buffer.Slice(0, frame.PayloadLength)); return(FlushAsync(writableBuffer)); }
public void Http2FrameSending(string connectionId, Http2Frame frame) { _http2FrameSending(_logger, connectionId, frame.Type, frame.StreamId, frame.PayloadLength, frame.ShowFlags(), null); }
public static void WriteWindowUpdateAsync(this PipeWriter writer, int streamId, int sizeIncrement, Http2Frame frame = null) { frame ??= new Http2Frame(); frame.PrepareWindowUpdate(streamId, sizeIncrement); Http2FrameWriter.WriteHeader(frame, writer); BinaryPrimitives.WriteUInt32BigEndian(writer.GetSpan(4), (uint)sizeIncrement); writer.Advance(4); }
public Task OnDataAsync(Http2Frame dataFrame, in ReadOnlySequence <byte> payload)
public void Http2FrameSending(string connectionId, Http2Frame frame) { }
public void Http2FrameReceived(string connectionId, Http2Frame frame) { }
public void Http2FrameSending(string connectionId, Http2Frame frame) { _trace1.Http2FrameSending(connectionId, frame); _trace2.Http2FrameSending(connectionId, frame); }
public void Http2FrameReceived(string connectionId, Http2Frame frame) { _trace1.Http2FrameReceived(connectionId, frame); _trace2.Http2FrameReceived(connectionId, frame); }