/* https://tools.ietf.org/html/rfc7540#section-6.2 +-+-------------+-----------------------------------------------+ |E| Stream Dependency? (31) | +-+-------------+-----------------------------------------------+ | Weight? (8) | +-+-------------+-----------------------------------------------+ | Header Block Fragment (*) ... +---------------------------------------------------------------+ */ public Task SendHeadersWithPriorityAsync(int streamId, IEnumerable <KeyValuePair <string, string> > headers, byte priority, int streamDependency, bool endStream) { var writableBuffer = _pair.Application.Output; var frame = new Http2Frame(); frame.PrepareHeaders(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.PRIORITY, streamId); frame.HeadersPriorityWeight = priority; frame.HeadersStreamDependency = streamDependency; var extendedHeaderLength = 5; // stream dependency + weight var buffer = _headerEncodingBuffer.AsSpan(); var extendedHeader = buffer.Slice(0, extendedHeaderLength); Bitshifter.WriteUInt31BigEndian(extendedHeader, (uint)streamDependency); extendedHeader[4] = priority; var payload = buffer.Slice(extendedHeaderLength); HPackHeaderWriter.BeginEncodeHeaders(GetHeadersEnumerator(headers), payload, out var length); frame.PayloadLength = extendedHeaderLength + length; if (endStream) { frame.HeadersFlags |= Http2HeadersFrameFlags.END_STREAM; } WriteHeader(frame, writableBuffer); writableBuffer.Write(buffer.Slice(0, frame.PayloadLength)); return(FlushAsync(writableBuffer)); }
/* https://tools.ietf.org/html/rfc7540#section-6.2 +---------------+ |Pad Length? (8)| +-+-------------+-----------------------------------------------+ | Header Block Fragment (*) ... +---------------------------------------------------------------+ | Padding (*) ... +---------------------------------------------------------------+ */ public Task SendHeadersWithPaddingAsync(int streamId, IEnumerable <KeyValuePair <string, string> > headers, byte padLength, bool endStream) { var writableBuffer = _pair.Application.Output; var frame = new Http2Frame(); frame.PrepareHeaders(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.PADDED, streamId); frame.HeadersPadLength = padLength; var extendedHeaderLength = 1; // Padding length field var buffer = _headerEncodingBuffer.AsSpan(); var extendedHeader = buffer.Slice(0, extendedHeaderLength); extendedHeader[0] = padLength; 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)); }
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 = HPackHeaderWriter.BeginEncodeHeaders(GetHeadersEnumerator(headers), buffer.Span, out var length); frame.PayloadLength = length; WriteHeader(frame, outputWriter); await SendAsync(buffer.Span.Slice(0, length)); return(done); }
public Task StartStreamAsync(int streamId, IEnumerable <KeyValuePair <string, string> > headers, bool endStream) { var writableBuffer = _pair.Application.Output; var tcs = new TaskCompletionSource <object>(TaskCreationOptions.RunContinuationsAsynchronously); 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)); }
/* 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 tcs = new TaskCompletionSource <object>(TaskCreationOptions.RunContinuationsAsynchronously); 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)); }