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));
}
var origin = context.Request.Headers[CorsConstants.Origin];
var requestHeaders = context.Request.Headers;
var origin = requestHeaders[CorsConstants.Origin];
var isOptionsRequest = string.Equals(context.Request.Method, CorsConstants.PreflightHttpMethod, StringComparison.OrdinalIgnoreCase);
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)
{
var headers = context.Request.Headers;
if (policy.AllowAnyOrigin)
{
result.AllowedOrigin = CorsConstants.AnyOrigin;
@ -117,7 +118,7 @@ namespace Microsoft.AspNetCore.Cors.Infrastructure
}
else
{
var origin = context.Request.Headers[CorsConstants.Origin];
var origin = headers[CorsConstants.Origin];
result.AllowedOrigin = origin;
result.VaryByOrigin = policy.Origins.Count > 1;
}
@ -129,12 +130,12 @@ namespace Microsoft.AspNetCore.Cors.Infrastructure
AddHeaderValues(result.AllowedExposedHeaders, policy.ExposedHeaders);
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;
AddHeaderValues(result.AllowedMethods, allowedMethods);
var allowedHeaders = policy.AllowAnyHeader ?
context.Request.Headers.GetCommaSeparatedValues(CorsConstants.AccessControlRequestHeaders) :
headers.GetCommaSeparatedValues(CorsConstants.AccessControlRequestHeaders) :
policy.Headers;
AddHeaderValues(result.AllowedHeaders, allowedHeaders);
}
@ -169,11 +170,12 @@ namespace Microsoft.AspNetCore.Cors.Infrastructure
return;
}
response.Headers[CorsConstants.AccessControlAllowOrigin] = result.AllowedOrigin;
var headers = response.Headers;
headers[CorsConstants.AccessControlAllowOrigin] = result.AllowedOrigin;
if (result.SupportsCredentials)
{
response.Headers[CorsConstants.AccessControlAllowCredentials] = "true";
headers[CorsConstants.AccessControlAllowCredentials] = "true";
}
if (result.IsPreflightRequest)
@ -184,17 +186,17 @@ namespace Microsoft.AspNetCore.Cors.Infrastructure
// `Access-Control-Allow-Methods`, `Access-Control-Allow-Headers`, `Access-Control-Max-Age`
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)
{
response.Headers.SetCommaSeparatedValues(CorsConstants.AccessControlAllowMethods, result.AllowedMethods.ToArray());
headers.SetCommaSeparatedValues(CorsConstants.AccessControlAllowMethods, result.AllowedMethods.ToArray());
}
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
@ -203,13 +205,13 @@ namespace Microsoft.AspNetCore.Cors.Infrastructure
// `Access-Control-Expose-Headers`
if (result.AllowedExposedHeaders.Count > 0)
{
response.Headers.SetCommaSeparatedValues(CorsConstants.AccessControlExposeHeaders, result.AllowedExposedHeaders.ToArray());
headers.SetCommaSeparatedValues(CorsConstants.AccessControlExposeHeaders, result.AllowedExposedHeaders.ToArray());
}
}
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)
{
var response = (HttpResponse)state;
response.Headers[HeaderNames.CacheControl] = "no-cache";
response.Headers[HeaderNames.Pragma] = "no-cache";
response.Headers[HeaderNames.Expires] = "-1";
response.Headers.Remove(HeaderNames.ETag);
var headers = ((HttpResponse)state).Headers;
headers[HeaderNames.CacheControl] = "no-cache";
headers[HeaderNames.Pragma] = "no-cache";
headers[HeaderNames.Expires] = "-1";
headers.Remove(HeaderNames.ETag);
return Task.CompletedTask;
}
}
}
}

View File

