Allow headers to match on ReferenceEquals before OrdinalIgnoreCase (#9341)

This commit is contained in:
Ben Adams 2019-04-18 20:00:01 +01:00 committed by Stephen Halter
parent 52b3b19e06
commit 8fcadf72cd
35 changed files with 7465 additions and 3809 deletions

View File

@ -263,12 +263,12 @@ namespace Microsoft.AspNetCore.Antiforgery
_tokenStore.SaveCookieToken(httpContext, cookieToken);
}
if (!_options.SuppressXFrameOptionsHeader && !httpContext.Response.Headers.ContainsKey("X-Frame-Options"))
if (!_options.SuppressXFrameOptionsHeader && !httpContext.Response.Headers.ContainsKey(HeaderNames.XFrameOptions))
{
// Adding X-Frame-Options header to prevent ClickJacking. See
// http://tools.ietf.org/html/draft-ietf-websec-x-frame-options-10
// for more information.
httpContext.Response.Headers["X-Frame-Options"] = "SAMEORIGIN";
httpContext.Response.Headers[HeaderNames.XFrameOptions] = "SAMEORIGIN";
}
}

View File

@ -20,6 +20,7 @@ using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.StackTrace.Sources;
using Microsoft.Net.Http.Headers;
namespace Microsoft.AspNetCore.Hosting.Internal
{
@ -184,7 +185,7 @@ namespace Microsoft.AspNetCore.Hosting.Internal
return context =>
{
context.Response.StatusCode = 500;
context.Response.Headers["Cache-Control"] = "no-cache";
context.Response.Headers[HeaderNames.CacheControl] = "no-cache";
return errorPage.ExecuteAsync(context);
};
}

View File

