diff --git a/src/Servers/Kestrel/Core/src/Internal/Http/HttpHeaders.Generated.cs b/src/Servers/Kestrel/Core/src/Internal/Http/HttpHeaders.Generated.cs index 0f8783e717..516d7c32ec 100644 --- a/src/Servers/Kestrel/Core/src/Internal/Http/HttpHeaders.Generated.cs +++ b/src/Servers/Kestrel/Core/src/Internal/Http/HttpHeaders.Generated.cs @@ -14,6 +14,81 @@ using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure; namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http { + internal enum KnownHeaderType + { + Unknown, + Accept, + AcceptCharset, + AcceptEncoding, + AcceptLanguage, + AcceptRanges, + AccessControlAllowCredentials, + AccessControlAllowHeaders, + AccessControlAllowMethods, + AccessControlAllowOrigin, + AccessControlExposeHeaders, + AccessControlMaxAge, + AccessControlRequestHeaders, + AccessControlRequestMethod, + Age, + Allow, + AltSvc, + Authority, + Authorization, + CacheControl, + Connection, + ContentEncoding, + ContentLanguage, + ContentLength, + ContentLocation, + ContentMD5, + ContentRange, + ContentType, + Cookie, + CorrelationContext, + Date, + DNT, + ETag, + Expect, + Expires, + From, + Host, + IfMatch, + IfModifiedSince, + IfNoneMatch, + IfRange, + IfUnmodifiedSince, + KeepAlive, + LastModified, + Location, + MaxForwards, + Method, + Origin, + Path, + Pragma, + ProxyAuthenticate, + ProxyAuthorization, + Range, + Referer, + RequestId, + RetryAfter, + Scheme, + Server, + SetCookie, + TE, + TraceParent, + TraceState, + Trailer, + TransferEncoding, + Translate, + Upgrade, + UpgradeInsecureRequests, + UserAgent, + Vary, + Via, + Warning, + WWWAuthenticate, + } internal partial class HttpRequestHeaders { @@ -6751,6 +6826,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x1L) != 0) { _current = new KeyValuePair(HeaderNames.CacheControl, _collection._headers._CacheControl); + _currentKnownType = KnownHeaderType.CacheControl; _next = 1; return true; } @@ -6758,6 +6834,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x2L) != 0) { _current = new KeyValuePair(HeaderNames.Connection, _collection._headers._Connection); + _currentKnownType = KnownHeaderType.Connection; _next = 2; return true; } @@ -6765,6 +6842,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x4L) != 0) { _current = new KeyValuePair(HeaderNames.Date, _collection._headers._Date); + _currentKnownType = KnownHeaderType.Date; _next = 3; return true; } @@ -6772,6 +6850,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x8L) != 0) { _current = new KeyValuePair(HeaderNames.KeepAlive, _collection._headers._KeepAlive); + _currentKnownType = KnownHeaderType.KeepAlive; _next = 4; return true; } @@ -6779,6 +6858,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x10L) != 0) { _current = new KeyValuePair(HeaderNames.Pragma, _collection._headers._Pragma); + _currentKnownType = KnownHeaderType.Pragma; _next = 5; return true; } @@ -6786,6 +6866,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x20L) != 0) { _current = new KeyValuePair(HeaderNames.Trailer, _collection._headers._Trailer); + _currentKnownType = KnownHeaderType.Trailer; _next = 6; return true; } @@ -6793,6 +6874,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x40L) != 0) { _current = new KeyValuePair(HeaderNames.TransferEncoding, _collection._headers._TransferEncoding); + _currentKnownType = KnownHeaderType.TransferEncoding; _next = 7; return true; } @@ -6800,6 +6882,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x80L) != 0) { _current = new KeyValuePair(HeaderNames.Upgrade, _collection._headers._Upgrade); + _currentKnownType = KnownHeaderType.Upgrade; _next = 8; return true; } @@ -6807,6 +6890,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x100L) != 0) { _current = new KeyValuePair(HeaderNames.Via, _collection._headers._Via); + _currentKnownType = KnownHeaderType.Via; _next = 9; return true; } @@ -6814,6 +6898,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x200L) != 0) { _current = new KeyValuePair(HeaderNames.Warning, _collection._headers._Warning); + _currentKnownType = KnownHeaderType.Warning; _next = 10; return true; } @@ -6821,6 +6906,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x400L) != 0) { _current = new KeyValuePair(HeaderNames.Allow, _collection._headers._Allow); + _currentKnownType = KnownHeaderType.Allow; _next = 11; return true; } @@ -6828,6 +6914,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x800L) != 0) { _current = new KeyValuePair(HeaderNames.ContentType, _collection._headers._ContentType); + _currentKnownType = KnownHeaderType.ContentType; _next = 12; return true; } @@ -6835,6 +6922,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x1000L) != 0) { _current = new KeyValuePair(HeaderNames.ContentEncoding, _collection._headers._ContentEncoding); + _currentKnownType = KnownHeaderType.ContentEncoding; _next = 13; return true; } @@ -6842,6 +6930,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x2000L) != 0) { _current = new KeyValuePair(HeaderNames.ContentLanguage, _collection._headers._ContentLanguage); + _currentKnownType = KnownHeaderType.ContentLanguage; _next = 14; return true; } @@ -6849,6 +6938,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x4000L) != 0) { _current = new KeyValuePair(HeaderNames.ContentLocation, _collection._headers._ContentLocation); + _currentKnownType = KnownHeaderType.ContentLocation; _next = 15; return true; } @@ -6856,6 +6946,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x8000L) != 0) { _current = new KeyValuePair(HeaderNames.ContentMD5, _collection._headers._ContentMD5); + _currentKnownType = KnownHeaderType.ContentMD5; _next = 16; return true; } @@ -6863,6 +6954,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x10000L) != 0) { _current = new KeyValuePair(HeaderNames.ContentRange, _collection._headers._ContentRange); + _currentKnownType = KnownHeaderType.ContentRange; _next = 17; return true; } @@ -6870,6 +6962,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x20000L) != 0) { _current = new KeyValuePair(HeaderNames.Expires, _collection._headers._Expires); + _currentKnownType = KnownHeaderType.Expires; _next = 18; return true; } @@ -6877,6 +6970,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x40000L) != 0) { _current = new KeyValuePair(HeaderNames.LastModified, _collection._headers._LastModified); + _currentKnownType = KnownHeaderType.LastModified; _next = 19; return true; } @@ -6884,6 +6978,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x80000L) != 0) { _current = new KeyValuePair(HeaderNames.Authority, _collection._headers._Authority); + _currentKnownType = KnownHeaderType.Authority; _next = 20; return true; } @@ -6891,6 +6986,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x100000L) != 0) { _current = new KeyValuePair(HeaderNames.Method, _collection._headers._Method); + _currentKnownType = KnownHeaderType.Method; _next = 21; return true; } @@ -6898,6 +6994,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x200000L) != 0) { _current = new KeyValuePair(HeaderNames.Path, _collection._headers._Path); + _currentKnownType = KnownHeaderType.Path; _next = 22; return true; } @@ -6905,6 +7002,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x400000L) != 0) { _current = new KeyValuePair(HeaderNames.Scheme, _collection._headers._Scheme); + _currentKnownType = KnownHeaderType.Scheme; _next = 23; return true; } @@ -6912,6 +7010,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x800000L) != 0) { _current = new KeyValuePair(HeaderNames.Accept, _collection._headers._Accept); + _currentKnownType = KnownHeaderType.Accept; _next = 24; return true; } @@ -6919,6 +7018,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x1000000L) != 0) { _current = new KeyValuePair(HeaderNames.AcceptCharset, _collection._headers._AcceptCharset); + _currentKnownType = KnownHeaderType.AcceptCharset; _next = 25; return true; } @@ -6926,6 +7026,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x2000000L) != 0) { _current = new KeyValuePair(HeaderNames.AcceptEncoding, _collection._headers._AcceptEncoding); + _currentKnownType = KnownHeaderType.AcceptEncoding; _next = 26; return true; } @@ -6933,6 +7034,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x4000000L) != 0) { _current = new KeyValuePair(HeaderNames.AcceptLanguage, _collection._headers._AcceptLanguage); + _currentKnownType = KnownHeaderType.AcceptLanguage; _next = 27; return true; } @@ -6940,6 +7042,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x8000000L) != 0) { _current = new KeyValuePair(HeaderNames.Authorization, _collection._headers._Authorization); + _currentKnownType = KnownHeaderType.Authorization; _next = 28; return true; } @@ -6947,6 +7050,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x10000000L) != 0) { _current = new KeyValuePair(HeaderNames.Cookie, _collection._headers._Cookie); + _currentKnownType = KnownHeaderType.Cookie; _next = 29; return true; } @@ -6954,6 +7058,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x20000000L) != 0) { _current = new KeyValuePair(HeaderNames.Expect, _collection._headers._Expect); + _currentKnownType = KnownHeaderType.Expect; _next = 30; return true; } @@ -6961,6 +7066,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x40000000L) != 0) { _current = new KeyValuePair(HeaderNames.From, _collection._headers._From); + _currentKnownType = KnownHeaderType.From; _next = 31; return true; } @@ -6968,6 +7074,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x80000000L) != 0) { _current = new KeyValuePair(HeaderNames.Host, _collection._headers._Host); + _currentKnownType = KnownHeaderType.Host; _next = 32; return true; } @@ -6975,6 +7082,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x100000000L) != 0) { _current = new KeyValuePair(HeaderNames.IfMatch, _collection._headers._IfMatch); + _currentKnownType = KnownHeaderType.IfMatch; _next = 33; return true; } @@ -6982,6 +7090,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x200000000L) != 0) { _current = new KeyValuePair(HeaderNames.IfModifiedSince, _collection._headers._IfModifiedSince); + _currentKnownType = KnownHeaderType.IfModifiedSince; _next = 34; return true; } @@ -6989,6 +7098,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x400000000L) != 0) { _current = new KeyValuePair(HeaderNames.IfNoneMatch, _collection._headers._IfNoneMatch); + _currentKnownType = KnownHeaderType.IfNoneMatch; _next = 35; return true; } @@ -6996,6 +7106,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x800000000L) != 0) { _current = new KeyValuePair(HeaderNames.IfRange, _collection._headers._IfRange); + _currentKnownType = KnownHeaderType.IfRange; _next = 36; return true; } @@ -7003,6 +7114,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x1000000000L) != 0) { _current = new KeyValuePair(HeaderNames.IfUnmodifiedSince, _collection._headers._IfUnmodifiedSince); + _currentKnownType = KnownHeaderType.IfUnmodifiedSince; _next = 37; return true; } @@ -7010,6 +7122,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x2000000000L) != 0) { _current = new KeyValuePair(HeaderNames.MaxForwards, _collection._headers._MaxForwards); + _currentKnownType = KnownHeaderType.MaxForwards; _next = 38; return true; } @@ -7017,6 +7130,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x4000000000L) != 0) { _current = new KeyValuePair(HeaderNames.ProxyAuthorization, _collection._headers._ProxyAuthorization); + _currentKnownType = KnownHeaderType.ProxyAuthorization; _next = 39; return true; } @@ -7024,6 +7138,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x8000000000L) != 0) { _current = new KeyValuePair(HeaderNames.Referer, _collection._headers._Referer); + _currentKnownType = KnownHeaderType.Referer; _next = 40; return true; } @@ -7031,6 +7146,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x10000000000L) != 0) { _current = new KeyValuePair(HeaderNames.Range, _collection._headers._Range); + _currentKnownType = KnownHeaderType.Range; _next = 41; return true; } @@ -7038,6 +7154,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x20000000000L) != 0) { _current = new KeyValuePair(HeaderNames.TE, _collection._headers._TE); + _currentKnownType = KnownHeaderType.TE; _next = 42; return true; } @@ -7045,6 +7162,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x40000000000L) != 0) { _current = new KeyValuePair(HeaderNames.Translate, _collection._headers._Translate); + _currentKnownType = KnownHeaderType.Translate; _next = 43; return true; } @@ -7052,6 +7170,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x80000000000L) != 0) { _current = new KeyValuePair(HeaderNames.UserAgent, _collection._headers._UserAgent); + _currentKnownType = KnownHeaderType.UserAgent; _next = 44; return true; } @@ -7059,6 +7178,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x100000000000L) != 0) { _current = new KeyValuePair(HeaderNames.DNT, _collection._headers._DNT); + _currentKnownType = KnownHeaderType.DNT; _next = 45; return true; } @@ -7066,6 +7186,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x200000000000L) != 0) { _current = new KeyValuePair(HeaderNames.UpgradeInsecureRequests, _collection._headers._UpgradeInsecureRequests); + _currentKnownType = KnownHeaderType.UpgradeInsecureRequests; _next = 46; return true; } @@ -7073,6 +7194,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x400000000000L) != 0) { _current = new KeyValuePair(HeaderNames.RequestId, _collection._headers._RequestId); + _currentKnownType = KnownHeaderType.RequestId; _next = 47; return true; } @@ -7080,6 +7202,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x800000000000L) != 0) { _current = new KeyValuePair(HeaderNames.CorrelationContext, _collection._headers._CorrelationContext); + _currentKnownType = KnownHeaderType.CorrelationContext; _next = 48; return true; } @@ -7087,6 +7210,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x1000000000000L) != 0) { _current = new KeyValuePair(HeaderNames.TraceParent, _collection._headers._TraceParent); + _currentKnownType = KnownHeaderType.TraceParent; _next = 49; return true; } @@ -7094,6 +7218,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x2000000000000L) != 0) { _current = new KeyValuePair(HeaderNames.TraceState, _collection._headers._TraceState); + _currentKnownType = KnownHeaderType.TraceState; _next = 50; return true; } @@ -7101,6 +7226,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x4000000000000L) != 0) { _current = new KeyValuePair(HeaderNames.Origin, _collection._headers._Origin); + _currentKnownType = KnownHeaderType.Origin; _next = 51; return true; } @@ -7108,6 +7234,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x8000000000000L) != 0) { _current = new KeyValuePair(HeaderNames.AccessControlRequestMethod, _collection._headers._AccessControlRequestMethod); + _currentKnownType = KnownHeaderType.AccessControlRequestMethod; _next = 52; return true; } @@ -7115,6 +7242,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x10000000000000L) != 0) { _current = new KeyValuePair(HeaderNames.AccessControlRequestHeaders, _collection._headers._AccessControlRequestHeaders); + _currentKnownType = KnownHeaderType.AccessControlRequestHeaders; _next = 53; return true; } @@ -7122,6 +7250,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if (_collection._contentLength.HasValue) { _current = new KeyValuePair(HeaderNames.ContentLength, HeaderUtilities.FormatNonNegativeInt64(_collection._contentLength.Value)); + _currentKnownType = KnownHeaderType.ContentLength; _next = 54; return true; } @@ -7129,9 +7258,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if (!_hasUnknown || !_unknownEnumerator.MoveNext()) { _current = default(KeyValuePair); + _currentKnownType = default; return false; } _current = _unknownEnumerator.Current; + _currentKnownType = KnownHeaderType.Unknown; return true; } } @@ -12161,6 +12292,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x1L) != 0) { _current = new KeyValuePair(HeaderNames.CacheControl, _collection._headers._CacheControl); + _currentKnownType = KnownHeaderType.CacheControl; _next = 1; return true; } @@ -12168,6 +12300,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x2L) != 0) { _current = new KeyValuePair(HeaderNames.Connection, _collection._headers._Connection); + _currentKnownType = KnownHeaderType.Connection; _next = 2; return true; } @@ -12175,6 +12308,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x4L) != 0) { _current = new KeyValuePair(HeaderNames.Date, _collection._headers._Date); + _currentKnownType = KnownHeaderType.Date; _next = 3; return true; } @@ -12182,6 +12316,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x8L) != 0) { _current = new KeyValuePair(HeaderNames.KeepAlive, _collection._headers._KeepAlive); + _currentKnownType = KnownHeaderType.KeepAlive; _next = 4; return true; } @@ -12189,6 +12324,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x10L) != 0) { _current = new KeyValuePair(HeaderNames.Pragma, _collection._headers._Pragma); + _currentKnownType = KnownHeaderType.Pragma; _next = 5; return true; } @@ -12196,6 +12332,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x20L) != 0) { _current = new KeyValuePair(HeaderNames.Trailer, _collection._headers._Trailer); + _currentKnownType = KnownHeaderType.Trailer; _next = 6; return true; } @@ -12203,6 +12340,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x40L) != 0) { _current = new KeyValuePair(HeaderNames.TransferEncoding, _collection._headers._TransferEncoding); + _currentKnownType = KnownHeaderType.TransferEncoding; _next = 7; return true; } @@ -12210,6 +12348,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x80L) != 0) { _current = new KeyValuePair(HeaderNames.Upgrade, _collection._headers._Upgrade); + _currentKnownType = KnownHeaderType.Upgrade; _next = 8; return true; } @@ -12217,6 +12356,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x100L) != 0) { _current = new KeyValuePair(HeaderNames.Via, _collection._headers._Via); + _currentKnownType = KnownHeaderType.Via; _next = 9; return true; } @@ -12224,6 +12364,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x200L) != 0) { _current = new KeyValuePair(HeaderNames.Warning, _collection._headers._Warning); + _currentKnownType = KnownHeaderType.Warning; _next = 10; return true; } @@ -12231,6 +12372,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x400L) != 0) { _current = new KeyValuePair(HeaderNames.Allow, _collection._headers._Allow); + _currentKnownType = KnownHeaderType.Allow; _next = 11; return true; } @@ -12238,6 +12380,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x800L) != 0) { _current = new KeyValuePair(HeaderNames.ContentType, _collection._headers._ContentType); + _currentKnownType = KnownHeaderType.ContentType; _next = 12; return true; } @@ -12245,6 +12388,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x1000L) != 0) { _current = new KeyValuePair(HeaderNames.ContentEncoding, _collection._headers._ContentEncoding); + _currentKnownType = KnownHeaderType.ContentEncoding; _next = 13; return true; } @@ -12252,6 +12396,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x2000L) != 0) { _current = new KeyValuePair(HeaderNames.ContentLanguage, _collection._headers._ContentLanguage); + _currentKnownType = KnownHeaderType.ContentLanguage; _next = 14; return true; } @@ -12259,6 +12404,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x4000L) != 0) { _current = new KeyValuePair(HeaderNames.ContentLocation, _collection._headers._ContentLocation); + _currentKnownType = KnownHeaderType.ContentLocation; _next = 15; return true; } @@ -12266,6 +12412,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x8000L) != 0) { _current = new KeyValuePair(HeaderNames.ContentMD5, _collection._headers._ContentMD5); + _currentKnownType = KnownHeaderType.ContentMD5; _next = 16; return true; } @@ -12273,6 +12420,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x10000L) != 0) { _current = new KeyValuePair(HeaderNames.ContentRange, _collection._headers._ContentRange); + _currentKnownType = KnownHeaderType.ContentRange; _next = 17; return true; } @@ -12280,6 +12428,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x20000L) != 0) { _current = new KeyValuePair(HeaderNames.Expires, _collection._headers._Expires); + _currentKnownType = KnownHeaderType.Expires; _next = 18; return true; } @@ -12287,6 +12436,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x40000L) != 0) { _current = new KeyValuePair(HeaderNames.LastModified, _collection._headers._LastModified); + _currentKnownType = KnownHeaderType.LastModified; _next = 19; return true; } @@ -12294,6 +12444,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x80000L) != 0) { _current = new KeyValuePair(HeaderNames.AcceptRanges, _collection._headers._AcceptRanges); + _currentKnownType = KnownHeaderType.AcceptRanges; _next = 20; return true; } @@ -12301,6 +12452,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x100000L) != 0) { _current = new KeyValuePair(HeaderNames.Age, _collection._headers._Age); + _currentKnownType = KnownHeaderType.Age; _next = 21; return true; } @@ -12308,6 +12460,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x200000L) != 0) { _current = new KeyValuePair(HeaderNames.AltSvc, _collection._headers._AltSvc); + _currentKnownType = KnownHeaderType.AltSvc; _next = 22; return true; } @@ -12315,6 +12468,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x400000L) != 0) { _current = new KeyValuePair(HeaderNames.ETag, _collection._headers._ETag); + _currentKnownType = KnownHeaderType.ETag; _next = 23; return true; } @@ -12322,6 +12476,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x800000L) != 0) { _current = new KeyValuePair(HeaderNames.Location, _collection._headers._Location); + _currentKnownType = KnownHeaderType.Location; _next = 24; return true; } @@ -12329,6 +12484,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x1000000L) != 0) { _current = new KeyValuePair(HeaderNames.ProxyAuthenticate, _collection._headers._ProxyAuthenticate); + _currentKnownType = KnownHeaderType.ProxyAuthenticate; _next = 25; return true; } @@ -12336,6 +12492,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x2000000L) != 0) { _current = new KeyValuePair(HeaderNames.RetryAfter, _collection._headers._RetryAfter); + _currentKnownType = KnownHeaderType.RetryAfter; _next = 26; return true; } @@ -12343,6 +12500,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x4000000L) != 0) { _current = new KeyValuePair(HeaderNames.Server, _collection._headers._Server); + _currentKnownType = KnownHeaderType.Server; _next = 27; return true; } @@ -12350,6 +12508,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x8000000L) != 0) { _current = new KeyValuePair(HeaderNames.SetCookie, _collection._headers._SetCookie); + _currentKnownType = KnownHeaderType.SetCookie; _next = 28; return true; } @@ -12357,6 +12516,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x10000000L) != 0) { _current = new KeyValuePair(HeaderNames.Vary, _collection._headers._Vary); + _currentKnownType = KnownHeaderType.Vary; _next = 29; return true; } @@ -12364,6 +12524,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x20000000L) != 0) { _current = new KeyValuePair(HeaderNames.WWWAuthenticate, _collection._headers._WWWAuthenticate); + _currentKnownType = KnownHeaderType.WWWAuthenticate; _next = 30; return true; } @@ -12371,6 +12532,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x40000000L) != 0) { _current = new KeyValuePair(HeaderNames.AccessControlAllowCredentials, _collection._headers._AccessControlAllowCredentials); + _currentKnownType = KnownHeaderType.AccessControlAllowCredentials; _next = 31; return true; } @@ -12378,6 +12540,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x80000000L) != 0) { _current = new KeyValuePair(HeaderNames.AccessControlAllowHeaders, _collection._headers._AccessControlAllowHeaders); + _currentKnownType = KnownHeaderType.AccessControlAllowHeaders; _next = 32; return true; } @@ -12385,6 +12548,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x100000000L) != 0) { _current = new KeyValuePair(HeaderNames.AccessControlAllowMethods, _collection._headers._AccessControlAllowMethods); + _currentKnownType = KnownHeaderType.AccessControlAllowMethods; _next = 33; return true; } @@ -12392,6 +12556,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x200000000L) != 0) { _current = new KeyValuePair(HeaderNames.AccessControlAllowOrigin, _collection._headers._AccessControlAllowOrigin); + _currentKnownType = KnownHeaderType.AccessControlAllowOrigin; _next = 34; return true; } @@ -12399,6 +12564,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x400000000L) != 0) { _current = new KeyValuePair(HeaderNames.AccessControlExposeHeaders, _collection._headers._AccessControlExposeHeaders); + _currentKnownType = KnownHeaderType.AccessControlExposeHeaders; _next = 35; return true; } @@ -12406,6 +12572,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x800000000L) != 0) { _current = new KeyValuePair(HeaderNames.AccessControlMaxAge, _collection._headers._AccessControlMaxAge); + _currentKnownType = KnownHeaderType.AccessControlMaxAge; _next = 36; return true; } @@ -12413,6 +12580,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if (_collection._contentLength.HasValue) { _current = new KeyValuePair(HeaderNames.ContentLength, HeaderUtilities.FormatNonNegativeInt64(_collection._contentLength.Value)); + _currentKnownType = KnownHeaderType.ContentLength; _next = 37; return true; } @@ -12420,9 +12588,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if (!_hasUnknown || !_unknownEnumerator.MoveNext()) { _current = default(KeyValuePair); + _currentKnownType = default; return false; } _current = _unknownEnumerator.Current; + _currentKnownType = KnownHeaderType.Unknown; return true; } } @@ -12668,6 +12838,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if ((_bits & 0x1L) != 0) { _current = new KeyValuePair(HeaderNames.ETag, _collection._headers._ETag); + _currentKnownType = KnownHeaderType.ETag; _next = 1; return true; } @@ -12676,9 +12847,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if (!_hasUnknown || !_unknownEnumerator.MoveNext()) { _current = default(KeyValuePair); + _currentKnownType = default; return false; } _current = _unknownEnumerator.Current; + _currentKnownType = KnownHeaderType.Unknown; return true; } } diff --git a/src/Servers/Kestrel/Core/src/Internal/Http/HttpRequestHeaders.cs b/src/Servers/Kestrel/Core/src/Internal/Http/HttpRequestHeaders.cs index f22588078c..a5e78a4442 100644 --- a/src/Servers/Kestrel/Core/src/Internal/Http/HttpRequestHeaders.cs +++ b/src/Servers/Kestrel/Core/src/Internal/Http/HttpRequestHeaders.cs @@ -127,6 +127,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http private readonly long _bits; private int _next; private KeyValuePair _current; + private KnownHeaderType _currentKnownType; private readonly bool _hasUnknown; private Dictionary.Enumerator _unknownEnumerator; @@ -136,6 +137,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http _bits = collection._bits; _next = 0; _current = default; + _currentKnownType = default; _hasUnknown = collection.MaybeUnknown != null; _unknownEnumerator = _hasUnknown ? collection.MaybeUnknown.GetEnumerator() @@ -144,6 +146,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http public KeyValuePair Current => _current; + internal KnownHeaderType CurrentKnownType => _currentKnownType; + object IEnumerator.Current => _current; public void Dispose() diff --git a/src/Servers/Kestrel/Core/src/Internal/Http/HttpResponseHeaders.cs b/src/Servers/Kestrel/Core/src/Internal/Http/HttpResponseHeaders.cs index f2100b0cd8..e2ae921259 100644 --- a/src/Servers/Kestrel/Core/src/Internal/Http/HttpResponseHeaders.cs +++ b/src/Servers/Kestrel/Core/src/Internal/Http/HttpResponseHeaders.cs @@ -94,6 +94,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http private readonly long _bits; private int _next; private KeyValuePair _current; + private KnownHeaderType _currentKnownType; private readonly bool _hasUnknown; private Dictionary.Enumerator _unknownEnumerator; @@ -103,6 +104,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http _bits = collection._bits; _next = 0; _current = default; + _currentKnownType = default; _hasUnknown = collection.MaybeUnknown != null; _unknownEnumerator = _hasUnknown ? collection.MaybeUnknown.GetEnumerator() @@ -111,6 +113,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http public KeyValuePair Current => _current; + internal KnownHeaderType CurrentKnownType => _currentKnownType; + object IEnumerator.Current => _current; public void Dispose() diff --git a/src/Servers/Kestrel/Core/src/Internal/Http/HttpResponseTrailers.cs b/src/Servers/Kestrel/Core/src/Internal/Http/HttpResponseTrailers.cs index ec4144cc83..6bae47c690 100644 --- a/src/Servers/Kestrel/Core/src/Internal/Http/HttpResponseTrailers.cs +++ b/src/Servers/Kestrel/Core/src/Internal/Http/HttpResponseTrailers.cs @@ -43,6 +43,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http private readonly long _bits; private int _next; private KeyValuePair _current; + private KnownHeaderType _currentKnownType; private readonly bool _hasUnknown; private Dictionary.Enumerator _unknownEnumerator; @@ -52,6 +53,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http _bits = collection._bits; _next = 0; _current = default; + _currentKnownType = default; _hasUnknown = collection.MaybeUnknown != null; _unknownEnumerator = _hasUnknown ? collection.MaybeUnknown.GetEnumerator() @@ -60,6 +62,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http public KeyValuePair Current => _current; + internal KnownHeaderType CurrentKnownType => _currentKnownType; + object IEnumerator.Current => _current; public void Dispose() diff --git a/src/Servers/Kestrel/Core/src/Internal/Http2/HPackHeaderWriter.cs b/src/Servers/Kestrel/Core/src/Internal/Http2/HPackHeaderWriter.cs new file mode 100644 index 0000000000..1598a18c7f --- /dev/null +++ b/src/Servers/Kestrel/Core/src/Internal/Http2/HPackHeaderWriter.cs @@ -0,0 +1,157 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Net.Http; +using System.Net.Http.HPack; +using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http; + +namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2 +{ + internal static class HPackHeaderWriter + { + /// + /// Begin encoding headers in the first HEADERS frame. + /// + public static bool BeginEncodeHeaders(int statusCode, Http2HeadersEnumerator headersEnumerator, Span buffer, out int length) + { + if (!HPackEncoder.EncodeStatusHeader(statusCode, buffer, out var statusCodeLength)) + { + throw new HPackEncodingException(SR.net_http_hpack_encode_failure); + } + + if (!headersEnumerator.MoveNext()) + { + length = statusCodeLength; + return true; + } + + // We're ok with not throwing if no headers were encoded because we've already encoded the status. + // There is a small chance that the header will encode if there is no other content in the next HEADERS frame. + var done = EncodeHeaders(headersEnumerator, buffer.Slice(statusCodeLength), throwIfNoneEncoded: false, out var headersLength); + length = statusCodeLength + headersLength; + + return done; + } + + /// + /// Begin encoding headers in the first HEADERS frame. + /// + public static bool BeginEncodeHeaders(Http2HeadersEnumerator headersEnumerator, Span buffer, out int length) + { + if (!headersEnumerator.MoveNext()) + { + length = 0; + return true; + } + + return EncodeHeaders(headersEnumerator, buffer, throwIfNoneEncoded: true, out length); + } + + /// + /// Continue encoding headers in the next HEADERS frame. The enumerator should already have a current value. + /// + public static bool ContinueEncodeHeaders(Http2HeadersEnumerator headersEnumerator, Span buffer, out int length) + { + return EncodeHeaders(headersEnumerator, buffer, throwIfNoneEncoded: true, out length); + } + + private static bool EncodeHeaders(Http2HeadersEnumerator headersEnumerator, Span buffer, bool throwIfNoneEncoded, out int length) + { + var currentLength = 0; + do + { + if (!EncodeHeader(headersEnumerator.KnownHeaderType, headersEnumerator.Current.Key, headersEnumerator.Current.Value, buffer.Slice(currentLength), out int headerLength)) + { + // The the header wasn't written and no headers have been written then the header is too large. + // Throw an error to avoid an infinite loop of attempting to write large header. + if (currentLength == 0 && throwIfNoneEncoded) + { + throw new HPackEncodingException(SR.net_http_hpack_encode_failure); + } + + length = currentLength; + return false; + } + + currentLength += headerLength; + } + while (headersEnumerator.MoveNext()); + + length = currentLength; + + return true; + } + + private static bool EncodeHeader(KnownHeaderType knownHeaderType, string name, string value, Span buffer, out int length) + { + var hPackStaticTableId = GetResponseHeaderStaticTableId(knownHeaderType); + + if (hPackStaticTableId == -1) + { + return HPackEncoder.EncodeLiteralHeaderFieldWithoutIndexingNewName(name, value, buffer, out length); + } + else + { + return HPackEncoder.EncodeLiteralHeaderFieldWithoutIndexing(hPackStaticTableId, value, buffer, out length); + } + } + + private static int GetResponseHeaderStaticTableId(KnownHeaderType responseHeaderType) + { + switch (responseHeaderType) + { + case KnownHeaderType.CacheControl: + return H2StaticTable.CacheControl; + case KnownHeaderType.Date: + return H2StaticTable.Date; + case KnownHeaderType.TransferEncoding: + return H2StaticTable.TransferEncoding; + case KnownHeaderType.Via: + return H2StaticTable.Via; + case KnownHeaderType.Allow: + return H2StaticTable.Allow; + case KnownHeaderType.ContentType: + return H2StaticTable.ContentType; + case KnownHeaderType.ContentEncoding: + return H2StaticTable.ContentEncoding; + case KnownHeaderType.ContentLanguage: + return H2StaticTable.ContentLanguage; + case KnownHeaderType.ContentLocation: + return H2StaticTable.ContentLocation; + case KnownHeaderType.ContentRange: + return H2StaticTable.ContentRange; + case KnownHeaderType.Expires: + return H2StaticTable.Expires; + case KnownHeaderType.LastModified: + return H2StaticTable.LastModified; + case KnownHeaderType.AcceptRanges: + return H2StaticTable.AcceptRanges; + case KnownHeaderType.Age: + return H2StaticTable.Age; + case KnownHeaderType.ETag: + return H2StaticTable.ETag; + case KnownHeaderType.Location: + return H2StaticTable.Location; + case KnownHeaderType.ProxyAuthenticate: + return H2StaticTable.ProxyAuthenticate; + case KnownHeaderType.RetryAfter: + return H2StaticTable.RetryAfter; + case KnownHeaderType.Server: + return H2StaticTable.Server; + case KnownHeaderType.SetCookie: + return H2StaticTable.SetCookie; + case KnownHeaderType.Vary: + return H2StaticTable.Vary; + case KnownHeaderType.WWWAuthenticate: + return H2StaticTable.WwwAuthenticate; + case KnownHeaderType.AccessControlAllowOrigin: + return H2StaticTable.AccessControlAllowOrigin; + case KnownHeaderType.ContentLength: + return H2StaticTable.ContentLength; + default: + return -1; + } + } + } +} diff --git a/src/Servers/Kestrel/Core/src/Internal/Http2/Http2FrameWriter.cs b/src/Servers/Kestrel/Core/src/Internal/Http2/Http2FrameWriter.cs index 8336fdf23b..2d50e71d5f 100644 --- a/src/Servers/Kestrel/Core/src/Internal/Http2/Http2FrameWriter.cs +++ b/src/Servers/Kestrel/Core/src/Internal/Http2/Http2FrameWriter.cs @@ -7,6 +7,7 @@ using System.Buffers.Binary; using System.Collections.Generic; using System.Diagnostics; using System.IO.Pipelines; +using System.Net.Http; using System.Net.Http.HPack; using System.Threading; using System.Threading.Tasks; @@ -27,7 +28,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2 private readonly object _writeLock = new object(); private readonly Http2Frame _outgoingFrame; - private readonly HPackEncoder _hpackEncoder = new HPackEncoder(); private readonly Http2HeadersEnumerator _headersEnumerator = new Http2HeadersEnumerator(); private readonly ConcurrentPipeWriter _outputWriter; private readonly ConnectionContext _connectionContext; @@ -175,7 +175,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2 _headersEnumerator.Initialize(headers); _outgoingFrame.PrepareHeaders(headerFrameFlags, streamId); var buffer = _headerEncodingBuffer.AsSpan(); - var done = _hpackEncoder.BeginEncode(statusCode, _headersEnumerator, buffer, out var payloadLength); + var done = HPackHeaderWriter.BeginEncodeHeaders(statusCode, _headersEnumerator, buffer, out var payloadLength); FinishWritingHeaders(streamId, payloadLength, done); } catch (HPackEncodingException hex) @@ -201,7 +201,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2 _headersEnumerator.Initialize(headers); _outgoingFrame.PrepareHeaders(Http2HeadersFrameFlags.END_STREAM, streamId); var buffer = _headerEncodingBuffer.AsSpan(); - var done = _hpackEncoder.BeginEncode(_headersEnumerator, buffer, out var payloadLength); + var done = HPackHeaderWriter.BeginEncodeHeaders(_headersEnumerator, buffer, out var payloadLength); FinishWritingHeaders(streamId, payloadLength, done); } catch (HPackEncodingException hex) @@ -230,7 +230,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2 { _outgoingFrame.PrepareContinuation(Http2ContinuationFrameFlags.NONE, streamId); - done = _hpackEncoder.Encode(buffer, out payloadLength); + done = HPackHeaderWriter.ContinueEncodeHeaders(_headersEnumerator, buffer, out payloadLength); _outgoingFrame.PayloadLength = payloadLength; if (done) diff --git a/src/Servers/Kestrel/Core/src/Internal/Http2/Http2HeaderEnumerator.cs b/src/Servers/Kestrel/Core/src/Internal/Http2/Http2HeaderEnumerator.cs index bd5ec3c449..421650b9fd 100644 --- a/src/Servers/Kestrel/Core/src/Internal/Http2/Http2HeaderEnumerator.cs +++ b/src/Servers/Kestrel/Core/src/Internal/Http2/Http2HeaderEnumerator.cs @@ -16,6 +16,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2 private IEnumerator> _genericEnumerator; private StringValues.Enumerator _stringValuesEnumerator; + public KnownHeaderType KnownHeaderType { get; private set; } public KeyValuePair Current { get; private set; } object IEnumerator.Current => Current; @@ -32,6 +33,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2 _stringValuesEnumerator = default; Current = default; + KnownHeaderType = default; } public void Initialize(HttpResponseTrailers headers) @@ -43,6 +45,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2 _stringValuesEnumerator = default; Current = default; + KnownHeaderType = default; } public void Initialize(IDictionary headers) @@ -54,6 +57,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2 _stringValuesEnumerator = default; Current = default; + KnownHeaderType = default; } public bool MoveNext() @@ -106,6 +110,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2 else { enumerator = _genericEnumerator.Current.Value.GetEnumerator(); + KnownHeaderType = default; return true; } } @@ -119,6 +124,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2 else { enumerator = _trailersEnumerator.Current.Value.GetEnumerator(); + KnownHeaderType = _trailersEnumerator.CurrentKnownType; return true; } } @@ -132,6 +138,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2 else { enumerator = _headersEnumerator.Current.Value.GetEnumerator(); + KnownHeaderType = _headersEnumerator.CurrentKnownType; return true; } } @@ -152,6 +159,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2 _headersEnumerator.Reset(); } _stringValuesEnumerator = default; + KnownHeaderType = default; } public void Dispose() diff --git a/src/Servers/Kestrel/Core/test/HPackEncoderTests.cs b/src/Servers/Kestrel/Core/test/HPackHeaderWriterTests.cs similarity index 89% rename from src/Servers/Kestrel/Core/test/HPackEncoderTests.cs rename to src/Servers/Kestrel/Core/test/HPackHeaderWriterTests.cs index c755292753..3b290d712b 100644 --- a/src/Servers/Kestrel/Core/test/HPackEncoderTests.cs +++ b/src/Servers/Kestrel/Core/test/HPackHeaderWriterTests.cs @@ -3,17 +3,14 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; -using System.Net.Http.HPack; -using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2; using Microsoft.Extensions.Primitives; using Xunit; namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests { - public class HPackEncoderTests + public class HPackHeaderWriterTests { public static TheoryData[], byte[], int?> SinglePayloadData { @@ -94,16 +91,15 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests [MemberData(nameof(SinglePayloadData))] public void EncodesHeadersInSinglePayloadWhenSpaceAvailable(KeyValuePair[] headers, byte[] expectedPayload, int? statusCode) { - var encoder = new HPackEncoder(); var payload = new byte[1024]; var length = 0; if (statusCode.HasValue) { - Assert.True(encoder.BeginEncode(statusCode.Value, GetHeadersEnumerator(headers), payload, out length)); + Assert.True(HPackHeaderWriter.BeginEncodeHeaders(statusCode.Value, GetHeadersEnumerator(headers), payload, out length)); } else { - Assert.True(encoder.BeginEncode(GetHeadersEnumerator(headers), payload, out length)); + Assert.True(HPackHeaderWriter.BeginEncodeHeaders(GetHeadersEnumerator(headers), payload, out length)); } Assert.Equal(expectedPayload.Length, length); @@ -120,10 +116,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests [InlineData(false)] public void EncodesHeadersInMultiplePayloadsWhenSpaceNotAvailable(bool exactSize) { - var encoder = new HPackEncoder(); - var statusCode = 200; - var headers = new [] + var headers = new[] { new KeyValuePair("date", "Mon, 24 Jul 2017 19:22:30 GMT"), new KeyValuePair("content-type", "text/html; charset=utf-8"), @@ -161,31 +155,32 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests Span payload = new byte[1024]; var offset = 0; + var headerEnumerator = GetHeadersEnumerator(headers); // When !exactSize, slices are one byte short of fitting the next header var sliceLength = expectedStatusCodePayload.Length + (exactSize ? 0 : expectedDateHeaderPayload.Length - 1); - Assert.False(encoder.BeginEncode(statusCode, GetHeadersEnumerator(headers), payload.Slice(offset, sliceLength), out var length)); + Assert.False(HPackHeaderWriter.BeginEncodeHeaders(statusCode, headerEnumerator, payload.Slice(offset, sliceLength), out var length)); Assert.Equal(expectedStatusCodePayload.Length, length); Assert.Equal(expectedStatusCodePayload, payload.Slice(0, length).ToArray()); offset += length; sliceLength = expectedDateHeaderPayload.Length + (exactSize ? 0 : expectedContentTypeHeaderPayload.Length - 1); - Assert.False(encoder.Encode(payload.Slice(offset, sliceLength), out length)); + Assert.False(HPackHeaderWriter.ContinueEncodeHeaders(headerEnumerator, payload.Slice(offset, sliceLength), out length)); Assert.Equal(expectedDateHeaderPayload.Length, length); Assert.Equal(expectedDateHeaderPayload, payload.Slice(offset, length).ToArray()); offset += length; sliceLength = expectedContentTypeHeaderPayload.Length + (exactSize ? 0 : expectedServerHeaderPayload.Length - 1); - Assert.False(encoder.Encode(payload.Slice(offset, sliceLength), out length)); + Assert.False(HPackHeaderWriter.ContinueEncodeHeaders(headerEnumerator, payload.Slice(offset, sliceLength), out length)); Assert.Equal(expectedContentTypeHeaderPayload.Length, length); Assert.Equal(expectedContentTypeHeaderPayload, payload.Slice(offset, length).ToArray()); offset += length; sliceLength = expectedServerHeaderPayload.Length; - Assert.True(encoder.Encode(payload.Slice(offset, sliceLength), out length)); + Assert.True(HPackHeaderWriter.ContinueEncodeHeaders(headerEnumerator, payload.Slice(offset, sliceLength), out length)); Assert.Equal(expectedServerHeaderPayload.Length, length); Assert.Equal(expectedServerHeaderPayload, payload.Slice(offset, length).ToArray()); } diff --git a/src/Servers/Kestrel/perf/Kestrel.Performance/Http2ConnectionBenchmark.cs b/src/Servers/Kestrel/perf/Kestrel.Performance/Http2ConnectionBenchmark.cs index 1438fb5379..3018f4a346 100644 --- a/src/Servers/Kestrel/perf/Kestrel.Performance/Http2ConnectionBenchmark.cs +++ b/src/Servers/Kestrel/perf/Kestrel.Performance/Http2ConnectionBenchmark.cs @@ -30,7 +30,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance private Http2Connection _connection; private Http2HeadersEnumerator _requestHeadersEnumerator; private int _currentStreamId; - private HPackEncoder _hpackEncoder; private byte[] _headersBuffer; [GlobalSetup] @@ -47,7 +46,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance _httpRequestHeaders.Append(HeaderNames.Scheme, new StringValues("http")); _httpRequestHeaders.Append(HeaderNames.Authority, new StringValues("localhost:80")); - _hpackEncoder = new HPackEncoder(); _headersBuffer = new byte[1024 * 16]; var serviceContext = new ServiceContext @@ -78,7 +76,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance _ = _connection.ProcessRequestsAsync(new DummyApplication()); _pipe.Writer.Write(Http2Connection.ClientPreface); - PipeWriterHttp2FrameExtensions.WriteSettings(_pipe.Writer, new Http2PeerSettings()); + _pipe.Writer.WriteSettings(new Http2PeerSettings()); _pipe.Writer.FlushAsync().GetAwaiter().GetResult(); } @@ -86,7 +84,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance public async Task EmptyRequest() { _requestHeadersEnumerator.Initialize(_httpRequestHeaders); - PipeWriterHttp2FrameExtensions.WriteStartStream(_pipe.Writer, streamId: _currentStreamId, _requestHeadersEnumerator, _hpackEncoder, _headersBuffer, endStream: true); + _requestHeadersEnumerator.MoveNext(); + _pipe.Writer.WriteStartStream(streamId: _currentStreamId, _requestHeadersEnumerator, _headersBuffer, endStream: true); _currentStreamId += 2; await _pipe.Writer.FlushAsync(); } diff --git a/src/Servers/Kestrel/shared/KnownHeaders.cs b/src/Servers/Kestrel/shared/KnownHeaders.cs index ec81326e68..e6389a675e 100644 --- a/src/Servers/Kestrel/shared/KnownHeaders.cs +++ b/src/Servers/Kestrel/shared/KnownHeaders.cs @@ -562,6 +562,9 @@ namespace CodeGenerator var responseTrailers = ResponseTrailers; + var allHeaderNames = RequestHeaders.Concat(ResponseHeaders).Concat(ResponseTrailers) + .Select(h => h.Identifier).Distinct().OrderBy(n => n).ToArray(); + var loops = new[] { new @@ -612,6 +615,11 @@ using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure; namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http {{ + internal enum KnownHeaderType + {{ + Unknown,{Each(allHeaderNames, n => @" + " + n + ",")} + }} {Each(loops, loop => $@" internal partial class {loop.ClassName} {{{(loop.Bytes != null ? @@ -1058,6 +1066,7 @@ $@" private void Clear(long bitsToClear) if ({header.TestBit()}) {{ _current = new KeyValuePair(HeaderNames.{header.Identifier}, _collection._headers._{header.Identifier}); + _currentKnownType = KnownHeaderType.{header.Identifier}; _next = {header.Index + 1}; return true; }}")} @@ -1065,6 +1074,7 @@ $@" private void Clear(long bitsToClear) if (_collection._contentLength.HasValue) {{ _current = new KeyValuePair(HeaderNames.ContentLength, HeaderUtilities.FormatNonNegativeInt64(_collection._contentLength.Value)); + _currentKnownType = KnownHeaderType.ContentLength; _next = {loop.Headers.Count()}; return true; }}" : "")} @@ -1072,9 +1082,11 @@ $@" private void Clear(long bitsToClear) if (!_hasUnknown || !_unknownEnumerator.MoveNext()) {{ _current = default(KeyValuePair); + _currentKnownType = default; return false; }} _current = _unknownEnumerator.Current; + _currentKnownType = KnownHeaderType.Unknown; return true; }} }} diff --git a/src/Servers/Kestrel/shared/test/PipeWriterHttp2FrameExtensions.cs b/src/Servers/Kestrel/shared/test/PipeWriterHttp2FrameExtensions.cs index beb76e1c55..daf333e703 100644 --- a/src/Servers/Kestrel/shared/test/PipeWriterHttp2FrameExtensions.cs +++ b/src/Servers/Kestrel/shared/test/PipeWriterHttp2FrameExtensions.cs @@ -24,13 +24,13 @@ namespace Microsoft.AspNetCore.Testing writer.Write(payload); } - public static void WriteStartStream(this PipeWriter writer, int streamId, Http2HeadersEnumerator headers, HPackEncoder hpackEncoder, byte[] headerEncodingBuffer, bool endStream) + public static void WriteStartStream(this PipeWriter writer, int streamId, Http2HeadersEnumerator headers, byte[] headerEncodingBuffer, bool endStream) { var frame = new Http2Frame(); frame.PrepareHeaders(Http2HeadersFrameFlags.NONE, streamId); var buffer = headerEncodingBuffer.AsSpan(); - var done = hpackEncoder.BeginEncode(headers, buffer, out var length); + var done = HPackHeaderWriter.BeginEncodeHeaders(headers, buffer, out var length); frame.PayloadLength = length; if (done) @@ -50,7 +50,7 @@ namespace Microsoft.AspNetCore.Testing { frame.PrepareContinuation(Http2ContinuationFrameFlags.NONE, streamId); - done = hpackEncoder.Encode(buffer, out length); + done = HPackHeaderWriter.ContinueEncodeHeaders(headers, buffer, out length); frame.PayloadLength = length; if (done) @@ -63,6 +63,22 @@ namespace Microsoft.AspNetCore.Testing } } + public static void WriteStartStream(this PipeWriter writer, int streamId, Span headerData, bool endStream) + { + var frame = new Http2Frame(); + frame.PrepareHeaders(Http2HeadersFrameFlags.NONE, streamId); + frame.PayloadLength = headerData.Length; + frame.HeadersFlags = Http2HeadersFrameFlags.END_HEADERS; + + if (endStream) + { + frame.HeadersFlags |= Http2HeadersFrameFlags.END_STREAM; + } + + Http2FrameWriter.WriteHeader(frame, writer); + writer.Write(headerData); + } + public static void WriteData(this PipeWriter writer, int streamId, Memory data, bool endStream) { var frame = new Http2Frame(); diff --git a/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2ConnectionTests.cs b/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2ConnectionTests.cs index 7d93bdce3a..310398d00e 100644 --- a/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2ConnectionTests.cs +++ b/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2ConnectionTests.cs @@ -42,7 +42,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, requestHeaders, endStream: true); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -61,7 +61,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(3, requestHeaders, endStream: true); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 3); @@ -82,7 +82,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, _browserRequestHeaders, endStream: true); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -112,7 +112,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendDataAsync(1, _helloBytes, endStream: true); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); await ExpectAsync(Http2FrameType.DATA, @@ -127,7 +127,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendDataAsync(3, _helloBytes, endStream: true); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 3); await ExpectAsync(Http2FrameType.DATA, @@ -171,7 +171,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests appDelegateTcs.TrySetResult(null); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -194,7 +194,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests appDelegateTcs.TrySetResult(null); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 3); @@ -304,7 +304,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendDataAsync(1, new byte[length], endStream: true); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); // The client's settings is still defaulted to Http2PeerSettings.MinAllowedMaxFrameSize so the echo response will come back in two separate frames @@ -333,7 +333,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendDataAsync(1, _helloWorldBytes, endStream: true); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); var dataFrame = await ExpectAsync(Http2FrameType.DATA, @@ -359,7 +359,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendDataAsync(1, _maxData, endStream: true); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); @@ -402,7 +402,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests } await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); @@ -523,7 +523,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendDataAsync(1, _noData, endStream: true); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); var dataFrame = await ExpectAsync(Http2FrameType.DATA, @@ -551,7 +551,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendDataAsync(1, _helloBytes, endStream: false); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); var stream1DataFrame1 = await ExpectAsync(Http2FrameType.DATA, @@ -562,7 +562,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendDataAsync(3, _helloBytes, endStream: false); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 3); var stream3DataFrame1 = await ExpectAsync(Http2FrameType.DATA, @@ -631,7 +631,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests } await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); @@ -683,7 +683,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests withStreamId: 0); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 3); @@ -761,7 +761,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests stream3ReadFinished.TrySetResult(null); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 3); await ExpectAsync(Http2FrameType.DATA, @@ -776,7 +776,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests stream1ReadFinished.TrySetResult(null); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); await ExpectAsync(Http2FrameType.DATA, @@ -803,7 +803,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendDataWithPaddingAsync(1, _helloWorldBytes, padLength, endStream: true); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); var dataFrame = await ExpectAsync(Http2FrameType.DATA, @@ -848,7 +848,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests } await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); @@ -907,7 +907,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests } await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -976,7 +976,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendDataAsync(1, _maxData, endStream: false); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); @@ -1151,7 +1151,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, _postRequestHeaders, endStream: true); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -1193,7 +1193,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(3, _browserRequestHeaders, endStream: true); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 3); @@ -1243,7 +1243,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(3, _browserRequestHeaders, endStream: true); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 3); @@ -1347,7 +1347,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, _browserRequestHeaders, endStream: true); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); @@ -1368,7 +1368,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(3, _browserRequestHeaders, endStream: true); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 3); @@ -1402,7 +1402,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, _browserRequestHeaders, endStream: true); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -1417,7 +1417,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, _browserRequestHeaders, endStream: true); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -1437,7 +1437,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendHeadersWithPaddingAsync(1, _browserRequestHeaders, padLength, endStream: true); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -1454,7 +1454,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendHeadersWithPriorityAsync(1, _browserRequestHeaders, priority: 42, streamDependency: 0, endStream: true); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -1474,7 +1474,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendHeadersWithPaddingAndPriorityAsync(1, _browserRequestHeaders, padLength, priority: 42, streamDependency: 0, endStream: true); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -1500,7 +1500,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests // The second stream should end first, since the first one is waiting for the request body. await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 3); @@ -1512,7 +1512,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendHeadersAsync(1, Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM, _requestTrailers); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -1546,7 +1546,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendDataAsync(1, _helloBytes, endStream: true); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); await ExpectAsync(Http2FrameType.DATA, @@ -1596,14 +1596,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests finishSecondRequest.TrySetResult(null); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 3); finishFirstRequest.TrySetResult(null); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -1629,7 +1629,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests requestBlocker.SetResult(0); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -1672,7 +1672,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, _browserRequestHeaders, endStream: true); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -1715,7 +1715,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(3, _browserRequestHeaders, endStream: true); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 3); @@ -1939,7 +1939,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendHeadersAsync(1, Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM, headers); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -2084,7 +2084,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendHeadersAsync(1, Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM, headers); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -2222,7 +2222,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, _browserRequestHeaders, endStream: true); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); @@ -2247,7 +2247,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests // The headers, but not the data for stream 3, can be sent prior to any window updates. await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 3); @@ -2331,7 +2331,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(streamId, _browserRequestHeaders, endStream: true); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: streamId); @@ -2811,7 +2811,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests _connection.ServerSettings.MaxFrameSize = Http2PeerSettings.MaxAllowedMaxFrameSize; // This includes the default response headers such as :status, etc - var defaultResponseHeaderLength = 37; + var defaultResponseHeaderLength = 33; var headerValueLength = Http2PeerSettings.MinAllowedMaxFrameSize; // First byte is always 0 // Second byte is the length of header name which is 1 @@ -2881,7 +2881,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, _browserRequestHeaders, endStream: true); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); await ExpectAsync(Http2FrameType.DATA, @@ -3030,7 +3030,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendDataAsync(1, _helloBytes, true); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); await ExpectAsync(Http2FrameType.DATA, @@ -3043,7 +3043,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests withStreamId: 1); await SendDataAsync(3, _helloBytes, true); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 3); await ExpectAsync(Http2FrameType.DATA, @@ -3116,7 +3116,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, _browserRequestHeaders, endStream: true); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); @@ -3139,13 +3139,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests // The headers, but not the data for the stream, can still be sent. await StartStreamAsync(3, _browserRequestHeaders, endStream: true); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 3); await StartStreamAsync(5, _browserRequestHeaders, endStream: true); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 5); @@ -3209,7 +3209,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(streamId, _browserRequestHeaders, endStream: true); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: streamId); @@ -3442,7 +3442,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, _browserRequestHeaders, endStream: true); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); @@ -3499,7 +3499,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendDataAsync(1, _helloWorldBytes, endStream: true); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); @@ -3538,7 +3538,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendDataAsync(1, _helloWorldBytes, endStream: true); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); @@ -3590,7 +3590,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, _twoContinuationsRequestHeaders, endStream: true); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -3616,7 +3616,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests // The second stream should end first, since the first one is waiting for the request body. await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 3); @@ -3639,7 +3639,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendContinuationAsync(1, Http2ContinuationFrameFlags.END_HEADERS, trailers); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -3661,8 +3661,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests { await InitializeConnectionAsync(_readHeadersApplication); - await SendHeadersAsync(1, Http2HeadersFrameFlags.NONE, _oneContinuationRequestHeaders); - await SendContinuationAsync(3, Http2ContinuationFrameFlags.END_HEADERS); + var headersEnumerator = GetHeadersEnumerator(_oneContinuationRequestHeaders); + await SendHeadersAsync(1, Http2HeadersFrameFlags.NONE, headersEnumerator); + await SendContinuationAsync(3, Http2ContinuationFrameFlags.END_HEADERS, headersEnumerator); await WaitForConnectionErrorAsync( ignoreNonGoAwayFrames: false, @@ -3736,7 +3737,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendEmptyContinuationFrameAsync(1, Http2ContinuationFrameFlags.END_HEADERS); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -3751,7 +3752,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, _browserRequestHeaders, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 12361, + withLength: 12343, withFlags: (byte)Http2HeadersFrameFlags.END_STREAM, withStreamId: 1); var continuationFrame1 = await ExpectAsync(Http2FrameType.CONTINUATION, @@ -3910,7 +3911,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, _browserRequestHeaders, endStream: true); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -3960,7 +3961,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendDataAsync(1, _helloBytes, true); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); await ExpectAsync(Http2FrameType.DATA, @@ -3994,7 +3995,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendDataAsync(1, _helloBytes, true); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); await ExpectAsync(Http2FrameType.DATA, @@ -4007,7 +4008,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests withStreamId: 1); await SendDataAsync(3, _helloBytes, true); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 3); await ExpectAsync(Http2FrameType.DATA, @@ -4097,7 +4098,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: false); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); diff --git a/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2StreamTests.cs b/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2StreamTests.cs index 6d9e6da62e..a59207ccda 100644 --- a/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2StreamTests.cs +++ b/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2StreamTests.cs @@ -79,7 +79,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 70, + withLength: 52, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -104,7 +104,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendHeadersAsync(1, Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM, headers); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 71, + withLength: 53, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -131,7 +131,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendHeadersAsync(1, Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM, headers); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 75, + withLength: 57, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -159,7 +159,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendHeadersAsync(1, Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM, headers); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 76, + withLength: 58, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -193,7 +193,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendHeadersAsync(1, Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM, headers); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 118, + withLength: 100, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -235,7 +235,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendHeadersAsync(1, Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM, headers); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -297,7 +297,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -326,7 +326,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -355,7 +355,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 65, + withLength: 47, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -386,7 +386,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 65, + withLength: 47, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -417,7 +417,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 65, + withLength: 47, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -448,7 +448,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 65, + withLength: 47, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -570,7 +570,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendDataAsync(1, new byte[12], endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -611,7 +611,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendDataAsync(1, new byte[12], endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -655,7 +655,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendDataAsync(1, new byte[8], endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -698,7 +698,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendDataAsync(1, new byte[8], endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -751,7 +751,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendDataAsync(1, new byte[8], endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -983,7 +983,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendDataAsync(1, new byte[12], endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -1015,7 +1015,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 56, + withLength: 38, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); await ExpectAsync(Http2FrameType.RST_STREAM, @@ -1054,7 +1054,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 56, + withLength: 38, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); await ExpectAsync(Http2FrameType.DATA, @@ -1092,7 +1092,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -1125,7 +1125,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); await ExpectAsync(Http2FrameType.DATA, @@ -1160,7 +1160,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); await ExpectAsync(Http2FrameType.DATA, @@ -1198,7 +1198,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); await ExpectAsync(Http2FrameType.DATA, @@ -1236,7 +1236,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); await ExpectAsync(Http2FrameType.DATA, @@ -1276,7 +1276,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); @@ -1323,7 +1323,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); @@ -1361,7 +1361,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); await ExpectAsync(Http2FrameType.DATA, @@ -1397,7 +1397,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); @@ -1441,7 +1441,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 56, + withLength: 38, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); @@ -1475,7 +1475,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); @@ -1508,7 +1508,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 56, + withLength: 38, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); await ExpectAsync(Http2FrameType.DATA, @@ -1552,7 +1552,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendDataAsync(1, new byte[12], endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -1591,7 +1591,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: false); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 59, + withLength: 41, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -1634,7 +1634,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendDataAsync(1, new byte[12], endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -1674,7 +1674,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendDataAsync(1, new byte[6], endStream: false); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 59, + withLength: 41, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -1733,7 +1733,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendDataAsync(1, new byte[6], endStream: false); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 59, + withLength: 41, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -1788,7 +1788,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendDataAsync(1, new byte[12], endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -1814,7 +1814,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, _browserRequestHeaders, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); @@ -1852,7 +1852,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, _browserRequestHeaders, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_STREAM | Http2HeadersFrameFlags.END_HEADERS), withStreamId: 1); @@ -1883,7 +1883,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, _browserRequestHeaders, endStream: true); var headersFrame1 = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS), withStreamId: 1); var trailersFrame1 = await ExpectAsync(Http2FrameType.HEADERS, @@ -1894,7 +1894,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(3, _browserRequestHeaders, endStream: true); var headersFrame2 = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS), withStreamId: 3); @@ -1930,7 +1930,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, _browserRequestHeaders, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); @@ -1980,7 +1980,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, _browserRequestHeaders, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); @@ -2039,7 +2039,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, _browserRequestHeaders, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); @@ -2074,7 +2074,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, _browserRequestHeaders, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); @@ -2124,7 +2124,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true).DefaultTimeout(); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1).DefaultTimeout(); @@ -2189,7 +2189,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); @@ -2235,7 +2235,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -2269,7 +2269,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); await ExpectAsync(Http2FrameType.DATA, @@ -2532,7 +2532,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, _browserRequestHeaders, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); await ExpectAsync(Http2FrameType.DATA, @@ -2623,7 +2623,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, _browserRequestHeaders, endStream: true); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); @@ -2671,7 +2671,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests // Just the StatusCode gets written before aborting in the continuation frame await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.NONE, withStreamId: 1); @@ -2700,7 +2700,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -2743,7 +2743,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); @@ -2789,7 +2789,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); var dataFrame = await ExpectAsync(Http2FrameType.DATA, @@ -2835,7 +2835,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); var dataFrame = await ExpectAsync(Http2FrameType.DATA, @@ -2884,7 +2884,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); var dataFrame = await ExpectAsync(Http2FrameType.DATA, @@ -2937,7 +2937,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); var dataFrame = await ExpectAsync(Http2FrameType.DATA, @@ -2987,7 +2987,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); var dataFrame = await ExpectAsync(Http2FrameType.DATA, @@ -3037,7 +3037,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); var dataFrame = await ExpectAsync(Http2FrameType.DATA, @@ -3080,7 +3080,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); var dataFrame = await ExpectAsync(Http2FrameType.DATA, @@ -3126,7 +3126,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); var dataFrame = await ExpectAsync(Http2FrameType.DATA, @@ -3168,7 +3168,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -3213,7 +3213,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); await ExpectAsync(Http2FrameType.DATA, @@ -3279,7 +3279,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 56, + withLength: 38, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); await ExpectAsync(Http2FrameType.DATA, @@ -3325,7 +3325,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 56, + withLength: 38, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); await ExpectAsync(Http2FrameType.DATA, @@ -3361,7 +3361,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 56, + withLength: 38, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); await ExpectAsync(Http2FrameType.DATA, @@ -3413,7 +3413,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 56, + withLength: 38, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); await ExpectAsync(Http2FrameType.DATA, @@ -3465,7 +3465,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -3498,7 +3498,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests // Don't receive content length because we called WriteAsync which caused an invalid response var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS | (byte)Http2HeadersFrameFlags.END_STREAM, withStreamId: 1); @@ -3531,7 +3531,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -3583,7 +3583,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -3639,7 +3639,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS), withStreamId: 1); var trailersFrame = await ExpectAsync(Http2FrameType.HEADERS, @@ -3705,7 +3705,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -3761,7 +3761,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS), withStreamId: 1); var bodyFrame = await ExpectAsync(Http2FrameType.DATA, @@ -3826,7 +3826,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -3885,7 +3885,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS), withStreamId: 1); var bodyFrame = await ExpectAsync(Http2FrameType.DATA, @@ -3941,7 +3941,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -4003,7 +4003,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS), withStreamId: 1); var bodyFrame = await ExpectAsync(Http2FrameType.DATA, @@ -4077,7 +4077,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS), withStreamId: 1); var bodyFrame = await ExpectAsync(Http2FrameType.DATA, @@ -4153,7 +4153,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 56, + withLength: 38, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS), withStreamId: 1); var bodyFrame = await ExpectAsync(Http2FrameType.DATA, @@ -4224,7 +4224,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 56, + withLength: 38, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS), withStreamId: 1); var bodyFrame = await ExpectAsync(Http2FrameType.DATA, @@ -4296,7 +4296,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS), withStreamId: 1); var bodyFrame = await ExpectAsync(Http2FrameType.DATA, @@ -4380,7 +4380,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: false); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS), withStreamId: 1); var bodyFrame = await ExpectAsync(Http2FrameType.DATA, @@ -4461,7 +4461,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS), withStreamId: 1); var bodyFrame = await ExpectAsync(Http2FrameType.DATA, @@ -4548,7 +4548,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await StartStreamAsync(1, headers, endStream: false); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS), withStreamId: 1); var bodyFrame = await ExpectAsync(Http2FrameType.DATA, @@ -4583,30 +4583,32 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests Assert.Equal("Custom Value", _decodedHeaders["CustomName"]); } + // :method = GET + // :path = / + // :scheme = http + // X-Test = £ + private static readonly byte[] LatinHeaderData = new byte[] + { + 0, 7, 58, 109, 101, 116, 104, 111, 100, 3, 71, 69, 84, 0, 5, 58, 112, 97, 116, + 104, 1, 47, 0, 7, 58, 115, 99, 104, 101, 109, 101, 4, 104, 116, 116, 112, 0, + 6, 120, 45, 116, 101, 115, 116, 1, 163 + }; + [Fact] public async Task HEADERS_Received_Latin1_AcceptedWhenLatin1OptionIsConfigured() { _serviceContext.ServerOptions.Latin1RequestHeaders = true; - var headers = new[] - { - new KeyValuePair(HeaderNames.Method, "GET"), - new KeyValuePair(HeaderNames.Path, "/"), - new KeyValuePair(HeaderNames.Scheme, "http"), - // The HPackEncoder will encode £ as 0xA3 aka Latin1 encoding. - new KeyValuePair("X-Test", "£"), - }; - await InitializeConnectionAsync(context => { Assert.Equal("£", context.Request.Headers["X-Test"]); return Task.CompletedTask; }); - await StartStreamAsync(1, headers, endStream: true); + await StartStreamAsync(1, LatinHeaderData, endStream: true); var headersFrame = await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -4623,18 +4625,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests [Fact] public async Task HEADERS_Received_Latin1_RejectedWhenLatin1OptionIsNotConfigured() { - var headers = new[] - { - new KeyValuePair(HeaderNames.Method, "GET"), - new KeyValuePair(HeaderNames.Path, "/"), - new KeyValuePair(HeaderNames.Scheme, "http"), - // The HPackEncoder will encode £ as 0xA3 aka Latin1 encoding. - new KeyValuePair("X-Test", "£"), - }; - await InitializeConnectionAsync(_noopApplication); - await StartStreamAsync(1, headers, endStream: true); + await StartStreamAsync(1, LatinHeaderData, endStream: true); await WaitForConnectionErrorAsync( ignoreNonGoAwayFrames: true, diff --git a/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2TestBase.cs b/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2TestBase.cs index 68076af39c..9277372a79 100644 --- a/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2TestBase.cs +++ b/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2TestBase.cs @@ -119,7 +119,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests private readonly MemoryPool _memoryPool = SlabMemoryPoolFactory.Create(); internal readonly Http2PeerSettings _clientSettings = new Http2PeerSettings(); - internal readonly HPackEncoder _hpackEncoder = new HPackEncoder(); internal readonly HPackDecoder _hpackDecoder; private readonly byte[] _headerEncodingBuffer = new byte[Http2PeerSettings.MinAllowedMaxFrameSize]; @@ -501,7 +500,17 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); _runningStreams[streamId] = tcs; - PipeWriterHttp2FrameExtensions.WriteStartStream(writableBuffer, streamId, GetHeadersEnumerator(headers), _hpackEncoder, _headerEncodingBuffer, endStream); + writableBuffer.WriteStartStream(streamId, GetHeadersEnumerator(headers), _headerEncodingBuffer, endStream); + return FlushAsync(writableBuffer); + } + + protected Task StartStreamAsync(int streamId, Span headerData, bool endStream) + { + var writableBuffer = _pair.Application.Output; + var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + _runningStreams[streamId] = tcs; + + writableBuffer.WriteStartStream(streamId, headerData, endStream); return FlushAsync(writableBuffer); } @@ -531,7 +540,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests extendedHeader[0] = padLength; var payload = buffer.Slice(extendedHeaderLength, buffer.Length - padLength - extendedHeaderLength); - _hpackEncoder.BeginEncode(GetHeadersEnumerator(headers), payload, out var length); + HPackHeaderWriter.BeginEncodeHeaders(GetHeadersEnumerator(headers), payload, out var length); var padding = buffer.Slice(extendedHeaderLength + length, padLength); padding.Fill(0); @@ -574,7 +583,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests extendedHeader[4] = priority; var payload = buffer.Slice(extendedHeaderLength); - _hpackEncoder.BeginEncode(GetHeadersEnumerator(headers), payload, out var length); + HPackHeaderWriter.BeginEncodeHeaders(GetHeadersEnumerator(headers), payload, out var length); frame.PayloadLength = extendedHeaderLength + length; @@ -621,7 +630,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests extendedHeader[5] = priority; var payload = buffer.Slice(extendedHeaderLength, buffer.Length - padLength - extendedHeaderLength); - _hpackEncoder.BeginEncode(GetHeadersEnumerator(headers), payload, out var length); + HPackHeaderWriter.BeginEncodeHeaders(GetHeadersEnumerator(headers), payload, out var length); var padding = buffer.Slice(extendedHeaderLength + length, padLength); padding.Fill(0); @@ -658,7 +667,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests protected async Task SendSettingsAsync() { - PipeWriterHttp2FrameExtensions.WriteSettings(_pair.Application.Output, _clientSettings); + _pair.Application.Output.WriteSettings(_clientSettings); await FlushAsync(_pair.Application.Output); } @@ -728,14 +737,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests return FlushAsync(writableBuffer); } - internal async Task SendHeadersAsync(int streamId, Http2HeadersFrameFlags flags, IEnumerable> headers) + internal async Task SendHeadersAsync(int streamId, Http2HeadersFrameFlags flags, Http2HeadersEnumerator headersEnumerator) { var outputWriter = _pair.Application.Output; var frame = new Http2Frame(); frame.PrepareHeaders(flags, streamId); var buffer = _headerEncodingBuffer.AsMemory(); - var done = _hpackEncoder.BeginEncode(GetHeadersEnumerator(headers), buffer.Span, out var length); + var done = HPackHeaderWriter.BeginEncodeHeaders(headersEnumerator, buffer.Span, out var length); frame.PayloadLength = length; Http2FrameWriter.WriteHeader(frame, outputWriter); @@ -744,6 +753,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests return done; } + internal Task SendHeadersAsync(int streamId, Http2HeadersFrameFlags flags, IEnumerable> headers) + { + return SendHeadersAsync(streamId, flags, GetHeadersEnumerator(headers)); + } + internal async Task SendHeadersAsync(int streamId, Http2HeadersFrameFlags flags, byte[] headerBlock) { var outputWriter = _pair.Application.Output; @@ -793,14 +807,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendAsync(payload); } - internal async Task SendContinuationAsync(int streamId, Http2ContinuationFrameFlags flags) + internal async Task SendContinuationAsync(int streamId, Http2ContinuationFrameFlags flags, Http2HeadersEnumerator headersEnumerator) { var outputWriter = _pair.Application.Output; var frame = new Http2Frame(); frame.PrepareContinuation(flags, streamId); var buffer = _headerEncodingBuffer.AsMemory(); - var done = _hpackEncoder.Encode(buffer.Span, out var length); + var done = HPackHeaderWriter.ContinueEncodeHeaders(headersEnumerator, buffer.Span, out var length); frame.PayloadLength = length; Http2FrameWriter.WriteHeader(frame, outputWriter); @@ -828,7 +842,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests frame.PrepareContinuation(flags, streamId); var buffer = _headerEncodingBuffer.AsMemory(); - var done = _hpackEncoder.BeginEncode(GetHeadersEnumerator(headers), buffer.Span, out var length); + var done = HPackHeaderWriter.BeginEncodeHeaders(GetHeadersEnumerator(headers), buffer.Span, out var length); frame.PayloadLength = length; Http2FrameWriter.WriteHeader(frame, outputWriter); @@ -837,7 +851,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests return done; } - private Http2HeadersEnumerator GetHeadersEnumerator(IEnumerable> headers) + internal Http2HeadersEnumerator GetHeadersEnumerator(IEnumerable> headers) { var dictionary = headers .GroupBy(g => g.Key) @@ -881,7 +895,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests protected Task SendDataAsync(int streamId, Memory data, bool endStream) { var outputWriter = _pair.Application.Output; - PipeWriterHttp2FrameExtensions.WriteData(outputWriter, streamId, data, endStream); + outputWriter.WriteData(streamId, data, endStream); return FlushAsync(outputWriter); } diff --git a/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2TimeoutTests.cs b/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2TimeoutTests.cs index 5ae038fed1..02413c5805 100644 --- a/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2TimeoutTests.cs +++ b/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2TimeoutTests.cs @@ -101,7 +101,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests _mockTimeoutControl.Verify(c => c.SetTimeout(It.IsAny(), TimeoutReason.RequestHeaders), Times.Once); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); @@ -283,7 +283,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendDataAsync(1, _helloWorldBytes, endStream: true); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); @@ -336,7 +336,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendDataAsync(1, _maxData, endStream: true); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); @@ -390,7 +390,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendDataAsync(1, _helloWorldBytes, endStream: true); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); await ExpectAsync(Http2FrameType.DATA, @@ -444,7 +444,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendDataAsync(1, _maxData, endStream: true); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); await ExpectAsync(Http2FrameType.DATA, @@ -500,7 +500,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendDataAsync(1, _maxData, endStream: true); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); await ExpectAsync(Http2FrameType.DATA, @@ -512,7 +512,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendDataAsync(3, _maxData, endStream: true); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 3); await ExpectAsync(Http2FrameType.DATA, @@ -566,7 +566,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendDataAsync(1, _helloWorldBytes, endStream: false); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); @@ -615,7 +615,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendDataAsync(1, _maxData, endStream: false); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); @@ -668,7 +668,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendDataAsync(1, _maxData, endStream: false); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); @@ -681,7 +681,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendDataAsync(3, _maxData, endStream: false); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 3); await ExpectAsync(Http2FrameType.DATA, @@ -737,7 +737,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendDataAsync(1, _maxData, endStream: true); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); @@ -755,7 +755,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendDataAsync(3, _maxData, endStream: false); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 3); await ExpectAsync(Http2FrameType.DATA, @@ -812,7 +812,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendDataAsync(1, _helloWorldBytes, endStream: false); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 1); @@ -884,7 +884,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await SendDataAsync(3, _helloWorldBytes, endStream: false); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 37, + withLength: 33, withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS, withStreamId: 3); await ExpectAsync(Http2FrameType.DATA, @@ -901,7 +901,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests backpressureTcs.SetResult(null); await ExpectAsync(Http2FrameType.HEADERS, - withLength: 55, + withLength: 37, withFlags: (byte)(Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM), withStreamId: 1); diff --git a/src/Servers/Kestrel/test/Interop.FunctionalTests/HttpClientHttp2InteropTests.cs b/src/Servers/Kestrel/test/Interop.FunctionalTests/HttpClientHttp2InteropTests.cs index add7c0e2fd..9f3c3598bc 100644 --- a/src/Servers/Kestrel/test/Interop.FunctionalTests/HttpClientHttp2InteropTests.cs +++ b/src/Servers/Kestrel/test/Interop.FunctionalTests/HttpClientHttp2InteropTests.cs @@ -1118,7 +1118,7 @@ namespace Interop.FunctionalTests Assert.Equal(oneKbString + i, response.Headers.GetValues("header" + i).Single()); } - Assert.Single(TestSink.Writes.Where(context => context.Message.Contains("sending HEADERS frame for stream ID 1 with length 15636 and flags END_STREAM"))); + Assert.Single(TestSink.Writes.Where(context => context.Message.Contains("sending HEADERS frame for stream ID 1 with length 15612 and flags END_STREAM"))); Assert.Equal(2, TestSink.Writes.Where(context => context.Message.Contains("sending CONTINUATION frame for stream ID 1 with length 15585 and flags NONE")).Count()); Assert.Single(TestSink.Writes.Where(context => context.Message.Contains("sending CONTINUATION frame for stream ID 1 with length 14546 and flags END_HEADERS"))); diff --git a/src/Shared/Http2cat/HPackHeaderWriter.cs b/src/Shared/Http2cat/HPackHeaderWriter.cs new file mode 100644 index 0000000000..27772caa72 --- /dev/null +++ b/src/Shared/Http2cat/HPackHeaderWriter.cs @@ -0,0 +1,91 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Net.Http.HPack; + +namespace Microsoft.AspNetCore.Http2Cat +{ + internal static class HPackHeaderWriter + { + /// + /// Begin encoding headers in the first HEADERS frame. + /// + public static bool BeginEncodeHeaders(int statusCode, IEnumerator> headersEnumerator, Span buffer, out int length) + { + if (!HPackEncoder.EncodeStatusHeader(statusCode, buffer, out var statusCodeLength)) + { + throw new HPackEncodingException(SR.net_http_hpack_encode_failure); + } + + if (!headersEnumerator.MoveNext()) + { + length = statusCodeLength; + return true; + } + + // We're ok with not throwing if no headers were encoded because we've already encoded the status. + // There is a small chance that the header will encode if there is no other content in the next HEADERS frame. + var done = EncodeHeaders(headersEnumerator, buffer.Slice(statusCodeLength), throwIfNoneEncoded: false, out var headersLength); + length = statusCodeLength + headersLength; + + return done; + } + + /// + /// Begin encoding headers in the first HEADERS frame. + /// + public static bool BeginEncodeHeaders(IEnumerator> headersEnumerator, Span buffer, out int length) + { + if (!headersEnumerator.MoveNext()) + { + length = 0; + return true; + } + + return EncodeHeaders(headersEnumerator, buffer, throwIfNoneEncoded: true, out length); + } + + /// + /// Continue encoding headers in the next HEADERS frame. The enumerator should already have a current value. + /// + public static bool ContinueEncodeHeaders(IEnumerator> headersEnumerator, Span buffer, out int length) + { + return EncodeHeaders(headersEnumerator, buffer, throwIfNoneEncoded: true, out length); + } + + private static bool EncodeHeaders(IEnumerator> headersEnumerator, Span buffer, bool throwIfNoneEncoded, out int length) + { + var currentLength = 0; + do + { + if (!EncodeHeader(headersEnumerator.Current.Key, headersEnumerator.Current.Value, buffer.Slice(currentLength), out int headerLength)) + { + // The the header wasn't written and no headers have been written then the header is too large. + // Throw an error to avoid an infinite loop of attempting to write large header. + if (currentLength == 0 && throwIfNoneEncoded) + { + throw new HPackEncodingException(SR.net_http_hpack_encode_failure); + } + + length = currentLength; + return false; + } + + currentLength += headerLength; + } + while (headersEnumerator.MoveNext()); + + length = currentLength; + + return true; + } + + private static bool EncodeHeader(string name, string value, Span buffer, out int length) + { + return HPackEncoder.EncodeLiteralHeaderFieldWithoutIndexingNewName(name, value, buffer, out length); + } + } +} diff --git a/src/Shared/Http2cat/Http2Utilities.cs b/src/Shared/Http2cat/Http2Utilities.cs index b4a0fd367c..13a6ba4fc5 100644 --- a/src/Shared/Http2cat/Http2Utilities.cs +++ b/src/Shared/Http2cat/Http2Utilities.cs @@ -122,7 +122,6 @@ namespace Microsoft.AspNetCore.Http2Cat public static readonly byte[] _maxData = Encoding.ASCII.GetBytes(new string('a', Http2PeerSettings.MinAllowedMaxFrameSize)); internal readonly Http2PeerSettings _clientSettings = new Http2PeerSettings(); - internal readonly HPackEncoder _hpackEncoder = new HPackEncoder(); internal readonly HPackDecoder _hpackDecoder; private readonly byte[] _headerEncodingBuffer = new byte[Http2PeerSettings.MinAllowedMaxFrameSize]; @@ -236,7 +235,8 @@ namespace Microsoft.AspNetCore.Http2Cat frame.PrepareHeaders(Http2HeadersFrameFlags.NONE, streamId); var buffer = _headerEncodingBuffer.AsSpan(); - var done = _hpackEncoder.BeginEncode(headers.GetEnumerator(), buffer, out var length); + var headersEnumerator = GetHeadersEnumerator(headers); + var done = HPackHeaderWriter.BeginEncodeHeaders(headersEnumerator, buffer, out var length); frame.PayloadLength = length; if (done) @@ -256,7 +256,7 @@ namespace Microsoft.AspNetCore.Http2Cat { frame.PrepareContinuation(Http2ContinuationFrameFlags.NONE, streamId); - done = _hpackEncoder.Encode(buffer, out length); + done = HPackHeaderWriter.ContinueEncodeHeaders(headersEnumerator, buffer, out length); frame.PayloadLength = length; if (done) @@ -271,6 +271,12 @@ namespace Microsoft.AspNetCore.Http2Cat return FlushAsync(writableBuffer); } + private static IEnumerator> GetHeadersEnumerator(IEnumerable> headers) + { + var headersEnumerator = headers.GetEnumerator(); + return headersEnumerator; + } + internal Dictionary DecodeHeaders(Http2FrameWithPayload frame, bool endHeaders = false) { Assert.Equal(Http2FrameType.HEADERS, frame.Type); @@ -335,7 +341,7 @@ namespace Microsoft.AspNetCore.Http2Cat extendedHeader[0] = padLength; var payload = buffer.Slice(extendedHeaderLength, buffer.Length - padLength - extendedHeaderLength); - _hpackEncoder.BeginEncode(headers.GetEnumerator(), payload, out var length); + HPackHeaderWriter.BeginEncodeHeaders(GetHeadersEnumerator(headers), payload, out var length); var padding = buffer.Slice(extendedHeaderLength + length, padLength); padding.Fill(0); @@ -377,7 +383,7 @@ namespace Microsoft.AspNetCore.Http2Cat extendedHeader[4] = priority; var payload = buffer.Slice(extendedHeaderLength); - _hpackEncoder.BeginEncode(headers.GetEnumerator(), payload, out var length); + HPackHeaderWriter.BeginEncodeHeaders(GetHeadersEnumerator(headers), payload, out var length); frame.PayloadLength = extendedHeaderLength + length; @@ -423,7 +429,7 @@ namespace Microsoft.AspNetCore.Http2Cat extendedHeader[5] = priority; var payload = buffer.Slice(extendedHeaderLength, buffer.Length - padLength - extendedHeaderLength); - _hpackEncoder.BeginEncode(headers.GetEnumerator(), payload, out var length); + HPackHeaderWriter.BeginEncodeHeaders(GetHeadersEnumerator(headers), payload, out var length); var padding = buffer.Slice(extendedHeaderLength + length, padLength); padding.Fill(0); @@ -549,7 +555,7 @@ namespace Microsoft.AspNetCore.Http2Cat frame.PrepareHeaders(flags, streamId); var buffer = _headerEncodingBuffer.AsMemory(); - var done = _hpackEncoder.BeginEncode(headers.GetEnumerator(), buffer.Span, out var length); + var done = HPackHeaderWriter.BeginEncodeHeaders(GetHeadersEnumerator(headers), buffer.Span, out var length); frame.PayloadLength = length; WriteHeader(frame, outputWriter); @@ -607,14 +613,14 @@ namespace Microsoft.AspNetCore.Http2Cat await SendAsync(payload); } - internal async Task SendContinuationAsync(int streamId, Http2ContinuationFrameFlags flags) + internal async Task SendContinuationAsync(int streamId, Http2ContinuationFrameFlags flags, IEnumerator> headersEnumerator) { var outputWriter = _pair.Application.Output; var frame = new Http2Frame(); frame.PrepareContinuation(flags, streamId); var buffer = _headerEncodingBuffer.AsMemory(); - var done = _hpackEncoder.Encode(buffer.Span, out var length); + var done = HPackHeaderWriter.ContinueEncodeHeaders(headersEnumerator, buffer.Span, out var length); frame.PayloadLength = length; WriteHeader(frame, outputWriter); @@ -642,7 +648,7 @@ namespace Microsoft.AspNetCore.Http2Cat frame.PrepareContinuation(flags, streamId); var buffer = _headerEncodingBuffer.AsMemory(); - var done = _hpackEncoder.BeginEncode(headers.GetEnumerator(), buffer.Span, out var length); + var done = HPackHeaderWriter.BeginEncodeHeaders(GetHeadersEnumerator(headers), buffer.Span, out var length); frame.PayloadLength = length; WriteHeader(frame, outputWriter); diff --git a/src/Shared/runtime/Http2/Hpack/H2StaticTable.cs b/src/Shared/runtime/Http2/Hpack/H2StaticTable.cs index 52de5ee8a8..7f3b775582 100644 --- a/src/Shared/runtime/Http2/Hpack/H2StaticTable.cs +++ b/src/Shared/runtime/Http2/Hpack/H2StaticTable.cs @@ -108,6 +108,7 @@ namespace System.Net.Http.HPack public const int PathSlash = 4; public const int SchemeHttp = 6; public const int SchemeHttps = 7; + public const int Status200 = 8; public const int AcceptCharset = 15; public const int AcceptEncoding = 16; public const int AcceptLanguage = 17; diff --git a/src/Shared/runtime/Http2/Hpack/HPackEncoder.cs b/src/Shared/runtime/Http2/Hpack/HPackEncoder.cs index ac321b6f0d..15aec6cfa6 100644 --- a/src/Shared/runtime/Http2/Hpack/HPackEncoder.cs +++ b/src/Shared/runtime/Http2/Hpack/HPackEncoder.cs @@ -3,172 +3,11 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; -#if KESTREL -using HeadersEnumerator = Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2.Http2HeadersEnumerator; -#else -using HeadersEnumerator = System.Collections.Generic.IEnumerator>; -#endif namespace System.Net.Http.HPack { - internal class HPackEncoder + internal static class HPackEncoder { - private HeadersEnumerator _enumerator; - - public bool BeginEncode(HeadersEnumerator enumerator, Span buffer, out int length) - { - _enumerator = enumerator; - _enumerator.MoveNext(); - - return Encode(buffer, out length); - } - - public bool BeginEncode(int statusCode, HeadersEnumerator enumerator, Span buffer, out int length) - { - _enumerator = enumerator; - _enumerator.MoveNext(); - - int statusCodeLength = EncodeStatusCode(statusCode, buffer); - bool done = Encode(buffer.Slice(statusCodeLength), throwIfNoneEncoded: false, out int headersLength); - length = statusCodeLength + headersLength; - - return done; - } - - public bool Encode(Span buffer, out int length) - { - return Encode(buffer, throwIfNoneEncoded: true, out length); - } - - private bool Encode(Span buffer, bool throwIfNoneEncoded, out int length) - { - int currentLength = 0; - do - { - if (!EncodeHeader(_enumerator.Current.Key, _enumerator.Current.Value, buffer.Slice(currentLength), out int headerLength)) - { - if (currentLength == 0 && throwIfNoneEncoded) - { - throw new HPackEncodingException(SR.net_http_hpack_encode_failure); - } - - length = currentLength; - return false; - } - - currentLength += headerLength; - } - while (_enumerator.MoveNext()); - - length = currentLength; - - return true; - } - - private int EncodeStatusCode(int statusCode, Span buffer) - { - switch (statusCode) - { - // Status codes which exist in the HTTP/2 StaticTable. - case 200: - case 204: - case 206: - case 304: - case 400: - case 404: - case 500: - buffer[0] = (byte)(0x80 | H2StaticTable.StatusIndex[statusCode]); - return 1; - default: - // Send as Literal Header Field Without Indexing - Indexed Name - buffer[0] = 0x08; - - ReadOnlySpan statusBytes = StatusCodes.ToStatusBytes(statusCode); - buffer[1] = (byte)statusBytes.Length; - statusBytes.CopyTo(buffer.Slice(2)); - - return 2 + statusBytes.Length; - } - } - - private bool EncodeHeader(string name, string value, Span buffer, out int length) - { - int i = 0; - length = 0; - - if (buffer.Length == 0) - { - return false; - } - - buffer[i++] = 0; - - if (i == buffer.Length) - { - return false; - } - - if (!EncodeString(name, buffer.Slice(i), out int nameLength, lowercase: true)) - { - return false; - } - - i += nameLength; - - if (i >= buffer.Length) - { - return false; - } - - if (!EncodeString(value, buffer.Slice(i), out int valueLength, lowercase: false)) - { - return false; - } - - i += valueLength; - - length = i; - return true; - } - - private bool EncodeString(string value, Span destination, out int bytesWritten, bool lowercase) - { - // From https://tools.ietf.org/html/rfc7541#section-5.2 - // ------------------------------------------------------ - // 0 1 2 3 4 5 6 7 - // +---+---+---+---+---+---+---+---+ - // | H | String Length (7+) | - // +---+---------------------------+ - // | String Data (Length octets) | - // +-------------------------------+ - const int toLowerMask = 0x20; - - if (destination.Length != 0) - { - destination[0] = 0; // TODO: Use Huffman encoding - if (IntegerEncoder.Encode(value.Length, 7, destination, out int integerLength)) - { - Debug.Assert(integerLength >= 1); - - destination = destination.Slice(integerLength); - if (value.Length <= destination.Length) - { - for (int i = 0; i < value.Length; i++) - { - char c = value[i]; - destination[i] = (byte)(lowercase && (uint)(c - 'A') <= ('Z' - 'A') ? c | toLowerMask : c); - } - - bytesWritten = integerLength + value.Length; - return true; - } - } - } - - bytesWritten = 0; - return false; - } - // Things we should add: // * Huffman encoding // @@ -199,6 +38,43 @@ namespace System.Net.Http.HPack return false; } + /// Encodes the status code of a response to the :status field. + public static bool EncodeStatusHeader(int statusCode, Span destination, out int bytesWritten) + { + // Bytes written depend on whether the status code value maps directly to an index + switch (statusCode) + { + case 200: + case 204: + case 206: + case 304: + case 400: + case 404: + case 500: + // Status codes which exist in the HTTP/2 StaticTable. + return EncodeIndexedHeaderField(H2StaticTable.StatusIndex[statusCode], destination, out bytesWritten); + default: + // If the status code doesn't have a static index then we need to include the full value. + // Write a status index and then the number bytes as a string literal. + if (!EncodeLiteralHeaderFieldWithoutIndexing(H2StaticTable.Status200, destination, out var nameLength)) + { + bytesWritten = 0; + return false; + } + + var statusBytes = StatusCodes.ToStatusBytes(statusCode); + + if (!EncodeStringLiteral(statusBytes, destination.Slice(nameLength), out var valueLength)) + { + bytesWritten = 0; + return false; + } + + bytesWritten = nameLength + valueLength; + return true; + } + } + /// Encodes a "Literal Header Field without Indexing". public static bool EncodeLiteralHeaderFieldWithoutIndexing(int index, string value, Span destination, out int bytesWritten) { @@ -233,7 +109,7 @@ namespace System.Net.Http.HPack /// /// Encodes a "Literal Header Field without Indexing", but only the index portion; - /// a subsequent call to must be used to encode the associated value. + /// a subsequent call to EncodeStringLiteral must be used to encode the associated value. /// public static bool EncodeLiteralHeaderFieldWithoutIndexing(int index, Span destination, out int bytesWritten) { @@ -266,6 +142,39 @@ namespace System.Net.Http.HPack return false; } + /// Encodes a "Literal Header Field without Indexing - New Name". + public static bool EncodeLiteralHeaderFieldWithoutIndexingNewName(string name, string value, Span destination, out int bytesWritten) + { + // From https://tools.ietf.org/html/rfc7541#section-6.2.2 + // ------------------------------------------------------ + // 0 1 2 3 4 5 6 7 + // +---+---+---+---+---+---+---+---+ + // | 0 | 0 | 0 | 0 | 0 | + // +---+---+-----------------------+ + // | H | Name Length (7+) | + // +---+---------------------------+ + // | Name String (Length octets) | + // +---+---------------------------+ + // | H | Value Length (7+) | + // +---+---------------------------+ + // | Value String (Length octets) | + // +-------------------------------+ + + if ((uint)destination.Length >= 3) + { + destination[0] = 0; + if (EncodeLiteralHeaderName(name, destination.Slice(1), out int nameLength) && + EncodeStringLiteral(value, destination.Slice(1 + nameLength), out int valueLength)) + { + bytesWritten = 1 + nameLength + valueLength; + return true; + } + } + + bytesWritten = 0; + return false; + } + /// Encodes a "Literal Header Field without Indexing - New Name". public static bool EncodeLiteralHeaderFieldWithoutIndexingNewName(string name, ReadOnlySpan values, string separator, Span destination, out int bytesWritten) { @@ -301,7 +210,7 @@ namespace System.Net.Http.HPack /// /// Encodes a "Literal Header Field without Indexing - New Name", but only the name portion; - /// a subsequent call to must be used to encode the associated value. + /// a subsequent call to EncodeStringLiteral must be used to encode the associated value. /// public static bool EncodeLiteralHeaderFieldWithoutIndexingNewName(string name, Span destination, out int bytesWritten) { @@ -397,6 +306,40 @@ namespace System.Net.Http.HPack return false; } + public static bool EncodeStringLiteral(ReadOnlySpan value, Span destination, out int bytesWritten) + { + // From https://tools.ietf.org/html/rfc7541#section-5.2 + // ------------------------------------------------------ + // 0 1 2 3 4 5 6 7 + // +---+---+---+---+---+---+---+---+ + // | H | String Length (7+) | + // +---+---------------------------+ + // | String Data (Length octets) | + // +-------------------------------+ + + if (destination.Length != 0) + { + destination[0] = 0; // TODO: Use Huffman encoding + if (IntegerEncoder.Encode(value.Length, 7, destination, out int integerLength)) + { + Debug.Assert(integerLength >= 1); + + destination = destination.Slice(integerLength); + if (value.Length <= destination.Length) + { + // Note: No validation. Bytes should have already been validated. + value.CopyTo(destination); + + bytesWritten = integerLength + value.Length; + return true; + } + } + } + + bytesWritten = 0; + return false; + } + public static bool EncodeStringLiteral(string value, Span destination, out int bytesWritten) { // From https://tools.ietf.org/html/rfc7541#section-5.2 @@ -485,7 +428,7 @@ namespace System.Net.Http.HPack /// /// Encodes a "Literal Header Field without Indexing" to a new array, but only the index portion; - /// a subsequent call to must be used to encode the associated value. + /// a subsequent call to EncodeStringLiteral must be used to encode the associated value. /// public static byte[] EncodeLiteralHeaderFieldWithoutIndexingToAllocatedArray(int index) { @@ -497,7 +440,7 @@ namespace System.Net.Http.HPack /// /// Encodes a "Literal Header Field without Indexing - New Name" to a new array, but only the name portion; - /// a subsequent call to must be used to encode the associated value. + /// a subsequent call to EncodeStringLiteral must be used to encode the associated value. /// public static byte[] EncodeLiteralHeaderFieldWithoutIndexingNewNameToAllocatedArray(string name) {