@ -150,17 +150,19 @@ namespace Microsoft.AspNetCore.HttpOverrides
bool checkFor = false, checkProto = false, checkHost = false;
int entryCount = 0;
var request = context.Request;
var requestHeaders = context.Request.Headers;
if ((_options.ForwardedHeaders & ForwardedHeaders.XForwardedFor) == ForwardedHeaders.XForwardedFor)
{
checkFor = true;
forwardedFor = context.Request.Headers.GetCommaSeparatedValues(_options.ForwardedForHeaderName);
forwardedFor = requestHeaders.GetCommaSeparatedValues(_options.ForwardedForHeaderName);
entryCount = Math.Max(forwardedFor.Length, entryCount);
}
if ((_options.ForwardedHeaders & ForwardedHeaders.XForwardedProto) == ForwardedHeaders.XForwardedProto)
{
checkProto = true;
forwardedProto = context.Request.Headers.GetCommaSeparatedValues(_options.ForwardedProtoHeaderName);
forwardedProto = requestHeaders.GetCommaSeparatedValues(_options.ForwardedProtoHeaderName);
if (_options.RequireHeaderSymmetry && checkFor && forwardedFor.Length != forwardedProto.Length)
{
_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)
{
checkHost = true;
forwardedHost = context.Request.Headers.GetCommaSeparatedValues(_options.ForwardedHostHeaderName);
forwardedHost = requestHeaders.GetCommaSeparatedValues(_options.ForwardedHostHeaderName);
if (_options.RequireHeaderSymmetry
&& ((checkFor && forwardedFor.Length != forwardedHost.Length)
|| (checkProto && forwardedProto.Length != forwardedHost.Length)))
@ -212,7 +214,6 @@ namespace Microsoft.AspNetCore.HttpOverrides
// Gather initial values
var connection = context.Connection;
var request = context.Request;
var currentValues = new SetOfForwarders()
{
RemoteIpAndPort = connection.RemoteIpAddress != null ? new IPEndPoint(connection.RemoteIpAddress, connection.RemotePort) : null,
@ -293,17 +294,17 @@ namespace Microsoft.AspNetCore.HttpOverrides
if (connection.RemoteIpAddress != null)
{
// 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)
{
// 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
{
// All values were consumed
request.Headers.Remove(_options.ForwardedForHeaderName);
requestHeaders.Remove(_options.ForwardedForHeaderName);
}
connection.RemoteIpAddress = currentValues.RemoteIpAndPort.Address;
connection.RemotePort = currentValues.RemoteIpAndPort.Port;
@ -312,16 +313,16 @@ namespace Microsoft.AspNetCore.HttpOverrides
if (checkProto && currentValues.Scheme != null)
{
// Save the original
request.Headers[_options.OriginalProtoHeaderName] = request.Scheme;
requestHeaders[_options.OriginalProtoHeaderName] = request.Scheme;
if (forwardedProto.Length > entriesConsumed)
{
// 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
{
// All values were consumed
request.Headers.Remove(_options.ForwardedProtoHeaderName);
requestHeaders.Remove(_options.ForwardedProtoHeaderName);
}
request.Scheme = currentValues.Scheme;
}
@ -329,16 +330,16 @@ namespace Microsoft.AspNetCore.HttpOverrides
if (checkHost && currentValues.Host != null)
{
// Save the original
request.Headers[_options.OriginalHostHeaderName] = request.Host.ToString();
requestHeaders[_options.OriginalHostHeaderName] = request.Host.ToString();
if (forwardedHost.Length > entriesConsumed)
{
// 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
{
// All values were consumed
request.Headers.Remove(_options.ForwardedHostHeaderName);
requestHeaders.Remove(_options.ForwardedHostHeaderName);
}
request.Host = HostString.FromUriComponent(currentValues.Host);
}

View File

@ -110,19 +110,21 @@ namespace Microsoft.AspNetCore.ResponseCaching.Internal
builder.Append(varyByRules.VaryByKeyPrefix);
// 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
builder.Append(KeyDelimiter)
.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 headerValues = context.HttpContext.Request.Headers[header];
var headerValues = requestHeaders[header];
builder.Append(KeyDelimiter)
.Append(header)
.Append("=");
.Append('=');
var headerValuesArray = headerValues.ToArray();
Array.Sort(headerValuesArray, StringComparer.Ordinal);
@ -152,7 +154,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Internal
{
builder.Append(KeyDelimiter)
.AppendUpperInvariant(queryArray[i].Key)
.Append("=");
.Append('=');
var queryValueArray = queryArray[i].Value.ToArray();
Array.Sort(queryValueArray, StringComparer.Ordinal);
@ -176,7 +178,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Internal
var queryKeyValues = context.HttpContext.Request.Query[queryKey];
builder.Append(KeyDelimiter)
.Append(queryKey)
.Append("=");
.Append('=');
var queryValueArray = queryKeyValues.ToArray();
Array.Sort(queryValueArray, StringComparer.Ordinal);

View File

@ -33,12 +33,12 @@ namespace Microsoft.AspNetCore.ResponseCaching.Internal
public virtual bool AllowCacheLookup(ResponseCachingContext context)
{
var request = context.HttpContext.Request;
var requestHeaders = context.HttpContext.Request.Headers;
// 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();
return false;
@ -47,7 +47,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Internal
else
{
// 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();
return false;

View File

@ -158,11 +158,13 @@ namespace Microsoft.AspNetCore.Session
{
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";
_context.Response.Headers[HeaderNames.Pragma] = "no-cache";
_context.Response.Headers[HeaderNames.Expires] = "-1";
var responseHeaders = response.Headers;
responseHeaders[HeaderNames.CacheControl] = "no-cache";
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.