@ -22,11 +22,6 @@ namespace Microsoft.AspNetCore.Hosting.Internal
private const string DeprecatedDiagnosticsEndRequestKey = "Microsoft.AspNetCore.Hosting.EndRequest";
private const string DiagnosticsUnhandledExceptionKey = "Microsoft.AspNetCore.Hosting.UnhandledException";
private const string RequestIdHeaderName = "Request-Id";
private const string CorrelationContextHeaderName = "Correlation-Context";
private const string TraceParentHeaderName = "traceparent";
private const string TraceStateHeaderName = "tracestate";
private readonly DiagnosticListener _diagnosticListener;
private readonly ILogger _logger;
@ -238,22 +233,22 @@ namespace Microsoft.AspNetCore.Hosting.Internal
{
var activity = new Activity(ActivityName);
if (!httpContext.Request.Headers.TryGetValue(TraceParentHeaderName, out var requestId))
if (!httpContext.Request.Headers.TryGetValue(HeaderNames.TraceParent, out var requestId))
{
httpContext.Request.Headers.TryGetValue(RequestIdHeaderName, out requestId);
httpContext.Request.Headers.TryGetValue(HeaderNames.RequestId, out requestId);
}
if (!StringValues.IsNullOrEmpty(requestId))
{
activity.SetParentId(requestId);
if (httpContext.Request.Headers.TryGetValue(TraceStateHeaderName, out var traceState))
if (httpContext.Request.Headers.TryGetValue(HeaderNames.TraceState, out var traceState))
{
activity.TraceStateString = traceState;
}
// We expect baggage to be empty by default
// Only very advanced users will be using it in near future, we encourage them to keep baggage small (few items)
string[] baggage = httpContext.Request.Headers.GetCommaSeparatedValues(CorrelationContextHeaderName);
string[] baggage = httpContext.Request.Headers.GetCommaSeparatedValues(HeaderNames.CorrelationContext);
if (baggage.Length > 0)
{
foreach (var item in baggage)

View File

@ -22,6 +22,7 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.StackTrace.Sources;
using Microsoft.Net.Http.Headers;
namespace Microsoft.AspNetCore.Hosting.Internal
{
@ -276,7 +277,7 @@ namespace Microsoft.AspNetCore.Hosting.Internal
return context =>
{
context.Response.StatusCode = 500;
context.Response.Headers["Cache-Control"] = "no-cache";
context.Response.Headers[HeaderNames.CacheControl] = "no-cache";
return errorPage.ExecuteAsync(context);
};
}

View File

@ -118,74 +118,87 @@ namespace Microsoft.Net.Http.Headers
}
public static partial class HeaderNames
{
public const string Accept = "Accept";
public const string AcceptCharset = "Accept-Charset";
public const string AcceptEncoding = "Accept-Encoding";
public const string AcceptLanguage = "Accept-Language";
public const string AcceptRanges = "Accept-Ranges";
public const string AccessControlAllowCredentials = "Access-Control-Allow-Credentials";
public const string AccessControlAllowHeaders = "Access-Control-Allow-Headers";
public const string AccessControlAllowMethods = "Access-Control-Allow-Methods";
public const string AccessControlAllowOrigin = "Access-Control-Allow-Origin";
public const string AccessControlExposeHeaders = "Access-Control-Expose-Headers";
public const string AccessControlMaxAge = "Access-Control-Max-Age";
public const string AccessControlRequestHeaders = "Access-Control-Request-Headers";
public const string AccessControlRequestMethod = "Access-Control-Request-Method";
public const string Age = "Age";
public const string Allow = "Allow";
public const string Authority = ":authority";
public const string Authorization = "Authorization";
public const string CacheControl = "Cache-Control";
public const string Connection = "Connection";
public const string ContentDisposition = "Content-Disposition";
public const string ContentEncoding = "Content-Encoding";
public const string ContentLanguage = "Content-Language";
public const string ContentLength = "Content-Length";
public const string ContentLocation = "Content-Location";
public const string ContentMD5 = "Content-MD5";
public const string ContentRange = "Content-Range";
public const string ContentSecurityPolicy = "Content-Security-Policy";
public const string ContentSecurityPolicyReportOnly = "Content-Security-Policy-Report-Only";
public const string ContentType = "Content-Type";
public const string Cookie = "Cookie";
public const string Date = "Date";
public const string ETag = "ETag";
public const string Expect = "Expect";
public const string Expires = "Expires";
public const string From = "From";
public const string Host = "Host";
public const string IfMatch = "If-Match";
public const string IfModifiedSince = "If-Modified-Since";
public const string IfNoneMatch = "If-None-Match";
public const string IfRange = "If-Range";
public const string IfUnmodifiedSince = "If-Unmodified-Since";
public const string LastModified = "Last-Modified";
public const string Location = "Location";
public const string MaxForwards = "Max-Forwards";
public const string Method = ":method";
public const string Origin = "Origin";
public const string Path = ":path";
public const string Pragma = "Pragma";
public const string ProxyAuthenticate = "Proxy-Authenticate";
public const string ProxyAuthorization = "Proxy-Authorization";
public const string Range = "Range";
public const string Referer = "Referer";
public const string RetryAfter = "Retry-After";
public const string Scheme = ":scheme";
public const string Server = "Server";
public const string SetCookie = "Set-Cookie";
public const string Status = ":status";
public const string StrictTransportSecurity = "Strict-Transport-Security";
public const string TE = "TE";
public const string Trailer = "Trailer";
public const string TransferEncoding = "Transfer-Encoding";
public const string Upgrade = "Upgrade";
public const string UserAgent = "User-Agent";
public const string Vary = "Vary";
public const string Via = "Via";
public const string Warning = "Warning";
public const string WebSocketSubProtocols = "Sec-WebSocket-Protocol";
public const string WWWAuthenticate = "WWW-Authenticate";
public static readonly string Accept;
public static readonly string AcceptCharset;
public static readonly string AcceptEncoding;
public static readonly string AcceptLanguage;
public static readonly string AcceptRanges;
public static readonly string AccessControlAllowCredentials;
public static readonly string AccessControlAllowHeaders;
public static readonly string AccessControlAllowMethods;
public static readonly string AccessControlAllowOrigin;
public static readonly string AccessControlExposeHeaders;
public static readonly string AccessControlMaxAge;
public static readonly string AccessControlRequestHeaders;
public static readonly string AccessControlRequestMethod;
public static readonly string Age;
public static readonly string Allow;
public static readonly string Authority;
public static readonly string Authorization;
public static readonly string CacheControl;
public static readonly string Connection;
public static readonly string ContentDisposition;
public static readonly string ContentEncoding;
public static readonly string ContentLanguage;
public static readonly string ContentLength;
public static readonly string ContentLocation;
public static readonly string ContentMD5;
public static readonly string ContentRange;
public static readonly string ContentSecurityPolicy;
public static readonly string ContentSecurityPolicyReportOnly;
public static readonly string ContentType;
public static readonly string Cookie;
public static readonly string CorrelationContext;
public static readonly string Date;
public static readonly string DNT;
public static readonly string ETag;
public static readonly string Expect;
public static readonly string Expires;
public static readonly string From;
public static readonly string Host;
public static readonly string IfMatch;
public static readonly string IfModifiedSince;
public static readonly string IfNoneMatch;
public static readonly string IfRange;
public static readonly string IfUnmodifiedSince;
public static readonly string KeepAlive;
public static readonly string LastModified;
public static readonly string Location;
public static readonly string MaxForwards;
public static readonly string Method;
public static readonly string Origin;
public static readonly string Path;
public static readonly string Pragma;
public static readonly string ProxyAuthenticate;
public static readonly string ProxyAuthorization;
public static readonly string Range;
public static readonly string Referer;
public static readonly string RequestId;
public static readonly string RetryAfter;
public static readonly string Scheme;
public static readonly string SecWebSocketAccept;
public static readonly string SecWebSocketKey;
public static readonly string SecWebSocketProtocol;
public static readonly string SecWebSocketVersion;
public static readonly string Server;
public static readonly string SetCookie;
public static readonly string Status;
public static readonly string StrictTransportSecurity;
public static readonly string TE;
public static readonly string TraceParent;
public static readonly string TraceState;
public static readonly string Trailer;
public static readonly string TransferEncoding;
public static readonly string Translate;
public static readonly string Upgrade;
public static readonly string UpgradeInsecureRequests;
public static readonly string UserAgent;
public static readonly string Vary;
public static readonly string Via;
public static readonly string Warning;
public static readonly string WebSocketSubProtocols;
public static readonly string WWWAuthenticate;
public static readonly string XFrameOptions;
}
public static partial class HeaderQuality
{

View File

@ -5,73 +5,87 @@ namespace Microsoft.Net.Http.Headers
{
public static class HeaderNames
{
public const string Accept = "Accept";
public const string AcceptCharset = "Accept-Charset";
public const string AcceptEncoding = "Accept-Encoding";
public const string AcceptLanguage = "Accept-Language";
public const string AcceptRanges = "Accept-Ranges";
public const string AccessControlAllowCredentials = "Access-Control-Allow-Credentials";
public const string AccessControlAllowHeaders = "Access-Control-Allow-Headers";
public const string AccessControlAllowMethods = "Access-Control-Allow-Methods";
public const string AccessControlAllowOrigin = "Access-Control-Allow-Origin";
public const string AccessControlExposeHeaders = "Access-Control-Expose-Headers";
public const string AccessControlMaxAge = "Access-Control-Max-Age";
public const string AccessControlRequestHeaders = "Access-Control-Request-Headers";
public const string AccessControlRequestMethod = "Access-Control-Request-Method";
public const string Age = "Age";
public const string Allow = "Allow";
public const string Authority = ":authority";
public const string Authorization = "Authorization";
public const string CacheControl = "Cache-Control";
public const string Connection = "Connection";
public const string ContentDisposition = "Content-Disposition";
public const string ContentEncoding = "Content-Encoding";
public const string ContentLanguage = "Content-Language";
public const string ContentLength = "Content-Length";
public const string ContentLocation = "Content-Location";
public const string ContentMD5 = "Content-MD5";
public const string ContentRange = "Content-Range";
public const string ContentSecurityPolicy = "Content-Security-Policy";
public const string ContentSecurityPolicyReportOnly = "Content-Security-Policy-Report-Only";
public const string ContentType = "Content-Type";
public const string Cookie = "Cookie";
public const string Date = "Date";
public const string ETag = "ETag";
public const string Expires = "Expires";
public const string Expect = "Expect";
public const string From = "From";
public const string Host = "Host";
public const string IfMatch = "If-Match";
public const string IfModifiedSince = "If-Modified-Since";
public const string IfNoneMatch = "If-None-Match";
public const string IfRange = "If-Range";
public const string IfUnmodifiedSince = "If-Unmodified-Since";
public const string LastModified = "Last-Modified";
public const string Location = "Location";
public const string MaxForwards = "Max-Forwards";
public const string Method = ":method";
public const string Origin = "Origin";
public const string Path = ":path";
public const string Pragma = "Pragma";
public const string ProxyAuthenticate = "Proxy-Authenticate";
public const string ProxyAuthorization = "Proxy-Authorization";
public const string Range = "Range";
public const string Referer = "Referer";
public const string RetryAfter = "Retry-After";
public const string Scheme = ":scheme";
public const string Server = "Server";
public const string SetCookie = "Set-Cookie";
public const string Status = ":status";
public const string StrictTransportSecurity = "Strict-Transport-Security";
public const string TE = "TE";
public const string Trailer = "Trailer";
public const string TransferEncoding = "Transfer-Encoding";
public const string Upgrade = "Upgrade";
public const string UserAgent = "User-Agent";
public const string Vary = "Vary";
public const string Via = "Via";
public const string Warning = "Warning";
public const string WebSocketSubProtocols = "Sec-WebSocket-Protocol";
public const string WWWAuthenticate = "WWW-Authenticate";
// Use readonly statics rather than constants so ReferenceEquals works
public static readonly string Accept = "Accept";
public static readonly string AcceptCharset = "Accept-Charset";
public static readonly string AcceptEncoding = "Accept-Encoding";
public static readonly string AcceptLanguage = "Accept-Language";
public static readonly string AcceptRanges = "Accept-Ranges";
public static readonly string AccessControlAllowCredentials = "Access-Control-Allow-Credentials";
public static readonly string AccessControlAllowHeaders = "Access-Control-Allow-Headers";
public static readonly string AccessControlAllowMethods = "Access-Control-Allow-Methods";
public static readonly string AccessControlAllowOrigin = "Access-Control-Allow-Origin";
public static readonly string AccessControlExposeHeaders = "Access-Control-Expose-Headers";
public static readonly string AccessControlMaxAge = "Access-Control-Max-Age";
public static readonly string AccessControlRequestHeaders = "Access-Control-Request-Headers";
public static readonly string AccessControlRequestMethod = "Access-Control-Request-Method";
public static readonly string Age = "Age";
public static readonly string Allow = "Allow";
public static readonly string Authority = ":authority";
public static readonly string Authorization = "Authorization";
public static readonly string CacheControl = "Cache-Control";
public static readonly string Connection = "Connection";
public static readonly string ContentDisposition = "Content-Disposition";
public static readonly string ContentEncoding = "Content-Encoding";
public static readonly string ContentLanguage = "Content-Language";
public static readonly string ContentLength = "Content-Length";
public static readonly string ContentLocation = "Content-Location";
public static readonly string ContentMD5 = "Content-MD5";
public static readonly string ContentRange = "Content-Range";
public static readonly string ContentSecurityPolicy = "Content-Security-Policy";
public static readonly string ContentSecurityPolicyReportOnly = "Content-Security-Policy-Report-Only";
public static readonly string ContentType = "Content-Type";
public static readonly string CorrelationContext = "Correlation-Context";
public static readonly string Cookie = "Cookie";
public static readonly string Date = "Date";
public static readonly string DNT = "DNT";
public static readonly string ETag = "ETag";
public static readonly string Expires = "Expires";
public static readonly string Expect = "Expect";
public static readonly string From = "From";
public static readonly string Host = "Host";
public static readonly string KeepAlive = "Keep-Alive";
public static readonly string IfMatch = "If-Match";
public static readonly string IfModifiedSince = "If-Modified-Since";
public static readonly string IfNoneMatch = "If-None-Match";
public static readonly string IfRange = "If-Range";
public static readonly string IfUnmodifiedSince = "If-Unmodified-Since";
public static readonly string LastModified = "Last-Modified";
public static readonly string Location = "Location";
public static readonly string MaxForwards = "Max-Forwards";
public static readonly string Method = ":method";
public static readonly string Origin = "Origin";
public static readonly string Path = ":path";
public static readonly string Pragma = "Pragma";
public static readonly string ProxyAuthenticate = "Proxy-Authenticate";
public static readonly string ProxyAuthorization = "Proxy-Authorization";
public static readonly string Range = "Range";
public static readonly string Referer = "Referer";
public static readonly string RetryAfter = "Retry-After";
public static readonly string RequestId = "Request-Id";
public static readonly string Scheme = ":scheme";
public static readonly string SecWebSocketAccept = "Sec-WebSocket-Accept";
public static readonly string SecWebSocketKey = "Sec-WebSocket-Key";
public static readonly string SecWebSocketProtocol = "Sec-WebSocket-Protocol";
public static readonly string SecWebSocketVersion = "Sec-WebSocket-Version";
public static readonly string Server = "Server";
public static readonly string SetCookie = "Set-Cookie";
public static readonly string Status = ":status";
public static readonly string StrictTransportSecurity = "Strict-Transport-Security";
public static readonly string TE = "TE";
public static readonly string Trailer = "Trailer";
public static readonly string TransferEncoding = "Transfer-Encoding";
public static readonly string Translate = "Translate";
public static readonly string TraceParent = "traceparent";
public static readonly string TraceState = "tracestate";
public static readonly string Upgrade = "Upgrade";
public static readonly string UpgradeInsecureRequests = "Upgrade-Insecure-Requests";
public static readonly string UserAgent = "User-Agent";
public static readonly string Vary = "Vary";
public static readonly string Via = "Via";
public static readonly string Warning = "Warning";
public static readonly string WebSocketSubProtocols = "Sec-WebSocket-Protocol";
public static readonly string WWWAuthenticate = "WWW-Authenticate";
public static readonly string XFrameOptions = "X-Frame-Options";
}
}

View File

@ -7,6 +7,7 @@
<Compile Include="Microsoft.AspNetCore.Http.Abstractions.netcoreapp3.0.cs" />
<Reference Include="Microsoft.AspNetCore.Http.Features" />
<Reference Include="Microsoft.Extensions.ActivatorUtilities.Sources" />
<Reference Include="Microsoft.Net.Http.Headers" />
<Reference Include="System.Text.Encodings.Web" />
</ItemGroup>
</Project>

View File

@ -4,13 +4,12 @@
using System;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.Extensions.Primitives;
using Microsoft.Net.Http.Headers;
namespace Microsoft.AspNetCore.Http
{
public static class ResponseTrailerExtensions
{
private const string Trailer = "Trailer";
/// <summary>
/// Adds the given trailer name to the 'Trailer' response header. This must happen before the response headers are sent.
/// </summary>
@ -18,7 +17,7 @@ namespace Microsoft.AspNetCore.Http
/// <param name="trailerName"></param>
public static void DeclareTrailer(this HttpResponse response, string trailerName)
{
response.Headers.AppendCommaSeparatedValues(Trailer, trailerName);
response.Headers.AppendCommaSeparatedValues(HeaderNames.Trailer, trailerName);
}
/// <summary>

View File

@ -22,6 +22,7 @@ Microsoft.AspNetCore.Http.HttpResponse</Description>
<ItemGroup>
<Reference Include="Microsoft.AspNetCore.Http.Features" />
<Reference Include="Microsoft.Extensions.ActivatorUtilities.Sources" />
<Reference Include="Microsoft.Net.Http.Headers" />
<Reference Include="System.Text.Encodings.Web" />
</ItemGroup>

View File

@ -116,8 +116,8 @@ namespace Microsoft.AspNetCore.Http.Internal
public override HostString Host
{
get { return HostString.FromUriComponent(Headers["Host"]); }
set { Headers["Host"] = value.ToUriComponent(); }
get { return HostString.FromUriComponent(Headers[HeaderNames.Host]); }
set { Headers[HeaderNames.Host] = value.ToUriComponent(); }
}
public override IQueryCollection Query

View File

@ -5,6 +5,7 @@ using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Net.Http.Headers;
namespace Microsoft.AspNetCore.Http.Internal
{
@ -30,8 +31,8 @@ namespace Microsoft.AspNetCore.Http.Internal
/// </summary>
public string ContentDisposition
{
get { return Headers["Content-Disposition"]; }
set { Headers["Content-Disposition"] = value; }
get { return Headers[HeaderNames.ContentDisposition]; }
set { Headers[HeaderNames.ContentDisposition] = value; }
}
/// <summary>
@ -39,8 +40,8 @@ namespace Microsoft.AspNetCore.Http.Internal
/// </summary>
public string ContentType
{
get { return Headers["Content-Type"]; }
set { Headers["Content-Type"] = value; }
get { return Headers[HeaderNames.ContentType]; }
set { Headers[HeaderNames.ContentType] = value; }
}
/// <summary>

View File

@ -391,7 +391,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
// Prevent ArgumentException from duplicate key if header already added, such as when the
// request is re-executed by an error handler (see https://github.com/aspnet/AspNetCore/issues/6415)
context.Response.Headers["Allow"] = allow;
context.Response.Headers[HeaderNames.Allow] = allow;
return Task.CompletedTask;
},

View File

@ -4,6 +4,7 @@
using System.Collections.Generic;
using System.IO;
using Microsoft.Extensions.Primitives;
using Microsoft.Net.Http.Headers;
namespace Microsoft.AspNetCore.WebUtilities
{
@ -14,7 +15,7 @@ namespace Microsoft.AspNetCore.WebUtilities
get
{
StringValues values;
if (Headers.TryGetValue("Content-Type", out values))
if (Headers.TryGetValue(HeaderNames.ContentType, out values))
{
return values;
}
@ -27,7 +28,7 @@ namespace Microsoft.AspNetCore.WebUtilities
get
{
StringValues values;
if (Headers.TryGetValue("Content-Disposition", out values))
if (Headers.TryGetValue(HeaderNames.ContentDisposition, out values))
{
return values;
}
@ -45,4 +46,4 @@ namespace Microsoft.AspNetCore.WebUtilities
/// </summary>
public long? BaseStreamOffset { get; set; }
}
}
}

View File

@ -11,6 +11,7 @@ using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Net.Http.Headers;
namespace Microsoft.AspNetCore.Session
{
@ -159,9 +160,9 @@ namespace Microsoft.AspNetCore.Session
_context.Response.Cookies.Append(_options.Cookie.Name, _cookieValue, cookieOptions);
_context.Response.Headers["Cache-Control"] = "no-cache";
_context.Response.Headers["Pragma"] = "no-cache";
_context.Response.Headers["Expires"] = "-1";
_context.Response.Headers[HeaderNames.CacheControl] = "no-cache";
_context.Response.Headers[HeaderNames.Pragma] = "no-cache";
_context.Response.Headers[HeaderNames.Expires] = "-1";
}
// Returns true if the session has already been established, or if it still can be because the response has not been sent.
@ -171,4 +172,4 @@ namespace Microsoft.AspNetCore.Session
}
}
}
}
}

