Cache some Headers lookups (#9618)

This commit is contained in:
Ben Adams 2019-04-22 04:37:56 +01:00 committed by Justin Kotalik
parent 667f7ca491
commit 19ce372887
6 changed files with 51 additions and 44 deletions

View File

@ -79,8 +79,8 @@ namespace Microsoft.AspNetCore.Cors.Infrastructure
throw new ArgumentException(Resources.InsecureConfiguration, nameof(policy)); throw new ArgumentException(Resources.InsecureConfiguration, nameof(policy));
} }
var origin = context.Request.Headers[CorsConstants.Origin];
var requestHeaders = context.Request.Headers; var requestHeaders = context.Request.Headers;
var origin = requestHeaders[CorsConstants.Origin];
var isOptionsRequest = string.Equals(context.Request.Method, CorsConstants.PreflightHttpMethod, StringComparison.OrdinalIgnoreCase); var isOptionsRequest = string.Equals(context.Request.Method, CorsConstants.PreflightHttpMethod, StringComparison.OrdinalIgnoreCase);
var isPreflightRequest = isOptionsRequest && requestHeaders.ContainsKey(CorsConstants.AccessControlRequestMethod); var isPreflightRequest = isOptionsRequest && requestHeaders.ContainsKey(CorsConstants.AccessControlRequestMethod);
@ -110,6 +110,7 @@ namespace Microsoft.AspNetCore.Cors.Infrastructure
private static void PopulateResult(HttpContext context, CorsPolicy policy, CorsResult result) private static void PopulateResult(HttpContext context, CorsPolicy policy, CorsResult result)
{ {
var headers = context.Request.Headers;
if (policy.AllowAnyOrigin) if (policy.AllowAnyOrigin)
{ {
result.AllowedOrigin = CorsConstants.AnyOrigin; result.AllowedOrigin = CorsConstants.AnyOrigin;
@ -117,7 +118,7 @@ namespace Microsoft.AspNetCore.Cors.Infrastructure
} }
else else
{ {
var origin = context.Request.Headers[CorsConstants.Origin]; var origin = headers[CorsConstants.Origin];
result.AllowedOrigin = origin; result.AllowedOrigin = origin;
result.VaryByOrigin = policy.Origins.Count > 1; result.VaryByOrigin = policy.Origins.Count > 1;
} }
@ -129,12 +130,12 @@ namespace Microsoft.AspNetCore.Cors.Infrastructure
AddHeaderValues(result.AllowedExposedHeaders, policy.ExposedHeaders); AddHeaderValues(result.AllowedExposedHeaders, policy.ExposedHeaders);
var allowedMethods = policy.AllowAnyMethod ? var allowedMethods = policy.AllowAnyMethod ?
new[] { result.IsPreflightRequest ? (string)context.Request.Headers[CorsConstants.AccessControlRequestMethod] : context.Request.Method } : new[] { result.IsPreflightRequest ? (string)headers[CorsConstants.AccessControlRequestMethod] : context.Request.Method } :
policy.Methods; policy.Methods;
AddHeaderValues(result.AllowedMethods, allowedMethods); AddHeaderValues(result.AllowedMethods, allowedMethods);
var allowedHeaders = policy.AllowAnyHeader ? var allowedHeaders = policy.AllowAnyHeader ?
context.Request.Headers.GetCommaSeparatedValues(CorsConstants.AccessControlRequestHeaders) : headers.GetCommaSeparatedValues(CorsConstants.AccessControlRequestHeaders) :
policy.Headers; policy.Headers;
AddHeaderValues(result.AllowedHeaders, allowedHeaders); AddHeaderValues(result.AllowedHeaders, allowedHeaders);
} }
@ -169,11 +170,12 @@ namespace Microsoft.AspNetCore.Cors.Infrastructure
return; return;
} }
response.Headers[CorsConstants.AccessControlAllowOrigin] = result.AllowedOrigin; var headers = response.Headers;
headers[CorsConstants.AccessControlAllowOrigin] = result.AllowedOrigin;
if (result.SupportsCredentials) if (result.SupportsCredentials)
{ {
response.Headers[CorsConstants.AccessControlAllowCredentials] = "true"; headers[CorsConstants.AccessControlAllowCredentials] = "true";
} }
if (result.IsPreflightRequest) if (result.IsPreflightRequest)
@ -184,17 +186,17 @@ namespace Microsoft.AspNetCore.Cors.Infrastructure
// `Access-Control-Allow-Methods`, `Access-Control-Allow-Headers`, `Access-Control-Max-Age` // `Access-Control-Allow-Methods`, `Access-Control-Allow-Headers`, `Access-Control-Max-Age`
if (result.AllowedHeaders.Count > 0) if (result.AllowedHeaders.Count > 0)
{ {
response.Headers.SetCommaSeparatedValues(CorsConstants.AccessControlAllowHeaders, result.AllowedHeaders.ToArray()); headers.SetCommaSeparatedValues(CorsConstants.AccessControlAllowHeaders, result.AllowedHeaders.ToArray());
} }
if (result.AllowedMethods.Count > 0) if (result.AllowedMethods.Count > 0)
{ {
response.Headers.SetCommaSeparatedValues(CorsConstants.AccessControlAllowMethods, result.AllowedMethods.ToArray()); headers.SetCommaSeparatedValues(CorsConstants.AccessControlAllowMethods, result.AllowedMethods.ToArray());
} }
if (result.PreflightMaxAge.HasValue) if (result.PreflightMaxAge.HasValue)
{ {
response.Headers[CorsConstants.AccessControlMaxAge] = result.PreflightMaxAge.Value.TotalSeconds.ToString(CultureInfo.InvariantCulture); headers[CorsConstants.AccessControlMaxAge] = result.PreflightMaxAge.Value.TotalSeconds.ToString(CultureInfo.InvariantCulture);
} }
} }
else else
@ -203,13 +205,13 @@ namespace Microsoft.AspNetCore.Cors.Infrastructure
// `Access-Control-Expose-Headers` // `Access-Control-Expose-Headers`
if (result.AllowedExposedHeaders.Count > 0) if (result.AllowedExposedHeaders.Count > 0)
{ {
response.Headers.SetCommaSeparatedValues(CorsConstants.AccessControlExposeHeaders, result.AllowedExposedHeaders.ToArray()); headers.SetCommaSeparatedValues(CorsConstants.AccessControlExposeHeaders, result.AllowedExposedHeaders.ToArray());
} }
} }
if (result.VaryByOrigin) if (result.VaryByOrigin)
{ {
response.Headers.Append("Vary", "Origin"); headers.Append("Vary", "Origin");
} }
} }

