Skip to content
This repository was archived by the owner on Nov 22, 2018. It is now read-only.

Optimizations #87

Merged
merged 1 commit into from
Dec 14, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public class CachedResponse : IResponseCacheEntry

public int StatusCode { get; set; }

public IHeaderDictionary Headers { get; set; } = new HeaderDictionary();
public IHeaderDictionary Headers { get; set; }

public Stream Body { get; set; }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System;
using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Net.Http.Headers;

namespace Microsoft.AspNetCore.ResponseCaching.Internal
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,13 +107,18 @@ public string CreateStorageVaryByKey(ResponseCachingContext context)
builder.Append(KeyDelimiter)
.Append('H');

foreach (var header in varyByRules.Headers)
for (var i = 0; i < varyByRules.Headers.Count; i++)
{
var header = varyByRules.Headers[i];
var headerValues = context.HttpContext.Request.Headers[header];
builder.Append(KeyDelimiter)
.Append(header)
.Append("=")
// TODO: Perf - iterate the string values instead?
.Append(context.HttpContext.Request.Headers[header]);
.Append("=");

for (var j = 0; j < headerValues.Count; j++)
{
builder.Append(headerValues[j]);
}
}
}

Expand All @@ -131,19 +136,28 @@ public string CreateStorageVaryByKey(ResponseCachingContext context)
{
builder.Append(KeyDelimiter)
.AppendUpperInvariant(query.Key)
.Append("=")
.Append(query.Value);
.Append("=");

for (var i = 0; i < query.Value.Count; i++)
{
builder.Append(query.Value[i]);
}
}
}
else
{
foreach (var queryKey in varyByRules.QueryKeys)
for (var i = 0; i < varyByRules.QueryKeys.Count; i++)
{
var queryKey = varyByRules.QueryKeys[i];
var queryKeyValues = context.HttpContext.Request.Query[queryKey];
builder.Append(KeyDelimiter)
.Append(queryKey)
.Append("=")
// TODO: Perf - iterate the string values instead?
.Append(context.HttpContext.Request.Query[queryKey]);
.Append("=");

for (var j = 0; j < queryKeyValues.Count; j++)
{
builder.Append(queryKeyValues[j]);
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
Expand Down Expand Up @@ -142,18 +141,15 @@ internal async Task<bool> TryServeCachedResponseAsync(ResponseCachingContext con
response.Headers.Add(header);
}

response.Headers[HeaderNames.Age] = context.CachedEntryAge.Value.TotalSeconds.ToString("F0", CultureInfo.InvariantCulture);
// Note: int64 division truncates result and errors may be up to 1 second. This reduction in
// accuracy of age calculation is considered appropriate since it is small compared to clock
// skews and the "Age" header is an estimate of the real age of cached content.
response.Headers[HeaderNames.Age] = HeaderUtilities.FormatInt64(context.CachedEntryAge.Value.Ticks / TimeSpan.TicksPerSecond);

// Copy the cached response body
var body = context.CachedResponse.Body;
if (body.Length > 0)
{
// Add a content-length if required
if (!response.ContentLength.HasValue && StringValues.IsNullOrEmpty(response.Headers[HeaderNames.TransferEncoding]))
{
response.ContentLength = body.Length;
}

try
{
await body.CopyToAsync(response.Body, StreamUtilities.BodySegmentSize, context.HttpContext.RequestAborted);
Expand Down Expand Up @@ -263,7 +259,8 @@ internal async Task FinalizeCacheHeadersAsync(ResponseCachingContext context)
context.CachedResponse = new CachedResponse
{
Created = context.ResponseDate.Value,
StatusCode = context.HttpContext.Response.StatusCode
StatusCode = context.HttpContext.Response.StatusCode,
Headers = new HeaderDictionary()
};

foreach (var header in context.HttpContext.Response.Headers)
Expand All @@ -288,6 +285,13 @@ internal async Task FinalizeCacheBodyAsync(ResponseCachingContext context)
var bufferStream = context.ResponseCachingStream.GetBufferStream();
if (!contentLength.HasValue || contentLength == bufferStream.Length)
{
var response = context.HttpContext.Response;
// Add a content-length if required
if (!response.ContentLength.HasValue && StringValues.IsNullOrEmpty(response.Headers[HeaderNames.TransferEncoding]))
{
context.CachedResponse.Headers[HeaderNames.ContentLength] = HeaderUtilities.FormatInt64(bufferStream.Length);
}

context.CachedResponse.Body = bufferStream;
_logger.LogResponseCached();
await _cache.SetAsync(context.StorageVaryKey ?? context.BaseKey, context.CachedResponse, context.CachedResponseValidFor);
Expand Down Expand Up @@ -371,8 +375,9 @@ internal static bool ContentIsNotModified(ResponseCachingContext context)
&& EntityTagHeaderValue.TryParse(cachedResponseHeaders[HeaderNames.ETag], out eTag)
&& EntityTagHeaderValue.TryParseList(ifNoneMatchHeader, out ifNoneMatchEtags))
{
foreach (var requestETag in ifNoneMatchEtags)
for (var i = 0; i < ifNoneMatchEtags.Count; i++)
{
var requestETag = ifNoneMatchEtags[i];
if (eTag.Compare(requestETag, useStrongComparison: false))
{
context.Logger.LogNotModifiedIfNoneMatchMatched(requestETag);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ await cache.SetAsync(
"BaseKey",
new CachedResponse()
{
Headers = new HeaderDictionary(),
Body = new SegmentReadStream(new List<byte[]>(0), 0)
},
TimeSpan.Zero);
Expand Down Expand Up @@ -108,6 +109,7 @@ await cache.SetAsync(
"BaseKeyVaryKey2",
new CachedResponse()
{
Headers = new HeaderDictionary(),
Body = new SegmentReadStream(new List<byte[]>(0), 0)
},
TimeSpan.Zero);
Expand Down Expand Up @@ -666,7 +668,10 @@ public async Task FinalizeCacheBody_Cache_IfContentLengthAbsent()
await context.HttpContext.Response.WriteAsync(new string('0', 10));

context.ShouldCacheResponse = true;
context.CachedResponse = new CachedResponse();
context.CachedResponse = new CachedResponse()
{
Headers = new HeaderDictionary()
};
context.BaseKey = "BaseKey";
context.CachedResponseValidFor = TimeSpan.FromSeconds(10);

Expand Down