public void Initialize_ChangeHeadersSource_EnumeratorUsesNewSource() { var responseHeaders = new HttpResponseHeaders(); responseHeaders.Append("Name1", "Value1"); responseHeaders.Append("Name2", "Value2-1"); responseHeaders.Append("Name2", "Value2-2"); var e = new Http3HeadersEnumerator(); e.Initialize(responseHeaders); Assert.True(e.MoveNext()); Assert.Equal("Name1", e.Current.Key); Assert.Equal("Value1", e.Current.Value); Assert.Equal(-1, e.QPackStaticTableId); Assert.True(e.MoveNext()); Assert.Equal("Name2", e.Current.Key); Assert.Equal("Value2-1", e.Current.Value); Assert.Equal(-1, e.QPackStaticTableId); Assert.True(e.MoveNext()); Assert.Equal("Name2", e.Current.Key); Assert.Equal("Value2-2", e.Current.Value); Assert.Equal(-1, e.QPackStaticTableId); var responseTrailers = (IHeaderDictionary) new HttpResponseTrailers(); responseTrailers.GrpcStatus = "1"; responseTrailers.Append("Name1", "Value1"); responseTrailers.Append("Name2", "Value2-1"); responseTrailers.Append("Name2", "Value2-2"); e.Initialize(responseTrailers); Assert.True(e.MoveNext()); Assert.Equal("Grpc-Status", e.Current.Key); Assert.Equal("1", e.Current.Value); Assert.Equal(-1, e.QPackStaticTableId); Assert.True(e.MoveNext()); Assert.Equal("Name1", e.Current.Key); Assert.Equal("Value1", e.Current.Value); Assert.Equal(-1, e.QPackStaticTableId); Assert.True(e.MoveNext()); Assert.Equal("Name2", e.Current.Key); Assert.Equal("Value2-1", e.Current.Value); Assert.Equal(-1, e.QPackStaticTableId); Assert.True(e.MoveNext()); Assert.Equal("Name2", e.Current.Key); Assert.Equal("Value2-2", e.Current.Value); Assert.Equal(-1, e.QPackStaticTableId); Assert.False(e.MoveNext()); }
private static bool Encode(Http3HeadersEnumerator headersEnumerator, Span <byte> buffer, bool throwIfNoneEncoded, ref int totalHeaderSize, out int length) { length = 0; do { var staticTableId = headersEnumerator.QPackStaticTableId; var name = headersEnumerator.Current.Key; var value = headersEnumerator.Current.Value; var valueEncoding = ReferenceEquals(headersEnumerator.EncodingSelector, KestrelServerOptions.DefaultHeaderEncodingSelector) ? null : headersEnumerator.EncodingSelector(name); if (!EncodeHeader(buffer.Slice(length), staticTableId, name, value, valueEncoding, out var headerLength)) { if (length == 0 && throwIfNoneEncoded) { throw new QPackEncodingException("TODO sync with corefx" /* CoreStrings.HPackErrorNotEnoughBuffer */); } return(false); } // https://quicwg.org/base-drafts/draft-ietf-quic-http.html#section-4.1.1.3 totalHeaderSize += HeaderField.GetLength(name.Length, value.Length); length += headerLength; } while (headersEnumerator.MoveNext()); return(true); }
public static bool BeginEncodeHeaders(Http3HeadersEnumerator enumerator, Span <byte> buffer, ref int totalHeaderSize, out int length) { bool hasValue = enumerator.MoveNext(); Debug.Assert(hasValue == true); buffer[0] = 0; buffer[1] = 0; bool doneEncode = Encode(enumerator, buffer.Slice(2), ref totalHeaderSize, out length); // Add two for the first two bytes. length += 2; return(doneEncode); }
private static bool Encode(Http3HeadersEnumerator headersEnumerator, Span <byte> buffer, bool throwIfNoneEncoded, ref int totalHeaderSize, out int length) { length = 0; do { // Match the current header to the QPACK static table. Possible outcomes: // 1. Known header and value. Write index. // 2. Known header with custom value. Write name index and full value. // 3. Unknown header. Write full name and value. var(staticTableId, matchedValue) = headersEnumerator.GetQPackStaticTableId(); var name = headersEnumerator.Current.Key; var value = headersEnumerator.Current.Value; int headerLength; if (matchedValue) { if (!QPackEncoder.EncodeStaticIndexedHeaderField(staticTableId, buffer.Slice(length), out headerLength)) { if (length == 0 && throwIfNoneEncoded) { throw new QPackEncodingException("TODO sync with corefx" /* CoreStrings.HPackErrorNotEnoughBuffer */); } return(false); } } else { var valueEncoding = ReferenceEquals(headersEnumerator.EncodingSelector, KestrelServerOptions.DefaultHeaderEncodingSelector) ? null : headersEnumerator.EncodingSelector(name); if (!EncodeHeader(buffer.Slice(length), staticTableId, name, value, valueEncoding, out headerLength)) { if (length == 0 && throwIfNoneEncoded) { throw new QPackEncodingException("TODO sync with corefx" /* CoreStrings.HPackErrorNotEnoughBuffer */); } return(false); } } // https://quicwg.org/base-drafts/draft-ietf-quic-http.html#section-4.1.1.3 totalHeaderSize += HeaderField.GetLength(name.Length, value.Length); length += headerLength; } while (headersEnumerator.MoveNext()); return(true); }
public static bool BeginEncode(int statusCode, Http3HeadersEnumerator enumerator, Span <byte> buffer, ref int totalHeaderSize, out int length) { bool hasValue = enumerator.MoveNext(); Debug.Assert(hasValue == true); // https://quicwg.org/base-drafts/draft-ietf-quic-qpack.html#header-prefix buffer[0] = 0; buffer[1] = 0; int statusCodeLength = EncodeStatusCode(statusCode, buffer.Slice(2)); totalHeaderSize += 42; // name (:status) + value (xxx) + overhead (32) bool done = Encode(enumerator, buffer.Slice(statusCodeLength + 2), throwIfNoneEncoded: false, ref totalHeaderSize, out int headersLength); length = statusCodeLength + headersLength + 2; return(done); }