View File

@ -35,21 +35,3 @@ namespace Microsoft.AspNetCore.WebSockets
public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddWebSockets(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action<Microsoft.AspNetCore.Builder.WebSocketOptions> configure) { throw null; }
}
}
namespace Microsoft.AspNetCore.WebSockets.Internal
{
public static partial class Constants
{
public static partial class Headers
{
public const string Connection = "Connection";
public const string ConnectionUpgrade = "Upgrade";
public const string SecWebSocketAccept = "Sec-WebSocket-Accept";
public const string SecWebSocketKey = "Sec-WebSocket-Key";
public const string SecWebSocketProtocol = "Sec-WebSocket-Protocol";
public const string SecWebSocketVersion = "Sec-WebSocket-Version";
public const string SupportedVersion = "13";
public const string Upgrade = "Upgrade";
public const string UpgradeWebSocket = "websocket";
}
}
}

View File

@ -3,18 +3,12 @@
namespace Microsoft.AspNetCore.WebSockets.Internal
{
public static class Constants
internal static class Constants
{
public static class Headers
{
public const string Upgrade = "Upgrade";
public const string UpgradeWebSocket = "websocket";
public const string Connection = "Connection";
{
public const string UpgradeWebSocket = "websocket";
public const string ConnectionUpgrade = "Upgrade";
public const string SecWebSocketKey = "Sec-WebSocket-Key";
public const string SecWebSocketVersion = "Sec-WebSocket-Version";
public const string SecWebSocketProtocol = "Sec-WebSocket-Protocol";
public const string SecWebSocketAccept = "Sec-WebSocket-Accept";
public const string SupportedVersion = "13";
}
}

View File

@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
using Microsoft.AspNetCore.Http;
using Microsoft.Net.Http.Headers;
namespace Microsoft.AspNetCore.WebSockets.Internal
{
@ -16,10 +17,10 @@ namespace Microsoft.AspNetCore.WebSockets.Internal
/// </summary>
public static readonly IEnumerable<string> NeededHeaders = new[]
{
Constants.Headers.Upgrade,
Constants.Headers.Connection,
Constants.Headers.SecWebSocketKey,
Constants.Headers.SecWebSocketVersion
HeaderNames.Upgrade,
HeaderNames.Connection,
HeaderNames.SecWebSocketKey,
HeaderNames.SecWebSocketVersion
};
// Verify Method, Upgrade, Connection, version, key, etc..
@ -34,28 +35,28 @@ namespace Microsoft.AspNetCore.WebSockets.Internal
foreach (var pair in headers)
{
if (string.Equals(Constants.Headers.Connection, pair.Key, StringComparison.OrdinalIgnoreCase))
if (string.Equals(HeaderNames.Connection, pair.Key, StringComparison.OrdinalIgnoreCase))
{
if (string.Equals(Constants.Headers.ConnectionUpgrade, pair.Value, StringComparison.OrdinalIgnoreCase))
{
validConnection = true;
}
}
else if (string.Equals(Constants.Headers.Upgrade, pair.Key, StringComparison.OrdinalIgnoreCase))
else if (string.Equals(HeaderNames.Upgrade, pair.Key, StringComparison.OrdinalIgnoreCase))
{
if (string.Equals(Constants.Headers.UpgradeWebSocket, pair.Value, StringComparison.OrdinalIgnoreCase))
{
validUpgrade = true;
}
}
else if (string.Equals(Constants.Headers.SecWebSocketVersion, pair.Key, StringComparison.OrdinalIgnoreCase))
else if (string.Equals(HeaderNames.SecWebSocketVersion, pair.Key, StringComparison.OrdinalIgnoreCase))
{
if (string.Equals(Constants.Headers.SupportedVersion, pair.Value, StringComparison.OrdinalIgnoreCase))
{
validVersion = true;
}
}
else if (string.Equals(Constants.Headers.SecWebSocketKey, pair.Key, StringComparison.OrdinalIgnoreCase))
else if (string.Equals(HeaderNames.SecWebSocketKey, pair.Key, StringComparison.OrdinalIgnoreCase))
{
validKey = IsRequestKeyValid(pair.Value);
}
@ -66,12 +67,12 @@ namespace Microsoft.AspNetCore.WebSockets.Internal
public static void GenerateResponseHeaders(string key, string subProtocol, IHeaderDictionary headers)
{
headers[Constants.Headers.Connection] = Constants.Headers.ConnectionUpgrade;
headers[Constants.Headers.Upgrade] = Constants.Headers.UpgradeWebSocket;
headers[Constants.Headers.SecWebSocketAccept] = CreateResponseKey(key);
headers[HeaderNames.Connection] = Constants.Headers.ConnectionUpgrade;
headers[HeaderNames.Upgrade] = Constants.Headers.UpgradeWebSocket;
headers[HeaderNames.SecWebSocketAccept] = CreateResponseKey(key);
if (!string.IsNullOrWhiteSpace(subProtocol))
{
headers[Constants.Headers.SecWebSocketProtocol] = subProtocol;
headers[HeaderNames.SecWebSocketProtocol] = subProtocol;
}
}
@ -118,4 +119,4 @@ namespace Microsoft.AspNetCore.WebSockets.Internal
}
}
}
}
}

View File

@ -147,7 +147,7 @@ namespace Microsoft.AspNetCore.WebSockets
}
}
string key = string.Join(", ", _context.Request.Headers[Constants.Headers.SecWebSocketKey]);
string key = string.Join(", ", _context.Request.Headers[HeaderNames.SecWebSocketKey]);
HandshakeHelpers.GenerateResponseHeaders(key, subProtocol, _context.Response.Headers);

View File

@ -12,6 +12,7 @@ using Microsoft.AspNetCore.Testing;
using Microsoft.AspNetCore.Testing.xunit;
using Microsoft.AspNetCore.WebSockets.Internal;
using Microsoft.Extensions.Logging.Testing;
using Microsoft.Net.Http.Headers;
using Xunit;
namespace Microsoft.AspNetCore.WebSockets.Test
@ -537,11 +538,11 @@ namespace Microsoft.AspNetCore.WebSockets.Test
request.Headers.Connection.Clear();
request.Headers.Connection.Add("Upgrade");
request.Headers.Upgrade.Add(new System.Net.Http.Headers.ProductHeaderValue("websocket"));
request.Headers.Add(Constants.Headers.SecWebSocketVersion, Constants.Headers.SupportedVersion);
request.Headers.Add(HeaderNames.SecWebSocketVersion, "13");
// SecWebSocketKey required to be 16 bytes
request.Headers.Add(Constants.Headers.SecWebSocketKey, Convert.ToBase64String(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }, Base64FormattingOptions.None));
request.Headers.Add(HeaderNames.SecWebSocketKey, Convert.ToBase64String(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }, Base64FormattingOptions.None));
request.Headers.Add("Origin", "http://example.com");
request.Headers.Add(HeaderNames.Origin, "http://example.com");
var response = await client.SendAsync(request);
Assert.Equal(expectedCode, response.StatusCode);

