public static void ToHttp2Headers(HttpHeaders inHeaders, IHttp2Headers output) { // Choose 8 as a default size because it is unlikely we will see more than 4 Connection headers values, but // still allowing for "enough" space in the map to reduce the chance of hash code collision. var connectionBlacklist = ToLowercaseMap(inHeaders.GetAll(HttpHeaderNames.Connection), 8); foreach (var entry in inHeaders) { AsciiString aName = entry.Key.ToLowerCase(); if (!HttpToHttp2HeaderBlacklist.Contains(aName) && !connectionBlacklist.Contains(aName)) { // https://tools.ietf.org/html/rfc7540#section-8.1.2.2 makes a special exception for TE if (aName.ContentEqualsIgnoreCase(HttpHeaderNames.Te)) { ToHttp2HeadersFilterTE(entry, output); } else if (aName.ContentEqualsIgnoreCase(HttpHeaderNames.Cookie)) { AsciiString value = AsciiString.Of(entry.Value); uint uValueCount = (uint)value.Count; // split up cookies to allow for better compression // https://tools.ietf.org/html/rfc7540#section-8.1.2.5 try { int index = value.ForEachByte(ByteProcessor.FindSemicolon); if (uValueCount > (uint)index) // != -1 { int start = 0; do { _ = output.Add(HttpHeaderNames.Cookie, value.SubSequence(start, index, false)); // skip 2 characters "; " (see https://tools.ietf.org/html/rfc6265#section-4.2.1) start = index + 2; } while ((uint)start < uValueCount && uValueCount > (uint)(index = value.ForEachByte(start, value.Count - start, ByteProcessor.FindSemicolon))); // != -1 if ((uint)start >= uValueCount) { ThrowHelper.ThrowArgumentException_CookieValueIsOfUnexpectedFormat(value); } _ = output.Add(HttpHeaderNames.Cookie, value.SubSequence(start, value.Count, false)); } else { _ = output.Add(HttpHeaderNames.Cookie, value); } } catch (Exception) { // This is not expect to happen because FIND_SEMI_COLON never throws but must be caught // because of the ByteProcessor interface. ThrowHelper.ThrowInvalidOperationException(); } } else { _ = output.Add(aName, entry.Value); } } } }
public void AppendToHeaderList(ICharSequence name, ICharSequence value) { _headersLength += HpackHeaderField.SizeOf(name, value); _exceededMaxLength |= _headersLength > _maxHeaderListSize; if (_exceededMaxLength || _validationException is object) { // We don't store the header since we've already failed validation requirements. return; } if (_validate) { try { _previousType = HpackDecoder.Validate(_streamId, name, _previousType); } catch (Http2Exception ex) { _validationException = ex; return; } } _ = _headers.Add(name, value); }
private static IHttp2Headers DummyHeaders(IHttp2Headers headers, int times) { string largeValue = Repeat("dummy-value", 100); for (int i = 0; i < times; i++) { headers.Add((AsciiString)string.Format("dummy-{0}", i), (AsciiString)largeValue); } return(headers); }
/// <summary> /// Filter the <see cref="HttpHeaderNames.Te"/> header according to the /// <a href="https://tools.ietf.org/html/rfc7540#section-8.1.2.2">special rules in the HTTP/2 RFC</a>. /// </summary> /// <param name="entry">An entry whose name is <see cref="HttpHeaderNames.Te"/>.</param> /// <param name="output">the resulting HTTP/2 headers.</param> private static void ToHttp2HeadersFilterTE(HeaderEntry <AsciiString, ICharSequence> entry, IHttp2Headers output) { if (AsciiString.IndexOf(entry.Value, ',', 0) == -1) { if (AsciiString.ContentEqualsIgnoreCase(AsciiString.Trim(entry.Value), HttpHeaderValues.Trailers)) { _ = output.Add(HttpHeaderNames.Te, HttpHeaderValues.Trailers); } } else { var teValues = StringUtil.UnescapeCsvFields(entry.Value); foreach (var teValue in teValues) { if (AsciiString.ContentEqualsIgnoreCase(AsciiString.Trim(teValue), HttpHeaderValues.Trailers)) { _ = output.Add(HttpHeaderNames.Te, HttpHeaderValues.Trailers); break; } } } }