@@ -6617,7 +6617,7 @@ public unsafe void Append(ReadOnlySpan<byte> name, ReadOnlySpan<byte> value)
66176617 ref StringValues values = ref Unsafe.AsRef<StringValues>(null);
66186618 var flag = 0L;
66196619
6620- // Does the name matched any "known" headers
6620+ // Does the name match any "known" headers
66216621 switch (name.Length)
66226622 {
66236623 case 2:
@@ -7070,6 +7070,251 @@ public unsafe void Append(ReadOnlySpan<byte> name, ReadOnlySpan<byte> value)
70707070 }
70717071 }
70727072
7073+ [MethodImpl(MethodImplOptions.AggressiveOptimization)]
7074+ public unsafe bool TryHPackAppend(int index, ReadOnlySpan<byte> value)
7075+ {
7076+ ref StringValues values = ref Unsafe.AsRef<StringValues>(null);
7077+ var nameStr = string.Empty;
7078+ var flag = 0L;
7079+
7080+ // Does the HPack static index match any "known" headers
7081+ switch (index)
7082+ {
7083+ case 1:
7084+ flag = 0x100000L;
7085+ values = ref _headers._Authority;
7086+ nameStr = HeaderNames.Authority;
7087+ break;
7088+ case 2:
7089+ case 3:
7090+ flag = 0x200000L;
7091+ values = ref _headers._Method;
7092+ nameStr = HeaderNames.Method;
7093+ break;
7094+ case 4:
7095+ case 5:
7096+ flag = 0x400000L;
7097+ values = ref _headers._Path;
7098+ nameStr = HeaderNames.Path;
7099+ break;
7100+ case 6:
7101+ case 7:
7102+ flag = 0x800000L;
7103+ values = ref _headers._Scheme;
7104+ nameStr = HeaderNames.Scheme;
7105+ break;
7106+ case 15:
7107+ flag = 0x2000000L;
7108+ values = ref _headers._AcceptCharset;
7109+ nameStr = HeaderNames.AcceptCharset;
7110+ break;
7111+ case 16:
7112+ flag = 0x4000000L;
7113+ values = ref _headers._AcceptEncoding;
7114+ nameStr = HeaderNames.AcceptEncoding;
7115+ break;
7116+ case 17:
7117+ flag = 0x8000000L;
7118+ values = ref _headers._AcceptLanguage;
7119+ nameStr = HeaderNames.AcceptLanguage;
7120+ break;
7121+ case 19:
7122+ flag = 0x1000000L;
7123+ values = ref _headers._Accept;
7124+ nameStr = HeaderNames.Accept;
7125+ break;
7126+ case 22:
7127+ flag = 0x800L;
7128+ values = ref _headers._Allow;
7129+ nameStr = HeaderNames.Allow;
7130+ break;
7131+ case 23:
7132+ flag = 0x10000000L;
7133+ values = ref _headers._Authorization;
7134+ nameStr = HeaderNames.Authorization;
7135+ break;
7136+ case 24:
7137+ flag = 0x1L;
7138+ values = ref _headers._CacheControl;
7139+ nameStr = HeaderNames.CacheControl;
7140+ break;
7141+ case 26:
7142+ flag = 0x2000L;
7143+ values = ref _headers._ContentEncoding;
7144+ nameStr = HeaderNames.ContentEncoding;
7145+ break;
7146+ case 27:
7147+ flag = 0x4000L;
7148+ values = ref _headers._ContentLanguage;
7149+ nameStr = HeaderNames.ContentLanguage;
7150+ break;
7151+ case 28:
7152+ if (ReferenceEquals(EncodingSelector, KestrelServerOptions.DefaultRequestHeaderEncodingSelector))
7153+ {
7154+ AppendContentLength(value);
7155+ }
7156+ else
7157+ {
7158+ AppendContentLengthCustomEncoding(value, EncodingSelector(HeaderNames.ContentLength));
7159+ }
7160+ return true;
7161+ case 29:
7162+ flag = 0x8000L;
7163+ values = ref _headers._ContentLocation;
7164+ nameStr = HeaderNames.ContentLocation;
7165+ break;
7166+ case 30:
7167+ flag = 0x20000L;
7168+ values = ref _headers._ContentRange;
7169+ nameStr = HeaderNames.ContentRange;
7170+ break;
7171+ case 31:
7172+ flag = 0x1000L;
7173+ values = ref _headers._ContentType;
7174+ nameStr = HeaderNames.ContentType;
7175+ break;
7176+ case 32:
7177+ flag = 0x20000000L;
7178+ values = ref _headers._Cookie;
7179+ nameStr = HeaderNames.Cookie;
7180+ break;
7181+ case 33:
7182+ flag = 0x4L;
7183+ values = ref _headers._Date;
7184+ nameStr = HeaderNames.Date;
7185+ break;
7186+ case 35:
7187+ flag = 0x40000000L;
7188+ values = ref _headers._Expect;
7189+ nameStr = HeaderNames.Expect;
7190+ break;
7191+ case 36:
7192+ flag = 0x40000L;
7193+ values = ref _headers._Expires;
7194+ nameStr = HeaderNames.Expires;
7195+ break;
7196+ case 37:
7197+ flag = 0x80000000L;
7198+ values = ref _headers._From;
7199+ nameStr = HeaderNames.From;
7200+ break;
7201+ case 38:
7202+ flag = 0x400000000L;
7203+ values = ref _headers._Host;
7204+ nameStr = HeaderNames.Host;
7205+ break;
7206+ case 39:
7207+ flag = 0x800000000L;
7208+ values = ref _headers._IfMatch;
7209+ nameStr = HeaderNames.IfMatch;
7210+ break;
7211+ case 40:
7212+ flag = 0x1000000000L;
7213+ values = ref _headers._IfModifiedSince;
7214+ nameStr = HeaderNames.IfModifiedSince;
7215+ break;
7216+ case 41:
7217+ flag = 0x2000000000L;
7218+ values = ref _headers._IfNoneMatch;
7219+ nameStr = HeaderNames.IfNoneMatch;
7220+ break;
7221+ case 42:
7222+ flag = 0x4000000000L;
7223+ values = ref _headers._IfRange;
7224+ nameStr = HeaderNames.IfRange;
7225+ break;
7226+ case 43:
7227+ flag = 0x8000000000L;
7228+ values = ref _headers._IfUnmodifiedSince;
7229+ nameStr = HeaderNames.IfUnmodifiedSince;
7230+ break;
7231+ case 44:
7232+ flag = 0x80000L;
7233+ values = ref _headers._LastModified;
7234+ nameStr = HeaderNames.LastModified;
7235+ break;
7236+ case 47:
7237+ flag = 0x10000000000L;
7238+ values = ref _headers._MaxForwards;
7239+ nameStr = HeaderNames.MaxForwards;
7240+ break;
7241+ case 49:
7242+ flag = 0x20000000000L;
7243+ values = ref _headers._ProxyAuthorization;
7244+ nameStr = HeaderNames.ProxyAuthorization;
7245+ break;
7246+ case 50:
7247+ flag = 0x80000000000L;
7248+ values = ref _headers._Range;
7249+ nameStr = HeaderNames.Range;
7250+ break;
7251+ case 51:
7252+ flag = 0x40000000000L;
7253+ values = ref _headers._Referer;
7254+ nameStr = HeaderNames.Referer;
7255+ break;
7256+ case 57:
7257+ flag = 0x80L;
7258+ values = ref _headers._TransferEncoding;
7259+ nameStr = HeaderNames.TransferEncoding;
7260+ break;
7261+ case 58:
7262+ flag = 0x400000000000L;
7263+ values = ref _headers._UserAgent;
7264+ nameStr = HeaderNames.UserAgent;
7265+ break;
7266+ case 60:
7267+ flag = 0x200L;
7268+ values = ref _headers._Via;
7269+ nameStr = HeaderNames.Via;
7270+ break;
7271+ }
7272+
7273+ if (flag != 0)
7274+ {
7275+ // Matched a known header
7276+ if ((_previousBits & flag) != 0)
7277+ {
7278+ // Had a previous string for this header, mark it as used so we don't clear it OnHeadersComplete or consider it if we get a second header
7279+ _previousBits ^= flag;
7280+
7281+ // We will only reuse this header if there was only one previous header
7282+ if (values.Count == 1)
7283+ {
7284+ var previousValue = values.ToString();
7285+ // Check lengths are the same, then if the bytes were converted to an ascii string if they would be the same.
7286+ // We do not consider Utf8 headers for reuse.
7287+ if (previousValue.Length == value.Length &&
7288+ StringUtilities.BytesOrdinalEqualsStringAndAscii(previousValue, value))
7289+ {
7290+ // The previous string matches what the bytes would convert to, so we will just use that one.
7291+ _bits |= flag;
7292+ return true;
7293+ }
7294+ }
7295+ }
7296+
7297+ // We didn't have a previous matching header value, or have already added a header, so get the string for this value.
7298+ var valueStr = value.GetRequestHeaderString(nameStr, EncodingSelector);
7299+ if ((_bits & flag) == 0)
7300+ {
7301+ // We didn't already have a header set, so add a new one.
7302+ _bits |= flag;
7303+ values = new StringValues(valueStr);
7304+ }
7305+ else
7306+ {
7307+ // We already had a header set, so concatenate the new one.
7308+ values = AppendValue(values, valueStr);
7309+ }
7310+ return true;
7311+ }
7312+ else
7313+ {
7314+ return false;
7315+ }
7316+ }
7317+
70737318 private struct HeaderReferences
70747319 {
70757320 public StringValues _CacheControl;
@@ -13716,4 +13961,4 @@ public bool MoveNext()
1371613961 }
1371713962 }
1371813963 }
13719- }
13964+ }
0 commit comments