View File

@ -7,6 +7,7 @@ using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Net.Http.Headers;
using Xunit;
namespace Microsoft.AspNetCore.Mvc.FunctionalTests
@ -41,7 +42,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
// Arrange
var requestId = Guid.NewGuid().ToString();
var request = new HttpRequestMessage(HttpMethod.Get, url);
request.Headers.TryAddWithoutValidation("RequestId", requestId);
request.Headers.TryAddWithoutValidation(HeaderNames.RequestId, requestId);
// Act
var response = await Client.SendAsync(request);
@ -64,7 +65,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
{
var requestId = Guid.NewGuid().ToString();
var request = new HttpRequestMessage(HttpMethod.Get, url);
request.Headers.TryAddWithoutValidation("RequestId", requestId);
request.Headers.TryAddWithoutValidation(HeaderNames.RequestId, requestId);
var response = await Client.SendAsync(request);
@ -84,7 +85,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
// Act & Assert
var requestId1 = "b40f6ec1-8a6b-41c1-b3fe-928f581ebaf5";
var request1 = new HttpRequestMessage(HttpMethod.Get, url);
request1.Headers.TryAddWithoutValidation("RequestId", requestId1);
request1.Headers.TryAddWithoutValidation(HeaderNames.RequestId, requestId1);
var response1 = await Client.SendAsync(request1);
@ -93,7 +94,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
var requestId2 = Guid.NewGuid().ToString();
var request2 = new HttpRequestMessage(HttpMethod.Get, url);
request2.Headers.TryAddWithoutValidation("RequestId", requestId2);
request2.Headers.TryAddWithoutValidation(HeaderNames.RequestId, requestId2);
var response2 = await Client.SendAsync(request2);
Assert.Equal(HttpStatusCode.NotFound, response2.StatusCode);

View File

@ -5,6 +5,7 @@ using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Net.Http.Headers;
namespace BasicWebSite
{
@ -26,7 +27,7 @@ namespace BasicWebSite
throw new InvalidOperationException("RequestId should be null here");
}
var requestId = context.Request.Headers["RequestId"];
var requestId = context.Request.Headers[HeaderNames.RequestId];
requestIdService.RequestId = requestId;
return _next(context);

View File

@ -4,6 +4,7 @@
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Net.Http.Headers;
namespace Microsoft.AspNetCore.Authentication.Cookies
{
@ -41,7 +42,7 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
{
if (IsAjaxRequest(context.Request))
{
context.Response.Headers["Location"] = context.RedirectUri;
context.Response.Headers[HeaderNames.Location] = context.RedirectUri;
context.Response.StatusCode = 401;
}
else
@ -58,7 +59,7 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
{
if (IsAjaxRequest(context.Request))
{
context.Response.Headers["Location"] = context.RedirectUri;
context.Response.Headers[HeaderNames.Location] = context.RedirectUri;
context.Response.StatusCode = 403;
}
else
@ -75,7 +76,7 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
{
if (IsAjaxRequest(context.Request))
{
context.Response.Headers["Location"] = context.RedirectUri;
context.Response.Headers[HeaderNames.Location] = context.RedirectUri;
}
else
{
@ -91,7 +92,7 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
{
if (IsAjaxRequest(context.Request))
{
context.Response.Headers["Location"] = context.RedirectUri;
context.Response.Headers[HeaderNames.Location] = context.RedirectUri;
}
else
{
@ -155,4 +156,4 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
/// <param name="context">Contains information about the event</param>
public virtual Task RedirectToAccessDenied(RedirectContext<CookieAuthenticationOptions> context) => OnRedirectToAccessDenied(context);
}
}
}

View File

@ -63,7 +63,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
if (string.IsNullOrEmpty(token))
{
string authorization = Request.Headers["Authorization"];
string authorization = Request.Headers[HeaderNames.Authorization];
// If no authorization header found, nothing to process further
if (string.IsNullOrEmpty(authorization))

View File

@ -127,6 +127,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
return StringValues.Concat(existing, append);
}
[MethodImpl(MethodImplOptions.NoInlining)]
protected bool TryGetUnknown(string key, ref StringValues value) => MaybeUnknown?.TryGetValue(key, out value) ?? false;
[MethodImpl(MethodImplOptions.NoInlining)]
protected bool RemoveUnknown(string key) => MaybeUnknown?.Remove(key) ?? false;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
protected static int BitCount(long value)
{

View File

@ -13,6 +13,7 @@ using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Server.Kestrel.Core.Features;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
using Microsoft.Net.Http.Headers;
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{
@ -302,7 +303,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
StatusCode = StatusCodes.Status101SwitchingProtocols;
ReasonPhrase = "Switching Protocols";
ResponseHeaders["Connection"] = "Upgrade";
ResponseHeaders[HeaderNames.Connection] = "Upgrade";
await FlushAsync();

View File

@ -20,6 +20,7 @@ using Microsoft.AspNetCore.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Primitives;
using Microsoft.Net.Http.Headers;
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{
@ -903,7 +904,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
}
if (_httpVersion != Http.HttpVersion.Http10 &&
RequestHeaders.TryGetValue("Expect", out var expect) &&
RequestHeaders.TryGetValue(HeaderNames.Expect, out var expect) &&
(expect.FirstOrDefault() ?? "").Equals("100-continue", StringComparison.OrdinalIgnoreCase))
{
Output.Write100ContinueAsync().GetAwaiter().GetResult();

View File

@ -92,6 +92,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
Unknown[key] = value;
}
[MethodImpl(MethodImplOptions.NoInlining)]
private bool AddValueUnknown(string key, StringValues value)
{
Unknown.Add(key, value);
// Return true, above will throw and exit for false
return true;
}
[MethodImpl(MethodImplOptions.NoInlining)]
private unsafe void AppendUnknownHeaders(Span<byte> name, string valueString)
{

View File

@ -78,6 +78,15 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
Unknown[key] = value;
}
[MethodImpl(MethodImplOptions.NoInlining)]
private bool AddValueUnknown(string key, StringValues value)
{
ValidateHeaderNameCharacters(key);
Unknown.Add(key, value);
// Return true, above will throw and exit for false
return true;
}
public partial struct Enumerator : IEnumerator<KeyValuePair<string, StringValues>>
{
private readonly HttpResponseHeaders _collection;

View File

@ -28,6 +28,15 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
Unknown[key] = value;
}
[MethodImpl(MethodImplOptions.NoInlining)]
private bool AddValueUnknown(string key, StringValues value)
{
ValidateHeaderNameCharacters(key);
Unknown.Add(key, value);
// Return true, above will throw and exit for false
return true;
}
public partial struct Enumerator : IEnumerator<KeyValuePair<string, StringValues>>
{
private readonly HttpResponseTrailers _collection;

View File

@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved.
// 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;
@ -13,12 +13,13 @@ using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
using Microsoft.Net.Http.Headers;
namespace Microsoft.AspNetCore.Server.Kestrel.Performance
{
public class ResponseHeaderCollectionBenchmark
{
private const int InnerLoopCount = 512;
private const int InnerLoopCount = 128;
private static readonly byte[] _bytesServer = Encoding.ASCII.GetBytes("\r\nServer: Kestrel");
private static readonly DateHeaderValueManager _dateHeaderValueManager = new DateHeaderValueManager();
@ -84,7 +85,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
{
_responseHeadersDirect.Reset();
_response.Headers["Content-Length"] = "0";
_response.Headers[HeaderNames.ContentLength] = "0";
}
}
@ -118,21 +119,21 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
var headers = _response.Headers;
headers["Connection"] = "Close";
headers["Cache-Control"] = "public, max-age=30672000";
headers["Vary"] = "Accept-Encoding";
headers["Content-Encoding"] = "gzip";
headers["Expires"] = "Fri, 12 Jan 2018 22:01:55 GMT";
headers["Last-Modified"] = "Wed, 22 Jun 2016 20:08:29 GMT";
headers["Set-Cookie"] = "prov=20629ccd-8b0f-e8ef-2935-cd26609fc0bc; __qca=P0-1591065732-1479167353442; _ga=GA1.2.1298898376.1479167354; _gat=1; sgt=id=9519gfde_3347_4762_8762_df51458c8ec2; acct=t=why-is-%e0%a5%a7%e0%a5%a8%e0%a5%a9-numeric&s=why-is-%e0%a5%a7%e0%a5%a8%e0%a5%a9-numeric";
headers["ETag"] = "\"54ef7954-1078\"";
headers["Transfer-Encoding"] = "chunked";
headers["Content-Language"] = "en-gb";
headers["Upgrade"] = "websocket";
headers["Via"] = "1.1 varnish";
headers["Access-Control-Allow-Origin"] = "*";
headers["Access-Control-Allow-credentials"] = "true";
headers["Access-Control-Expose-Headers"] = "Client-Protocol, Content-Length, Content-Type, X-Bandwidth-Est, X-Bandwidth-Est2, X-Bandwidth-Est-Comp, X-Bandwidth-Avg, X-Walltime-Ms, X-Sequence-Num";
headers[HeaderNames.Connection] = "Close";
headers[HeaderNames.CacheControl] = "public, max-age=30672000";
headers[HeaderNames.Vary] = "Accept-Encoding";
headers[HeaderNames.ContentEncoding] = "gzip";
headers[HeaderNames.Expires] = "Fri, 12 Jan 2018 22:01:55 GMT";
headers[HeaderNames.LastModified] = "Wed, 22 Jun 2016 20:08:29 GMT";
headers[HeaderNames.SetCookie] = "prov=20629ccd-8b0f-e8ef-2935-cd26609fc0bc; __qca=P0-1591065732-1479167353442; _ga=GA1.2.1298898376.1479167354; _gat=1; sgt=id=9519gfde_3347_4762_8762_df51458c8ec2; acct=t=why-is-%e0%a5%a7%e0%a5%a8%e0%a5%a9-numeric&s=why-is-%e0%a5%a7%e0%a5%a8%e0%a5%a9-numeric";
headers[HeaderNames.ETag] = "\"54ef7954-1078\"";
headers[HeaderNames.TransferEncoding] = "chunked";
headers[HeaderNames.ContentLanguage] = "en-gb";
headers[HeaderNames.Upgrade] = "websocket";
headers[HeaderNames.Via] = "1.1 varnish";
headers[HeaderNames.AccessControlAllowOrigin] = "*";
headers[HeaderNames.AccessControlAllowCredentials] = "true";
headers[HeaderNames.AccessControlExposeHeaders] = "Client-Protocol, Content-Length, Content-Type, X-Bandwidth-Est, X-Bandwidth-Est2, X-Bandwidth-Est-Comp, X-Bandwidth-Avg, X-Walltime-Ms, X-Sequence-Num";
var dateHeaderValues = _dateHeaderValueManager.GetDateHeaderValues();
_responseHeadersDirect.SetRawDate(dateHeaderValues.String, dateHeaderValues.Bytes);
@ -159,8 +160,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
headers["X-Content-Type-Options"] = "nosniff";
headers["X-Xss-Protection"] = "1; mode=block";
headers["X-Frame-Options"] = "SAMEORIGIN";
headers["Strict-Transport-Security"] = "max-age=31536000; includeSubDomains; preload";
headers["Content-Security-Policy"] = "default-src 'none'; script-src 'self' cdnjs.cloudflare.com code.jquery.com scotthelme.disqus.com a.disquscdn.com www.google-analytics.com go.disqus.com platform.twitter.com cdn.syndication.twimg.com; style-src 'self' a.disquscdn.com fonts.googleapis.com cdnjs.cloudflare.com platform.twitter.com; img-src 'self' data: www.gravatar.com www.google-analytics.com links.services.disqus.com referrer.disqus.com a.disquscdn.com cdn.syndication.twimg.com syndication.twitter.com pbs.twimg.com platform.twitter.com abs.twimg.com; child-src fusiontables.googleusercontent.com fusiontables.google.com www.google.com disqus.com www.youtube.com syndication.twitter.com platform.twitter.com; frame-src fusiontables.googleusercontent.com fusiontables.google.com www.google.com disqus.com www.youtube.com syndication.twitter.com platform.twitter.com; connect-src 'self' links.services.disqus.com; font-src 'self' cdnjs.cloudflare.com fonts.gstatic.com fonts.googleapis.com; form-action 'self'; upgrade-insecure-requests;";
headers[HeaderNames.StrictTransportSecurity] = "max-age=31536000; includeSubDomains; preload";
headers[HeaderNames.ContentSecurityPolicy] = "default-src 'none'; script-src 'self' cdnjs.cloudflare.com code.jquery.com scotthelme.disqus.com a.disquscdn.com www.google-analytics.com go.disqus.com platform.twitter.com cdn.syndication.twimg.com; style-src 'self' a.disquscdn.com fonts.googleapis.com cdnjs.cloudflare.com platform.twitter.com; img-src 'self' data: www.gravatar.com www.google-analytics.com links.services.disqus.com referrer.disqus.com a.disquscdn.com cdn.syndication.twimg.com syndication.twitter.com pbs.twimg.com platform.twitter.com abs.twimg.com; child-src fusiontables.googleusercontent.com fusiontables.google.com www.google.com disqus.com www.youtube.com syndication.twitter.com platform.twitter.com; frame-src fusiontables.googleusercontent.com fusiontables.google.com www.google.com disqus.com www.youtube.com syndication.twitter.com platform.twitter.com; connect-src 'self' links.services.disqus.com; font-src 'self' cdnjs.cloudflare.com fonts.gstatic.com fonts.googleapis.com; form-action 'self'; upgrade-insecure-requests;";
var dateHeaderValues = _dateHeaderValueManager.GetDateHeaderValues();
_responseHeadersDirect.SetRawDate(dateHeaderValues.String, dateHeaderValues.Bytes);

View File

@ -11,6 +11,7 @@ using BenchmarkDotNet.Attributes;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
using Microsoft.Net.Http.Headers;
namespace Microsoft.AspNetCore.Server.Kestrel.Performance
{
@ -82,7 +83,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
var responseHeaders = _responseHeaders;
responseHeaders.HeaderContentEncoding = "gzip";
responseHeaders.HeaderContentType = "text/html; charset=utf-8";
_responseHeadersDict["Strict-Transport-Security"] = "max-age=31536000; includeSubdomains";
_responseHeadersDict[HeaderNames.StrictTransportSecurity] = "max-age=31536000; includeSubdomains";
responseHeaders.HeaderVary = "Accept-Encoding";
_responseHeadersDict["X-Powered-By"] = "ASP.NET";

View File

@ -94,7 +94,11 @@ namespace CodeGenerator
"Translate",
"User-Agent",
"DNT",
"Upgrade-Insecure-Requests"
"Upgrade-Insecure-Requests",
"Request-Id",
"Correlation-Context",
"TraceParent",
"TraceState"
})
.Concat(corsRequestHeaders)
.Select((header, index) => new KnownHeader
@ -539,21 +543,21 @@ namespace CodeGenerator
new
{
Headers = requestHeaders,
HeadersByLength = requestHeaders.GroupBy(x => x.Name.Length),
HeadersByLength = requestHeaders.OrderBy(x => x.Name.Length).GroupBy(x => x.Name.Length),
ClassName = "HttpRequestHeaders",
Bytes = default(byte[])
},
new
{
Headers = responseHeaders,
HeadersByLength = responseHeaders.GroupBy(x => x.Name.Length),
HeadersByLength = responseHeaders.OrderBy(x => x.Name.Length).GroupBy(x => x.Name.Length),
ClassName = "HttpResponseHeaders",
Bytes = responseHeaders.SelectMany(header => header.Bytes).ToArray()
},
new
{
Headers = responseTrailers,
HeadersByLength = responseTrailers.GroupBy(x => x.Name.Length),
HeadersByLength = responseTrailers.OrderBy(x => x.Name.Length).GroupBy(x => x.Name.Length),
ClassName = "HttpResponseTrailers",
Bytes = responseTrailers.SelectMany(header => header.Bytes).ToArray()
}
@ -647,27 +651,43 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
switch (key.Length)
{{{Each(loop.HeadersByLength, byLength => $@"
case {byLength.Key}:
{{{Each(byLength, header => $@"
if (""{header.Name}"".Equals(key, StringComparison.OrdinalIgnoreCase))
{{{(header.Identifier == "ContentLength" ? @"
if (_contentLength.HasValue)
{
value = HeaderUtilities.FormatNonNegativeInt64(_contentLength.Value);
return true;
}
return false;" : $@"
if ({header.TestBit()})
{{
value = _headers._{header.Identifier};
return true;
}}
return false;")}
}}")}
}}
break;")}
{{{Each(byLength.OrderBy(h => !h.PrimaryHeader), header => $@"
if (ReferenceEquals(HeaderNames.{header.Identifier}, key))
{{{(header.Identifier == "ContentLength" ? @"
if (_contentLength.HasValue)
{
value = HeaderUtilities.FormatNonNegativeInt64(_contentLength.Value);
return true;
}
return false;" : $@"
if ({header.TestBit()})
{{
value = _headers._{header.Identifier};
return true;
}}
return false;")}
}}")}
{Each(byLength.OrderBy(h => !h.PrimaryHeader), header => $@"
if (HeaderNames.{header.Identifier}.Equals(key, StringComparison.OrdinalIgnoreCase))
{{{(header.Identifier == "ContentLength" ? @"
if (_contentLength.HasValue)
{
value = HeaderUtilities.FormatNonNegativeInt64(_contentLength.Value);
return true;
}
return false;" : $@"
if ({header.TestBit()})
{{
value = _headers._{header.Identifier};
return true;
}}
return false;")}
}}")}
break;
}}")}
}}
return MaybeUnknown?.TryGetValue(key, out value) ?? false;
return TryGetUnknown(key, ref value);
}}
protected override void SetValueFast(string key, StringValues value)
@ -676,17 +696,26 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
switch (key.Length)
{{{Each(loop.HeadersByLength, byLength => $@"
case {byLength.Key}:
{{{Each(byLength, header => $@"
if (""{header.Name}"".Equals(key, StringComparison.OrdinalIgnoreCase))
{{{(header.Identifier == "ContentLength" ? $@"
_contentLength = ParseContentLength(value.ToString());" : $@"
{header.SetBit()};
_headers._{header.Identifier} = value;{(header.EnhancedSetter == false ? "" : $@"
_headers._raw{header.Identifier} = null;")}")}
return;
}}")}
}}
break;")}
{{{Each(byLength.OrderBy(h => !h.PrimaryHeader), header => $@"
if (ReferenceEquals(HeaderNames.{header.Identifier}, key))
{{{(header.Identifier == "ContentLength" ? $@"
_contentLength = ParseContentLength(value.ToString());" : $@"
{header.SetBit()};
_headers._{header.Identifier} = value;{(header.EnhancedSetter == false ? "" : $@"
_headers._raw{header.Identifier} = null;")}")}
return;
}}")}
{Each(byLength.OrderBy(h => !h.PrimaryHeader), header => $@"
if (HeaderNames.{header.Identifier}.Equals(key, StringComparison.OrdinalIgnoreCase))
{{{(header.Identifier == "ContentLength" ? $@"
_contentLength = ParseContentLength(value.ToString());" : $@"
{header.SetBit()};
_headers._{header.Identifier} = value;{(header.EnhancedSetter == false ? "" : $@"
_headers._raw{header.Identifier} = null;")}")}
return;
}}")}
break;
}}")}
}}
SetValueUnknown(key, value);
@ -698,32 +727,47 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
switch (key.Length)
{{{Each(loop.HeadersByLength, byLength => $@"
case {byLength.Key}:
{{{Each(byLength, header => $@"
if (""{header.Name}"".Equals(key, StringComparison.OrdinalIgnoreCase))
{{{(header.Identifier == "ContentLength" ? $@"
if (!_contentLength.HasValue)
{{
_contentLength = ParseContentLength(value);
return true;
}}
return false;" : $@"
if ({header.TestNotBit()})
{{
{header.SetBit()};
_headers._{header.Identifier} = value;{(header.EnhancedSetter == false ? "" : $@"
_headers._raw{header.Identifier} = null;")}
return true;
}}
return false;")}
}}")}
}}
break;")}
{{{Each(byLength.OrderBy(h => !h.PrimaryHeader), header => $@"
if (ReferenceEquals(HeaderNames.{header.Identifier}, key))
{{{(header.Identifier == "ContentLength" ? $@"
if (!_contentLength.HasValue)
{{
_contentLength = ParseContentLength(value);
return true;
}}
return false;" : $@"
if ({header.TestNotBit()})
{{
{header.SetBit()};
_headers._{header.Identifier} = value;{(header.EnhancedSetter == false ? "" : $@"
_headers._raw{header.Identifier} = null;")}
return true;
}}
return false;")}
}}")}
{Each(byLength.OrderBy(h => !h.PrimaryHeader), header => $@"
if (HeaderNames.{header.Identifier}.Equals(key, StringComparison.OrdinalIgnoreCase))
{{{(header.Identifier == "ContentLength" ? $@"
if (!_contentLength.HasValue)
{{
_contentLength = ParseContentLength(value);
return true;
}}
return false;" : $@"
if ({header.TestNotBit()})
{{
{header.SetBit()};
_headers._{header.Identifier} = value;{(header.EnhancedSetter == false ? "" : $@"
_headers._raw{header.Identifier} = null;")}
return true;
}}
return false;")}
}}")}
break;
}}")}
}}
{(loop.ClassName == "HttpResponseHeaders" ? @"
ValidateHeaderNameCharacters(key);" : "")}
Unknown.Add(key, value);
// Return true, above will throw and exit for false
return true;
return AddValueUnknown(key, value);
}}
protected override bool RemoveFast(string key)
@ -731,29 +775,47 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
switch (key.Length)
{{{Each(loop.HeadersByLength, byLength => $@"
case {byLength.Key}:
{{{Each(byLength, header => $@"
if (""{header.Name}"".Equals(key, StringComparison.OrdinalIgnoreCase))
{{{(header.Identifier == "ContentLength" ? @"
if (_contentLength.HasValue)
{
_contentLength = null;
return true;
}
return false;" : $@"
if ({header.TestBit()})
{{
{header.ClearBit()};
_headers._{header.Identifier} = default(StringValues);{(header.EnhancedSetter == false ? "" : $@"
_headers._raw{header.Identifier} = null;")}
return true;
}}
return false;")}
}}")}
}}
break;")}
{{{Each(byLength.OrderBy(h => !h.PrimaryHeader), header => $@"
if (ReferenceEquals(HeaderNames.{header.Identifier}, key))
{{{(header.Identifier == "ContentLength" ? @"
if (_contentLength.HasValue)
{
_contentLength = null;
return true;
}
return false;" : $@"
if ({header.TestBit()})
{{
{header.ClearBit()};
_headers._{header.Identifier} = default(StringValues);{(header.EnhancedSetter == false ? "" : $@"
_headers._raw{header.Identifier} = null;")}
return true;
}}
return false;")}
}}")}
{Each(byLength.OrderBy(h => !h.PrimaryHeader), header => $@"
if (HeaderNames.{header.Identifier}.Equals(key, StringComparison.OrdinalIgnoreCase))
{{{(header.Identifier == "ContentLength" ? @"
if (_contentLength.HasValue)
{
_contentLength = null;
return true;
}
return false;" : $@"
if ({header.TestBit()})
{{
{header.ClearBit()};
_headers._{header.Identifier} = default(StringValues);{(header.EnhancedSetter == false ? "" : $@"
_headers._raw{header.Identifier} = null;")}
return true;
}}
return false;")}
}}")}
break;
}}")}
}}
return MaybeUnknown?.Remove(key) ?? false;
return RemoveUnknown(key);
}}
{(loop.ClassName != "HttpRequestHeaders" ?
$@" protected override void ClearFast()
@ -770,7 +832,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{Each(loop.Headers.Where(header => header.Identifier != "ContentLength").OrderBy(h => !h.PrimaryHeader), header => $@"
if ({header.TestTempBit()})
{{
_headers._{header.Identifier} = default(StringValues);
_headers._{header.Identifier} = default;
if({header.TestNotTempBit()})
{{
return;
@ -786,7 +848,7 @@ $@" private void Clear(long bitsToClear)
{Each(loop.Headers.Where(header => header.Identifier != "ContentLength").OrderBy(h => !h.PrimaryHeader), header => $@"
if ({header.TestTempBit()})
{{
_headers._{header.Identifier} = default(StringValues);
_headers._{header.Identifier} = default;
if({header.TestNotTempBit()})
{{
return;
@ -809,7 +871,7 @@ $@" private void Clear(long bitsToClear)
{{
return false;
}}
array[arrayIndex] = new KeyValuePair<string, StringValues>(""{header.Name}"", _headers._{header.Identifier});
array[arrayIndex] = new KeyValuePair<string, StringValues>(HeaderNames.{header.Identifier}, _headers._{header.Identifier});
++arrayIndex;
}}")}
if (_contentLength.HasValue)
@ -818,7 +880,7 @@ $@" private void Clear(long bitsToClear)
{{
return false;
}}
array[arrayIndex] = new KeyValuePair<string, StringValues>(""Content-Length"", HeaderUtilities.FormatNonNegativeInt64(_contentLength.Value));
array[arrayIndex] = new KeyValuePair<string, StringValues>(HeaderNames.ContentLength, HeaderUtilities.FormatNonNegativeInt64(_contentLength.Value));
++arrayIndex;
}}
((ICollection<KeyValuePair<string, StringValues>>)MaybeUnknown)?.CopyTo(array, arrayIndex);
@ -970,14 +1032,14 @@ $@" private void Clear(long bitsToClear)
Header{header.Identifier}: // case {header.Index}
if ({header.TestBit()})
{{
_current = new KeyValuePair<string, StringValues>(""{header.Name}"", _collection._headers._{header.Identifier});
_current = new KeyValuePair<string, StringValues>(HeaderNames.{header.Identifier}, _collection._headers._{header.Identifier});
_next = {header.Index + 1};
return true;
}}")}
{(!loop.ClassName.Contains("Trailers") ? $@"HeaderContentLength: // case {loop.Headers.Count() - 1}
if (_collection._contentLength.HasValue)
{{
_current = new KeyValuePair<string, StringValues>(""Content-Length"", HeaderUtilities.FormatNonNegativeInt64(_collection._contentLength.Value));
_current = new KeyValuePair<string, StringValues>(HeaderNames.ContentLength, HeaderUtilities.FormatNonNegativeInt64(_collection._contentLength.Value));
_next = {loop.Headers.Count()};
return true;
}}" : "")}

View File

@ -273,8 +273,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
}
[Theory]
[InlineData(HeaderNames.Path, "/")]
[InlineData(HeaderNames.Scheme, "http")]
[InlineData(":path", "/")]
[InlineData(":scheme", "http")]
public async Task HEADERS_Received_CONNECTMethod_WithSchemeOrPath_Reset(string headerName, string value)
{
await InitializeConnectionAsync(_noopApplication);

View File

@ -7,6 +7,7 @@ using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.Extensions.Logging;
using Microsoft.Net.Http.Headers;
namespace Microsoft.AspNetCore.Http.Connections.Internal.Transports
{
@ -26,13 +27,13 @@ namespace Microsoft.AspNetCore.Http.Connections.Internal.Transports
public async Task ProcessRequestAsync(HttpContext context, CancellationToken token)
{
context.Response.ContentType = "text/event-stream";
context.Response.Headers["Cache-Control"] = "no-cache";
context.Response.Headers[HeaderNames.CacheControl] = "no-cache";
// Make sure we disable all response buffering for SSE
var bufferingFeature = context.Features.Get<IHttpBufferingFeature>();
bufferingFeature?.DisableResponseBuffering();
context.Response.Headers["Content-Encoding"] = "identity";
context.Response.Headers[HeaderNames.ContentEncoding] = "identity";
// Workaround for a Firefox bug where EventSource won't fire the open event
// until it receives some data