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 SubSequence() { char[] initChars = { 't', 'h', 'i', 's', ' ', 'i', 's', ' ', 'a', ' ', 't', 'e', 's', 't' }; byte[] init = initChars.Select(c => (byte)c).ToArray(); var ascii = new AsciiString(init); const int Start = 2; int end = init.Length; AsciiString sub1 = ascii.SubSequence(Start, end, false); AsciiString sub2 = ascii.SubSequence(Start, end, true); Assert.Equal(sub1.GetHashCode(), sub2.GetHashCode()); Assert.Equal(sub1, sub2); for (int i = Start; i < end; ++i) { Assert.Equal(init[i], sub1.ByteAt(i - Start)); } }
private static CharSequenceMap <AsciiString> ToLowercaseMap(IEnumerable <ICharSequence> values, int arraySizeHint) { var valueConverter = UnsupportedValueConverter <AsciiString> .Instance; var result = new CharSequenceMap <AsciiString>(true, valueConverter, arraySizeHint); foreach (var item in values) { AsciiString lowerCased = AsciiString.Of(item).ToLowerCase(); try { int index = lowerCased.ForEachByte(ByteProcessor.FindComma); if (index != -1) { int start = 0; do { _ = result.Add(lowerCased.SubSequence(start, index, false).Trim(), AsciiString.Empty); start = index + 1; } while (start < lowerCased.Count && (index = lowerCased.ForEachByte(start, lowerCased.Count - start, ByteProcessor.FindComma)) != -1); _ = result.Add(lowerCased.SubSequence(start, lowerCased.Count, false).Trim(), AsciiString.Empty); } else { _ = result.Add(lowerCased.Trim(), AsciiString.Empty); } } catch (Exception) { // This is not expect to happen because FIND_COMMA never throws but must be caught // because of the ByteProcessor interface. ThrowHelper.ThrowInvalidOperationException(); } } return(result); }
private static int GetChunkSize(AsciiString hex) { hex = hex.Trim(); for (int i = hex.Offset; i < hex.Count; i++) { byte c = hex.Array[i]; if (IsWhiteSpaceOrSemicolonOrISOControl(c)) { hex = (AsciiString)hex.SubSequence(0, i); break; } } return(hex.ParseInt(16)); }
static int GetChunkSize(AsciiString hex) { hex = hex.Trim(); for (int i = hex.Offset; i < hex.Count; i++) { byte c = hex.Array[i]; if (c == ';' || IsWhiteSpace(c) || CharUtil.IsISOControl(c)) { hex = (AsciiString)hex.SubSequence(0, i); break; } } return(hex.ParseInt(16)); }