View File

@ -104,12 +104,12 @@ namespace Microsoft.AspNetCore.Diagnostics
private Task ClearCacheHeaders(object state) private Task ClearCacheHeaders(object state)
{ {
var response = (HttpResponse)state; var headers = ((HttpResponse)state).Headers;
response.Headers[HeaderNames.CacheControl] = "no-cache"; headers[HeaderNames.CacheControl] = "no-cache";
response.Headers[HeaderNames.Pragma] = "no-cache"; headers[HeaderNames.Pragma] = "no-cache";
response.Headers[HeaderNames.Expires] = "-1"; headers[HeaderNames.Expires] = "-1";
response.Headers.Remove(HeaderNames.ETag); headers.Remove(HeaderNames.ETag);
return Task.CompletedTask; return Task.CompletedTask;
} }
} }
} }

View File

@ -150,17 +150,19 @@ namespace Microsoft.AspNetCore.HttpOverrides
bool checkFor = false, checkProto = false, checkHost = false; bool checkFor = false, checkProto = false, checkHost = false;
int entryCount = 0; int entryCount = 0;
var request = context.Request;
var requestHeaders = context.Request.Headers;
if ((_options.ForwardedHeaders & ForwardedHeaders.XForwardedFor) == ForwardedHeaders.XForwardedFor) if ((_options.ForwardedHeaders & ForwardedHeaders.XForwardedFor) == ForwardedHeaders.XForwardedFor)
{ {
checkFor = true; checkFor = true;
forwardedFor = context.Request.Headers.GetCommaSeparatedValues(_options.ForwardedForHeaderName); forwardedFor = requestHeaders.GetCommaSeparatedValues(_options.ForwardedForHeaderName);
entryCount = Math.Max(forwardedFor.Length, entryCount); entryCount = Math.Max(forwardedFor.Length, entryCount);
} }
if ((_options.ForwardedHeaders & ForwardedHeaders.XForwardedProto) == ForwardedHeaders.XForwardedProto) if ((_options.ForwardedHeaders & ForwardedHeaders.XForwardedProto) == ForwardedHeaders.XForwardedProto)
{ {
checkProto = true; checkProto = true;
forwardedProto = context.Request.Headers.GetCommaSeparatedValues(_options.ForwardedProtoHeaderName); forwardedProto = requestHeaders.GetCommaSeparatedValues(_options.ForwardedProtoHeaderName);
if (_options.RequireHeaderSymmetry && checkFor && forwardedFor.Length != forwardedProto.Length) if (_options.RequireHeaderSymmetry && checkFor && forwardedFor.Length != forwardedProto.Length)
{ {
_logger.LogWarning(1, "Parameter count mismatch between X-Forwarded-For and X-Forwarded-Proto."); _logger.LogWarning(1, "Parameter count mismatch between X-Forwarded-For and X-Forwarded-Proto.");
@ -172,7 +174,7 @@ namespace Microsoft.AspNetCore.HttpOverrides
if ((_options.ForwardedHeaders & ForwardedHeaders.XForwardedHost) == ForwardedHeaders.XForwardedHost) if ((_options.ForwardedHeaders & ForwardedHeaders.XForwardedHost) == ForwardedHeaders.XForwardedHost)
{ {
checkHost = true; checkHost = true;
forwardedHost = context.Request.Headers.GetCommaSeparatedValues(_options.ForwardedHostHeaderName); forwardedHost = requestHeaders.GetCommaSeparatedValues(_options.ForwardedHostHeaderName);
if (_options.RequireHeaderSymmetry if (_options.RequireHeaderSymmetry
&& ((checkFor && forwardedFor.Length != forwardedHost.Length) && ((checkFor && forwardedFor.Length != forwardedHost.Length)
|| (checkProto && forwardedProto.Length != forwardedHost.Length))) || (checkProto && forwardedProto.Length != forwardedHost.Length)))
@ -212,7 +214,6 @@ namespace Microsoft.AspNetCore.HttpOverrides
// Gather initial values // Gather initial values
var connection = context.Connection; var connection = context.Connection;
var request = context.Request;
var currentValues = new SetOfForwarders() var currentValues = new SetOfForwarders()
{ {
RemoteIpAndPort = connection.RemoteIpAddress != null ? new IPEndPoint(connection.RemoteIpAddress, connection.RemotePort) : null, RemoteIpAndPort = connection.RemoteIpAddress != null ? new IPEndPoint(connection.RemoteIpAddress, connection.RemotePort) : null,
@ -293,17 +294,17 @@ namespace Microsoft.AspNetCore.HttpOverrides
if (connection.RemoteIpAddress != null) if (connection.RemoteIpAddress != null)
{ {
// Save the original // Save the original
request.Headers[_options.OriginalForHeaderName] = new IPEndPoint(connection.RemoteIpAddress, connection.RemotePort).ToString(); requestHeaders[_options.OriginalForHeaderName] = new IPEndPoint(connection.RemoteIpAddress, connection.RemotePort).ToString();
} }
if (forwardedFor.Length > entriesConsumed) if (forwardedFor.Length > entriesConsumed)
{ {
// Truncate the consumed header values // Truncate the consumed header values
request.Headers[_options.ForwardedForHeaderName] = forwardedFor.Take(forwardedFor.Length - entriesConsumed).ToArray(); requestHeaders[_options.ForwardedForHeaderName] = forwardedFor.Take(forwardedFor.Length - entriesConsumed).ToArray();
} }
else else
{ {
// All values were consumed // All values were consumed
request.Headers.Remove(_options.ForwardedForHeaderName); requestHeaders.Remove(_options.ForwardedForHeaderName);
} }
connection.RemoteIpAddress = currentValues.RemoteIpAndPort.Address; connection.RemoteIpAddress = currentValues.RemoteIpAndPort.Address;
connection.RemotePort = currentValues.RemoteIpAndPort.Port; connection.RemotePort = currentValues.RemoteIpAndPort.Port;
@ -312,16 +313,16 @@ namespace Microsoft.AspNetCore.HttpOverrides
if (checkProto && currentValues.Scheme != null) if (checkProto && currentValues.Scheme != null)
{ {
// Save the original // Save the original
request.Headers[_options.OriginalProtoHeaderName] = request.Scheme; requestHeaders[_options.OriginalProtoHeaderName] = request.Scheme;
if (forwardedProto.Length > entriesConsumed) if (forwardedProto.Length > entriesConsumed)
{ {
// Truncate the consumed header values // Truncate the consumed header values
request.Headers[_options.ForwardedProtoHeaderName] = forwardedProto.Take(forwardedProto.Length - entriesConsumed).ToArray(); requestHeaders[_options.ForwardedProtoHeaderName] = forwardedProto.Take(forwardedProto.Length - entriesConsumed).ToArray();
} }
else else
{ {
// All values were consumed // All values were consumed
request.Headers.Remove(_options.ForwardedProtoHeaderName); requestHeaders.Remove(_options.ForwardedProtoHeaderName);
} }
request.Scheme = currentValues.Scheme; request.Scheme = currentValues.Scheme;
} }
@ -329,16 +330,16 @@ namespace Microsoft.AspNetCore.HttpOverrides
if (checkHost && currentValues.Host != null) if (checkHost && currentValues.Host != null)
{ {
// Save the original // Save the original
request.Headers[_options.OriginalHostHeaderName] = request.Host.ToString(); requestHeaders[_options.OriginalHostHeaderName] = request.Host.ToString();
if (forwardedHost.Length > entriesConsumed) if (forwardedHost.Length > entriesConsumed)
{ {
// Truncate the consumed header values // Truncate the consumed header values
request.Headers[_options.ForwardedHostHeaderName] = forwardedHost.Take(forwardedHost.Length - entriesConsumed).ToArray(); requestHeaders[_options.ForwardedHostHeaderName] = forwardedHost.Take(forwardedHost.Length - entriesConsumed).ToArray();
} }
else else
{ {
// All values were consumed // All values were consumed
request.Headers.Remove(_options.ForwardedHostHeaderName); requestHeaders.Remove(_options.ForwardedHostHeaderName);
} }
request.Host = HostString.FromUriComponent(currentValues.Host); request.Host = HostString.FromUriComponent(currentValues.Host);
} }

View File

@ -110,19 +110,21 @@ namespace Microsoft.AspNetCore.ResponseCaching.Internal
builder.Append(varyByRules.VaryByKeyPrefix); builder.Append(varyByRules.VaryByKeyPrefix);
// Vary by headers // Vary by headers
if (varyByRules?.Headers.Count > 0) var headersCount = varyByRules?.Headers.Count ?? 0;
if (headersCount > 0)
{ {
// Append a group separator for the header segment of the cache key // Append a group separator for the header segment of the cache key
builder.Append(KeyDelimiter) builder.Append(KeyDelimiter)
.Append('H'); .Append('H');
for (var i = 0; i < varyByRules.Headers.Count; i++) var requestHeaders = context.HttpContext.Request.Headers;
for (var i = 0; i < headersCount; i++)
{ {
var header = varyByRules.Headers[i]; var header = varyByRules.Headers[i];
var headerValues = context.HttpContext.Request.Headers[header]; var headerValues = requestHeaders[header];
builder.Append(KeyDelimiter) builder.Append(KeyDelimiter)
.Append(header) .Append(header)
.Append("="); .Append('=');
var headerValuesArray = headerValues.ToArray(); var headerValuesArray = headerValues.ToArray();
Array.Sort(headerValuesArray, StringComparer.Ordinal); Array.Sort(headerValuesArray, StringComparer.Ordinal);
@ -152,7 +154,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Internal
{ {
builder.Append(KeyDelimiter) builder.Append(KeyDelimiter)
.AppendUpperInvariant(queryArray[i].Key) .AppendUpperInvariant(queryArray[i].Key)
.Append("="); .Append('=');
var queryValueArray = queryArray[i].Value.ToArray(); var queryValueArray = queryArray[i].Value.ToArray();
Array.Sort(queryValueArray, StringComparer.Ordinal); Array.Sort(queryValueArray, StringComparer.Ordinal);
@ -176,7 +178,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Internal
var queryKeyValues = context.HttpContext.Request.Query[queryKey]; var queryKeyValues = context.HttpContext.Request.Query[queryKey];
builder.Append(KeyDelimiter) builder.Append(KeyDelimiter)
.Append(queryKey) .Append(queryKey)
.Append("="); .Append('=');
var queryValueArray = queryKeyValues.ToArray(); var queryValueArray = queryKeyValues.ToArray();
Array.Sort(queryValueArray, StringComparer.Ordinal); Array.Sort(queryValueArray, StringComparer.Ordinal);

View File

@ -33,12 +33,12 @@ namespace Microsoft.AspNetCore.ResponseCaching.Internal
public virtual bool AllowCacheLookup(ResponseCachingContext context) public virtual bool AllowCacheLookup(ResponseCachingContext context)
{ {
var request = context.HttpContext.Request; var requestHeaders = context.HttpContext.Request.Headers;
// Verify request cache-control parameters // Verify request cache-control parameters
if (!StringValues.IsNullOrEmpty(request.Headers[HeaderNames.CacheControl])) if (!StringValues.IsNullOrEmpty(requestHeaders[HeaderNames.CacheControl]))
{ {
if (HeaderUtilities.ContainsCacheDirective(request.Headers[HeaderNames.CacheControl], CacheControlHeaderValue.NoCacheString)) if (HeaderUtilities.ContainsCacheDirective(requestHeaders[HeaderNames.CacheControl], CacheControlHeaderValue.NoCacheString))
{ {
context.Logger.RequestWithNoCacheNotCacheable(); context.Logger.RequestWithNoCacheNotCacheable();
return false; return false;
@ -47,7 +47,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Internal
else else
{ {
// Support for legacy HTTP 1.0 cache directive // Support for legacy HTTP 1.0 cache directive
if (HeaderUtilities.ContainsCacheDirective(request.Headers[HeaderNames.Pragma], CacheControlHeaderValue.NoCacheString)) if (HeaderUtilities.ContainsCacheDirective(requestHeaders[HeaderNames.Pragma], CacheControlHeaderValue.NoCacheString))
{ {
context.Logger.RequestWithPragmaNoCacheNotCacheable(); context.Logger.RequestWithPragmaNoCacheNotCacheable();
return false; return false;

View File

@ -158,11 +158,13 @@ namespace Microsoft.AspNetCore.Session
{ {
var cookieOptions = _options.Cookie.Build(_context); var cookieOptions = _options.Cookie.Build(_context);
_context.Response.Cookies.Append(_options.Cookie.Name, _cookieValue, cookieOptions); var response = _context.Response;
response.Cookies.Append(_options.Cookie.Name, _cookieValue, cookieOptions);
_context.Response.Headers[HeaderNames.CacheControl] = "no-cache"; var responseHeaders = response.Headers;
_context.Response.Headers[HeaderNames.Pragma] = "no-cache"; responseHeaders[HeaderNames.CacheControl] = "no-cache";
_context.Response.Headers[HeaderNames.Expires] = "-1"; responseHeaders[HeaderNames.Pragma] = "no-cache";
responseHeaders[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. // Returns true if the session has already been established, or if it still can be because the response has not been sent.