Less StringValue struct copies for header checks (#2488)
This commit is contained in:
parent
2d51d23697
commit
e30a02cee5
|
|
@ -360,9 +360,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
// request message that contains more than one Host header field or a
|
// request message that contains more than one Host header field or a
|
||||||
// Host header field with an invalid field-value.
|
// Host header field with an invalid field-value.
|
||||||
|
|
||||||
var host = HttpRequestHeaders.HeaderHost;
|
var hostCount = HttpRequestHeaders.HostCount;
|
||||||
var hostText = host.ToString();
|
var hostText = HttpRequestHeaders.HeaderHost.ToString();
|
||||||
if (host.Count <= 0)
|
if (hostCount <= 0)
|
||||||
{
|
{
|
||||||
if (_httpVersion == Http.HttpVersion.Http10)
|
if (_httpVersion == Http.HttpVersion.Http10)
|
||||||
{
|
{
|
||||||
|
|
@ -370,13 +370,27 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
}
|
}
|
||||||
BadHttpRequestException.Throw(RequestRejectionReason.MissingHostHeader);
|
BadHttpRequestException.Throw(RequestRejectionReason.MissingHostHeader);
|
||||||
}
|
}
|
||||||
else if (host.Count > 1)
|
else if (hostCount > 1)
|
||||||
{
|
{
|
||||||
BadHttpRequestException.Throw(RequestRejectionReason.MultipleHostHeaders);
|
BadHttpRequestException.Throw(RequestRejectionReason.MultipleHostHeaders);
|
||||||
}
|
}
|
||||||
else if (_requestTargetForm == HttpRequestTarget.AuthorityForm)
|
else if (_requestTargetForm != HttpRequestTarget.OriginForm)
|
||||||
{
|
{
|
||||||
if (!host.Equals(RawTarget))
|
// Tail call
|
||||||
|
ValidateNonOrginHostHeader(hostText);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Tail call
|
||||||
|
HttpUtilities.ValidateHostHeader(hostText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ValidateNonOrginHostHeader(string hostText)
|
||||||
|
{
|
||||||
|
if (_requestTargetForm == HttpRequestTarget.AuthorityForm)
|
||||||
|
{
|
||||||
|
if (hostText != RawTarget)
|
||||||
{
|
{
|
||||||
BadHttpRequestException.Throw(RequestRejectionReason.InvalidHostHeader, hostText);
|
BadHttpRequestException.Throw(RequestRejectionReason.InvalidHostHeader, hostText);
|
||||||
}
|
}
|
||||||
|
|
@ -390,20 +404,18 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
|
|
||||||
// System.Uri doesn't not tell us if the port was in the original string or not.
|
// System.Uri doesn't not tell us if the port was in the original string or not.
|
||||||
// When IsDefaultPort = true, we will allow Host: with or without the default port
|
// When IsDefaultPort = true, we will allow Host: with or without the default port
|
||||||
if (host != _absoluteRequestTarget.Authority)
|
if (hostText != _absoluteRequestTarget.Authority)
|
||||||
{
|
{
|
||||||
if (!_absoluteRequestTarget.IsDefaultPort
|
if (!_absoluteRequestTarget.IsDefaultPort
|
||||||
|| host != _absoluteRequestTarget.Authority + ":" + _absoluteRequestTarget.Port.ToString(CultureInfo.InvariantCulture))
|
|| hostText != _absoluteRequestTarget.Authority + ":" + _absoluteRequestTarget.Port.ToString(CultureInfo.InvariantCulture))
|
||||||
{
|
{
|
||||||
BadHttpRequestException.Throw(RequestRejectionReason.InvalidHostHeader, hostText);
|
BadHttpRequestException.Throw(RequestRejectionReason.InvalidHostHeader, hostText);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!HttpUtilities.IsValidHostHeader(hostText))
|
// Tail call
|
||||||
{
|
HttpUtilities.ValidateHostHeader(hostText);
|
||||||
BadHttpRequestException.Throw(RequestRejectionReason.InvalidHostHeader, hostText);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnReset()
|
protected override void OnReset()
|
||||||
|
|
@ -454,8 +466,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
{
|
{
|
||||||
if (_requestProcessingStatus == RequestProcessingStatus.ParsingHeaders)
|
if (_requestProcessingStatus == RequestProcessingStatus.ParsingHeaders)
|
||||||
{
|
{
|
||||||
BadHttpRequestException.Throw(RequestRejectionReason
|
BadHttpRequestException.Throw(RequestRejectionReason.MalformedRequestInvalidHeaders);
|
||||||
.MalformedRequestInvalidHeaders);
|
|
||||||
}
|
}
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -213,11 +213,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
// see also http://tools.ietf.org/html/rfc2616#section-4.4
|
// see also http://tools.ietf.org/html/rfc2616#section-4.4
|
||||||
var keepAlive = httpVersion != HttpVersion.Http10;
|
var keepAlive = httpVersion != HttpVersion.Http10;
|
||||||
|
|
||||||
var connection = headers.HeaderConnection;
|
|
||||||
var upgrade = false;
|
var upgrade = false;
|
||||||
if (connection.Count > 0)
|
if (headers.HasConnection)
|
||||||
{
|
{
|
||||||
var connectionOptions = HttpHeaders.ParseConnection(connection);
|
var connectionOptions = HttpHeaders.ParseConnection(headers.HeaderConnection);
|
||||||
|
|
||||||
upgrade = (connectionOptions & ConnectionOptions.Upgrade) == ConnectionOptions.Upgrade;
|
upgrade = (connectionOptions & ConnectionOptions.Upgrade) == ConnectionOptions.Upgrade;
|
||||||
keepAlive = (connectionOptions & ConnectionOptions.KeepAlive) == ConnectionOptions.KeepAlive;
|
keepAlive = (connectionOptions & ConnectionOptions.KeepAlive) == ConnectionOptions.KeepAlive;
|
||||||
|
|
@ -233,10 +232,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
return new ForUpgrade(context);
|
return new ForUpgrade(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
var transferEncoding = headers.HeaderTransferEncoding;
|
if (headers.HasTransferEncoding)
|
||||||
if (transferEncoding.Count > 0)
|
|
||||||
{
|
{
|
||||||
var transferCoding = HttpHeaders.GetFinalTransferCoding(headers.HeaderTransferEncoding);
|
var transferEncoding = headers.HeaderTransferEncoding;
|
||||||
|
var transferCoding = HttpHeaders.GetFinalTransferCoding(transferEncoding);
|
||||||
|
|
||||||
// https://tools.ietf.org/html/rfc7230#section-3.3.3
|
// https://tools.ietf.org/html/rfc7230#section-3.3.3
|
||||||
// If a Transfer-Encoding header field
|
// If a Transfer-Encoding header field
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
|
|
||||||
private long _bits = 0;
|
private long _bits = 0;
|
||||||
private HeaderReferences _headers;
|
private HeaderReferences _headers;
|
||||||
|
|
||||||
|
public bool HasConnection => (_bits & 2L) != 0;
|
||||||
|
public bool HasTransferEncoding => (_bits & 64L) != 0;
|
||||||
|
|
||||||
|
public int HostCount => _headers._Host.Count;
|
||||||
|
|
||||||
public StringValues HeaderCacheControl
|
public StringValues HeaderCacheControl
|
||||||
{
|
{
|
||||||
|
|
@ -4794,6 +4799,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
|
|
||||||
private long _bits = 0;
|
private long _bits = 0;
|
||||||
private HeaderReferences _headers;
|
private HeaderReferences _headers;
|
||||||
|
|
||||||
|
public bool HasConnection => (_bits & 2L) != 0;
|
||||||
|
public bool HasDate => (_bits & 4L) != 0;
|
||||||
|
public bool HasTransferEncoding => (_bits & 64L) != 0;
|
||||||
|
public bool HasServer => (_bits & 33554432L) != 0;
|
||||||
|
|
||||||
|
|
||||||
public StringValues HeaderCacheControl
|
public StringValues HeaderCacheControl
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
{
|
{
|
||||||
ThrowHeadersReadOnlyException();
|
ThrowHeadersReadOnlyException();
|
||||||
}
|
}
|
||||||
SetValueFast(key, value);
|
if (value.Count == 0)
|
||||||
|
{
|
||||||
|
RemoveFast(key);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetValueFast(key, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -164,7 +171,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
ThrowHeadersReadOnlyException();
|
ThrowHeadersReadOnlyException();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!AddValueFast(key, value))
|
if (value.Count > 0 && !AddValueFast(key, value))
|
||||||
{
|
{
|
||||||
ThrowDuplicateKeyException();
|
ThrowDuplicateKeyException();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1111,7 +1111,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
var hasConnection = responseHeaders.HasConnection;
|
var hasConnection = responseHeaders.HasConnection;
|
||||||
var connectionOptions = HttpHeaders.ParseConnection(responseHeaders.HeaderConnection);
|
var connectionOptions = HttpHeaders.ParseConnection(responseHeaders.HeaderConnection);
|
||||||
var hasTransferEncoding = responseHeaders.HasTransferEncoding;
|
var hasTransferEncoding = responseHeaders.HasTransferEncoding;
|
||||||
var transferCoding = HttpHeaders.GetFinalTransferCoding(responseHeaders.HeaderTransferEncoding);
|
|
||||||
|
|
||||||
if (_keepAlive && hasConnection && (connectionOptions & ConnectionOptions.KeepAlive) != ConnectionOptions.KeepAlive)
|
if (_keepAlive && hasConnection && (connectionOptions & ConnectionOptions.KeepAlive) != ConnectionOptions.KeepAlive)
|
||||||
{
|
{
|
||||||
|
|
@ -1123,7 +1122,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
// chunked is applied to a response payload body, the sender MUST either
|
// chunked is applied to a response payload body, the sender MUST either
|
||||||
// apply chunked as the final transfer coding or terminate the message
|
// apply chunked as the final transfer coding or terminate the message
|
||||||
// by closing the connection.
|
// by closing the connection.
|
||||||
if (hasTransferEncoding && transferCoding != TransferCoding.Chunked)
|
if (hasTransferEncoding &&
|
||||||
|
HttpHeaders.GetFinalTransferCoding(responseHeaders.HeaderTransferEncoding) != TransferCoding.Chunked)
|
||||||
{
|
{
|
||||||
_keepAlive = false;
|
_keepAlive = false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,14 +17,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
private static readonly byte[] _CrLf = new[] { (byte)'\r', (byte)'\n' };
|
private static readonly byte[] _CrLf = new[] { (byte)'\r', (byte)'\n' };
|
||||||
private static readonly byte[] _colonSpace = new[] { (byte)':', (byte)' ' };
|
private static readonly byte[] _colonSpace = new[] { (byte)':', (byte)' ' };
|
||||||
|
|
||||||
public bool HasConnection => HeaderConnection.Count != 0;
|
|
||||||
|
|
||||||
public bool HasTransferEncoding => HeaderTransferEncoding.Count != 0;
|
|
||||||
|
|
||||||
public bool HasServer => HeaderServer.Count != 0;
|
|
||||||
|
|
||||||
public bool HasDate => HeaderDate.Count != 0;
|
|
||||||
|
|
||||||
public Enumerator GetEnumerator()
|
public Enumerator GetEnumerator()
|
||||||
{
|
{
|
||||||
return new Enumerator(this);
|
return new Enumerator(this);
|
||||||
|
|
|
||||||
|
|
@ -110,10 +110,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
||||||
}
|
}
|
||||||
|
|
||||||
var hostText = host.ToString();
|
var hostText = host.ToString();
|
||||||
if (!HttpUtilities.IsValidHostHeader(hostText))
|
HttpUtilities.ValidateHostHeader(hostText);
|
||||||
{
|
|
||||||
BadHttpRequestException.Throw(RequestRejectionReason.InvalidHostHeader, hostText);
|
|
||||||
}
|
|
||||||
|
|
||||||
endConnection = false;
|
endConnection = false;
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -426,45 +426,44 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsValidHostHeader(string hostText)
|
public static void ValidateHostHeader(string hostText)
|
||||||
{
|
{
|
||||||
// The spec allows empty values
|
|
||||||
if (string.IsNullOrEmpty(hostText))
|
if (string.IsNullOrEmpty(hostText))
|
||||||
{
|
{
|
||||||
return true;
|
// The spec allows empty values
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hostText[0] == '[')
|
var firstChar = hostText[0];
|
||||||
|
if (firstChar == '[')
|
||||||
{
|
{
|
||||||
return IsValidIPv6Host(hostText);
|
// Tail call
|
||||||
|
ValidateIPv6Host(hostText);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
if (hostText[0] == ':')
|
|
||||||
{
|
{
|
||||||
// Only a port
|
if (firstChar == ':')
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var i = 0;
|
|
||||||
for (; i < hostText.Length; i++)
|
|
||||||
{
|
|
||||||
if (!IsValidHostChar(hostText[i]))
|
|
||||||
{
|
{
|
||||||
break;
|
// Only a port
|
||||||
|
BadHttpRequestException.Throw(RequestRejectionReason.InvalidHostHeader, hostText);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enregister array
|
||||||
|
var hostCharValidity = HostCharValidity;
|
||||||
|
for (var i = 0; i < hostText.Length; i++)
|
||||||
|
{
|
||||||
|
if (!hostCharValidity[hostText[i]])
|
||||||
|
{
|
||||||
|
// Tail call
|
||||||
|
ValidateHostPort(hostText, i);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return IsValidHostPort(hostText, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
private static bool IsValidHostChar(char ch)
|
|
||||||
{
|
|
||||||
return ch < HostCharValidity.Length && HostCharValidity[ch];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The lead '[' was already checked
|
// The lead '[' was already checked
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
private static void ValidateIPv6Host(string hostText)
|
||||||
private static bool IsValidIPv6Host(string hostText)
|
|
||||||
{
|
{
|
||||||
for (var i = 1; i < hostText.Length; i++)
|
for (var i = 1; i < hostText.Length; i++)
|
||||||
{
|
{
|
||||||
|
|
@ -474,58 +473,69 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure
|
||||||
// [::1] is the shortest valid IPv6 host
|
// [::1] is the shortest valid IPv6 host
|
||||||
if (i < 4)
|
if (i < 4)
|
||||||
{
|
{
|
||||||
return false;
|
BadHttpRequestException.Throw(RequestRejectionReason.InvalidHostHeader, hostText);
|
||||||
}
|
}
|
||||||
return IsValidHostPort(hostText, i + 1);
|
else if (i + 1 < hostText.Length)
|
||||||
|
{
|
||||||
|
// Tail call
|
||||||
|
ValidateHostPort(hostText, i + 1);
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsHex(ch) && ch != ':' && ch != '.')
|
if (!IsHex(ch) && ch != ':' && ch != '.')
|
||||||
{
|
{
|
||||||
return false;
|
BadHttpRequestException.Throw(RequestRejectionReason.InvalidHostHeader, hostText);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Must contain a ']'
|
// Must contain a ']'
|
||||||
return false;
|
BadHttpRequestException.Throw(RequestRejectionReason.InvalidHostHeader, hostText);
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
private static void ValidateHostPort(string hostText, int offset)
|
||||||
private static bool IsValidHostPort(string hostText, int offset)
|
|
||||||
{
|
{
|
||||||
if (offset == hostText.Length)
|
var firstChar = hostText[offset];
|
||||||
{
|
offset++;
|
||||||
return true;
|
if (firstChar != ':' || offset == hostText.Length)
|
||||||
}
|
|
||||||
|
|
||||||
if (hostText[offset] != ':' || hostText.Length == offset + 1)
|
|
||||||
{
|
{
|
||||||
// Must have at least one number after the colon if present.
|
// Must have at least one number after the colon if present.
|
||||||
return false;
|
BadHttpRequestException.Throw(RequestRejectionReason.InvalidHostHeader, hostText);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = offset + 1; i < hostText.Length; i++)
|
for (var i = offset; i < hostText.Length; i++)
|
||||||
{
|
{
|
||||||
if (!IsNumeric(hostText[i]))
|
if (!IsNumeric(hostText[i]))
|
||||||
{
|
{
|
||||||
return false;
|
BadHttpRequestException.Throw(RequestRejectionReason.InvalidHostHeader, hostText);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static bool IsNumeric(char ch)
|
private static bool IsNumeric(char ch)
|
||||||
{
|
{
|
||||||
return '0' <= ch && ch <= '9';
|
// '0' <= ch && ch <= '9'
|
||||||
|
// (uint)(ch - '0') <= (uint)('9' - '0')
|
||||||
|
|
||||||
|
// Subtract start of range '0'
|
||||||
|
// Cast to uint to change negative numbers to large numbers
|
||||||
|
// Check if less than 10 representing chars '0' - '9'
|
||||||
|
return (uint)(ch - '0') < 10u;
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static bool IsHex(char ch)
|
private static bool IsHex(char ch)
|
||||||
{
|
{
|
||||||
return IsNumeric(ch)
|
return IsNumeric(ch)
|
||||||
|| ('a' <= ch && ch <= 'f')
|
// || ('a' <= ch && ch <= 'f')
|
||||||
|| ('A' <= ch && ch <= 'F');
|
// || ('A' <= ch && ch <= 'F');
|
||||||
|
|
||||||
|
// Lowercase indiscriminately (or with 32)
|
||||||
|
// Subtract start of range 'a'
|
||||||
|
// Cast to uint to change negative numbers to large numbers
|
||||||
|
// Check if less than 6 representing chars 'a' - 'f'
|
||||||
|
|| (uint)((ch | 32) - 'a') < 6u;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -170,7 +170,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
[MemberData(nameof(HostHeaderData))]
|
[MemberData(nameof(HostHeaderData))]
|
||||||
public void ValidHostHeadersParsed(string host)
|
public void ValidHostHeadersParsed(string host)
|
||||||
{
|
{
|
||||||
Assert.True(HttpUtilities.IsValidHostHeader(host));
|
HttpUtilities.ValidateHostHeader(host);
|
||||||
|
// Shouldn't throw
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TheoryData<string> HostHeaderInvalidData
|
public static TheoryData<string> HostHeaderInvalidData
|
||||||
|
|
@ -224,7 +225,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
[MemberData(nameof(HostHeaderInvalidData))]
|
[MemberData(nameof(HostHeaderInvalidData))]
|
||||||
public void InvalidHostHeadersRejected(string host)
|
public void InvalidHostHeadersRejected(string host)
|
||||||
{
|
{
|
||||||
Assert.False(HttpUtilities.IsValidHostHeader(host));
|
Assert.Throws<BadHttpRequestException>(() => HttpUtilities.ValidateHostHeader(host));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -68,6 +68,8 @@ namespace CodeGenerator
|
||||||
public byte[] Bytes => Encoding.ASCII.GetBytes($"\r\n{Name}: ");
|
public byte[] Bytes => Encoding.ASCII.GetBytes($"\r\n{Name}: ");
|
||||||
public int BytesOffset { get; set; }
|
public int BytesOffset { get; set; }
|
||||||
public int BytesCount { get; set; }
|
public int BytesCount { get; set; }
|
||||||
|
public bool ExistenceCheck { get; set; }
|
||||||
|
public bool FastCount { get; set; }
|
||||||
public bool EnhancedSetter { get; set; }
|
public bool EnhancedSetter { get; set; }
|
||||||
public bool PrimaryHeader { get; set; }
|
public bool PrimaryHeader { get; set; }
|
||||||
public string TestBit() => $"(_bits & {1L << Index}L) != 0";
|
public string TestBit() => $"(_bits & {1L << Index}L) != 0";
|
||||||
|
|
@ -168,6 +170,15 @@ namespace CodeGenerator
|
||||||
"Access-Control-Request-Method",
|
"Access-Control-Request-Method",
|
||||||
"Access-Control-Request-Headers",
|
"Access-Control-Request-Headers",
|
||||||
};
|
};
|
||||||
|
var requestHeadersExistence = new[]
|
||||||
|
{
|
||||||
|
"Connection",
|
||||||
|
"Transfer-Encoding",
|
||||||
|
};
|
||||||
|
var requestHeadersCount = new[]
|
||||||
|
{
|
||||||
|
"Host"
|
||||||
|
};
|
||||||
var requestHeaders = commonHeaders.Concat(new[]
|
var requestHeaders = commonHeaders.Concat(new[]
|
||||||
{
|
{
|
||||||
"Accept",
|
"Accept",
|
||||||
|
|
@ -197,7 +208,9 @@ namespace CodeGenerator
|
||||||
{
|
{
|
||||||
Name = header,
|
Name = header,
|
||||||
Index = index,
|
Index = index,
|
||||||
PrimaryHeader = requestPrimaryHeaders.Contains(header)
|
PrimaryHeader = requestPrimaryHeaders.Contains(header),
|
||||||
|
ExistenceCheck = requestHeadersExistence.Contains(header),
|
||||||
|
FastCount = requestHeadersCount.Contains(header)
|
||||||
})
|
})
|
||||||
.Concat(new[] { new KnownHeader
|
.Concat(new[] { new KnownHeader
|
||||||
{
|
{
|
||||||
|
|
@ -209,6 +222,13 @@ namespace CodeGenerator
|
||||||
Debug.Assert(requestHeaders.Length <= 64);
|
Debug.Assert(requestHeaders.Length <= 64);
|
||||||
Debug.Assert(requestHeaders.Max(x => x.Index) <= 62);
|
Debug.Assert(requestHeaders.Max(x => x.Index) <= 62);
|
||||||
|
|
||||||
|
var responseHeadersExistence = new[]
|
||||||
|
{
|
||||||
|
"Connection",
|
||||||
|
"Server",
|
||||||
|
"Date",
|
||||||
|
"Transfer-Encoding"
|
||||||
|
};
|
||||||
var enhancedHeaders = new[]
|
var enhancedHeaders = new[]
|
||||||
{
|
{
|
||||||
"Connection",
|
"Connection",
|
||||||
|
|
@ -245,6 +265,7 @@ namespace CodeGenerator
|
||||||
Name = header,
|
Name = header,
|
||||||
Index = index,
|
Index = index,
|
||||||
EnhancedSetter = enhancedHeaders.Contains(header),
|
EnhancedSetter = enhancedHeaders.Contains(header),
|
||||||
|
ExistenceCheck = responseHeadersExistence.Contains(header),
|
||||||
PrimaryHeader = responsePrimaryHeaders.Contains(header)
|
PrimaryHeader = responsePrimaryHeaders.Contains(header)
|
||||||
})
|
})
|
||||||
.Concat(new[] { new KnownHeader
|
.Concat(new[] { new KnownHeader
|
||||||
|
|
@ -311,6 +332,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
|
|
||||||
private long _bits = 0;
|
private long _bits = 0;
|
||||||
private HeaderReferences _headers;
|
private HeaderReferences _headers;
|
||||||
|
{Each(loop.Headers.Where(header => header.ExistenceCheck), header => $@"
|
||||||
|
public bool Has{header.Identifier} => {header.TestBit()};")}
|
||||||
|
{Each(loop.Headers.Where(header => header.FastCount), header => $@"
|
||||||
|
public int {header.Identifier}Count => _headers._{header.Identifier}.Count;")}
|
||||||
{Each(loop.Headers, header => $@"
|
{Each(loop.Headers, header => $@"
|
||||||
public StringValues Header{header.Identifier}
|
public StringValues Header{header.Identifier}
|
||||||
{{{(header.Identifier == "ContentLength" ? $@"
|
{{{(header.Identifier == "ContentLength" ? $@"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue