Giter Site home page Giter Site logo

aspnet / responsecaching Goto Github PK

View Code? Open in Web Editor NEW
69.0 48.0 38.0 482 KB

[Archived] ASP.NET Core middleware for caching responses. Project moved to https://github.com/aspnet/AspNetCore

License: Apache License 2.0

Batchfile 0.18% PowerShell 2.38% Shell 3.32% C# 94.12%
aspnet-product

responsecaching's Introduction

ASP.NET Core Response Caching [Archived]

This GitHub project has been archived. Ongoing development on this project can be found in https://github.com/aspnet/AspNetCore.

This repo hosts the ASP.NET Core middleware for response caching.

This project is part of ASP.NET Core. You can find samples, documentation and getting started instructions for ASP.NET Core at the AspNetCore repo.

responsecaching's People

Contributors

ajaybhargavb avatar aspnetci avatar benaadams avatar brennanconroy avatar davidfowl avatar dougbu avatar eilon avatar javiercn avatar jkotalik avatar juntaoluo avatar kichalla avatar mikeharder avatar muratg avatar natemcmaster avatar ntaylormullen avatar pakrym avatar pranavkm avatar ryanbrandenburg avatar tratcher avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

responsecaching's Issues

ResponseCaching Checklist

Infrastructure work

  • Reserve package name #12
  • Builds, CI, packages.csv, etc. #12
  • Update to ASP.NET Core 1.0.0 #12

Middleware

  • Default cache behaviours
    • based on HTTP Headers (RFC 7234) #15
    • Request/Response are cacheable, cacheability based on state: headers, expiry, ... #15
    • Heuristics based freshness (RFC) - #15
    • ๐Ÿ“‚ strip/send warnings (RFC) #41
    • โŒ Corrected age value (RFC) probably not an issue since our closeness to the endpoint means the apparent age is accurate enough
    • ๐Ÿ“‚ POST responses invalidates cache (RFC) - #38
    • ๐Ÿ“‚ no-cache fields (RFC) - #40
    • โŒ no-transform (RFC) No work needs to be done here since we don't transform the payload.
  • Options
    • max size to buffer #25
    • path case sensitivity #26
  • Conditional requests (respond to validation requests)
    • IfNotModifiedSince, IfNoneMatch #22
  • Revalidation with endpoint
    • ๐Ÿ“‚eviction, freshness update (RFC, ASPNET, Orchard) - #39
  • Cache invalidation
    • ๐Ÿ“‚ cache dependency, invalidation by endpoint (RFC, Orchard) - #38
  • ๐Ÿ“‚Partial responses (RFC, ASPNET) - #36
    • Consolidating partial responses
    • Serve portions of full cached responses per range header
  • ๐Ÿ“‚Gated incoming requests (Orchard) #37

Storage

  • IDistributedCache, IMemroyCache
    • Storage provider interface #14
    • Serialization, binary serialization #14
  • ๐Ÿ“‚ FileSystem based storage (ASPNET) - #8
  • Key generation
    • Path Method, VaryBy #12
    • Custom key producer via delegate (ASPNET) #16
  • Vary By
    • Headers #14
    • Location (Orchard) - user extensible
    • Auth (Orchard) - user extensible
    • Hash of POST data (ASPNET) - user extensible
    • QueryString (ASPNET, Orchard) #21
    • Encoding (ASPNET) - user extensible
    • Delegate for more custom vary by (ASPNET) #16
  • Diagnostics
    • Cache hit ratio, maybe this should be in Caching?

Endpoint

  • Communication with endpoint
    • cache-control header #15
  • Cache invalidation - #38

Performance

  • ๐Ÿ“‚ Chunking of cached responses in storage to prevent allocations on LOH #7

Users are able to make site throw an exception when using ResponseCaching middleware.

using the ResponseCachingMiddleware with VaryByQueryKeys

[ResponseCache(CacheProfileName = "DefaultCache", VaryByQueryKeys = new string[] { "id" })]

open chrome inspector
tick disable cache
go to page that uses a ResponseCache with VaryByQueryKeys

image

it throws:
InvalidOperationException: 'VaryByQueryKeys' requires the response cache middleware.

closing the inspector or untick disable cache work fine.

Using fiddler, adding Pragma: no-cache header is enough to make the site throw an exception.

Port fix for Update how certain cache directives are handled to 1.1.x

We'll need to port back part of the fixes in #88 back to 1.1.x.

At the minimum we'll need the fixes to:

  • Always add the IResponseCachingFeature before calling the next middleware #81
  • Use If-Modified-Since instead of the wrong If-Unmodified-Since header for conditional requests

Also potentially consider

  • handling of proxy-revalidate cache directive and handling of max-stale without specified limit

Update how certain cache directives are handled

  • no-store on request:
    This should by-pass ShimResponseStream since we can't store any part of the response so there's no point in capturing the response
  • no-cache on request:
    We can "validate" by asking the server to regenerate the response. As such we shouldn't skip the capturing of the response and update the cache entry if possible.
  • max-stale
    The case where no limit is specified, which means any stale response can be served, is not handled.
  • proxy-revalidate
    Same effect as must-revalidate

Also the header

  • If-Unmodified-Since is being used incorrectly. The correct header to check for in when determining if content is modified is If-Modified-Since

Cache related warning headers

Need to revisit this to see what warnings we may want to send along with cached responses. For example, if no original expiry information is explicitly stated, we currently use a default expiration of 10s. In this case, we should send the warning 113 - "Heuristic expiration"

Extensibility for user operations of cached responses

We may want to expose an extensibility point for users to modify the cached response. There are two instances where this can occur and we can add the extensibility to one or both. First is when the middleware first receives the response and is about to store it in cache. Second is when the middleware has retrieved the item from cache and is about to use it to serve a request. A scenario that may require this is for stripping out a few headers in an otherwise cacheable response.

Redis response cache store

Currently Redis will be exposed through the DistributedResponseCacheStore but the API of IDistributed cache could be a limiting factor. We may bypass that abstraction and design a RedisResponseCacheStore to take advantage of more features of redis.

Logging

Add logging to indicate what the response cache is doing.

Review logged messages

Review the messages that are logged added in #65. Also make sure the messages are at the correct level.

IHttpSendFileFeature

Need to consider allowing for caching files sent using the IHttpSendFileFeature. Currently these responses are considered not-cacheable by default. This could be a configurable option on the middleware.

Check response headers on write to preserve middleware order consistency

Ran into this issue in aspnet/BasicMiddleware#199. Currently checking the response headers is triggered either by the OnStarting callback which is called when the first write to the body occurs, or when the next middleware returns. This however will not work if the previous middleware buffers the response so no write occurs but modifies the headers on write.

The proposal is to check the response headers relevant to response caching on write as well as the current triggers. This will guarantee that the behaviour will match the middleware order.

Cache invalidation

Currently we only set the absolute timeouts for cache entries. There is no mechanism to explicitly invalidate a cache entry before expiry. Also, how would applications/users interact with this feature?

Note that invalidation is required by the RFC for unsafe methods, e.g. a successful PUT should invalidate any previous cached resources at the same URI.

KeyBuilder and hashed keys

Currently keys are strings. We may want to consider creating an abstraction of KeyBuilder that only creates a string for IDistributedCache based stores and use an object as the key for IMemoryCache based stores. We may also want to consider adding support for hashing the keys to a constant length

No-cache fields

Some directive such as no-cache may contain fields which can be stripped from the response after which the response can be deemed cacheable.

Revalidation

No current mechanism exist for revalidating a stale entry in the response cache. We may want to support the cache-control extensions listed in https://tools.ietf.org/html/rfc5861, in particular the stale-while-revalidate directive.

Request headers can't opt out of looking in the cache

https://github.com/aspnet/ResponseCaching/blob/chrross/initial/src/Microsoft.AspNet.ResponseCaching/CachingContext.cs#L46

No-cache in the request header says a cached response has to be revalidated.
No-store says you can't store the response, but if someone else requested it without no-store and the response is fresh then you can serve it.

Clients can avoid getting cached responses by using max-age and min-fresh request directives, but that requires pulling the response from the cache anyway to check the age.

Gated incoming requests

In Orchard CMS, there was a feature where multiple incoming requests will block until the response for the first one is generated and is used to satisfy all waiting requests. Will need to investigate how this can be supported, either within the middleware or by the user given the available extensibility points.

cc @sebastienros

Include Host, Port and Scheme in Cache Key

Multi tenant applications may return different content for the same path+query but with a different host header value

Maybe add the Host value to the cache key, or provide a way to customize it using code

Implement response caching middleware

MVC and other application level components will set standard HTTP cache headers (Cache-Control, Vary, etc.) for clients and proxies.

Middleware will read the response headers and cache in a local memory cache when appropriate. Then it can short circuit incoming requests and serve them from the cache.

We may also need a feature interface for interacting with server level caches (e.g. to limit double caching).

Add options for cookie handling

It would be nice if there are options for cookies handling. Two things I can propose:

  1. Option to ignore all cookies (they are often used for client-side stuff only in public sites)
  2. Option to give names of cookies to ignore

Second option is specially important as currently it is not possible to use Application Insights with response caching as AI uses cookies when browser-side diagnostics are enabled. I think in this case request cookies must be just copied to response to not delete them.

Middleware throws Argument Exception if cached headers conflict with pre-existing response headers

I just encountered an error while using ResponseCache in conjunction with the Stackify APM extension on Azure. It seems something is trying to insert a duplicate X-StackifyID header. I'm not sure if it is the extension that's misbehaving, or ResponseCache, or just a combination that hadn't been thought of.

My use of the ResponseCache is pretty trivial: [ResponseCache(Duration = 30)]

The error does not occur every time, but it's pretty easy to reproduce.

exception": "System.ArgumentException: An item with the same key has already been added. Key: X-StackifyID\r\n at System.ThrowHelper.ThrowAddingDuplicateWithKeyArgumentException(Object key)\r\n at System.Collections.Generic.Dictionary2.Insert(TKey key, TValue value, Boolean add)\r\n at System.Collections.Generic.Dictionary2.Add(TKey key, TValue value)\r\n at Microsoft.AspNetCore.Server.Kestrel.Internal.Http.FrameResponseHeaders.AddValueFast(String key, StringValues value)\r\n at Microsoft.AspNetCore.Server.Kestrel.Internal.Http.FrameHeaders.System.Collections.Generic.IDictionary<System.String,Microsoft.Extensions.Primitives.StringValues>.Add(String key, StringValues value)\r\n at Microsoft.AspNetCore.Server.Kestrel.Internal.Http.FrameHeaders.System.Collections.Generic.ICollection<System.Collections.Generic.KeyValuePair<System.String,Microsoft.Extensions.Primitives.StringValues>>.Add(KeyValuePair2 item)\r\n at Microsoft.AspNetCore.ResponseCaching.ResponseCachingMiddleware.d__10.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter1.GetResult()\r\n at Microsoft.AspNetCore.ResponseCaching.ResponseCachingMiddleware.d__11.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---

feature request - automatic ETag generation

I'd like a facility where the ResponseCaching middleware can be configured to calculate the ETag automatically based on e.g. request path+query and response body and accounting for vary headers. You'd also want the ability to override that functionality, possibly by passing in an Options object to e.g. specify what vary headers you care about/ignore.

Current community solutions to work out the ETag from the response body use a buffer (because you need to know if e.g. the view file or javascript file guid has changed), which is is a bit of a hack:

http://stackoverflow.com/questions/35458737/implement-http-cache-etag-in-asp-net-core-web-api/43017504

In the real world, the MS responsecaching middleware seems a bit pointless without ETag generation, as it forces you to roll your own middleware to provide this functionality, which means you then don't need the MS version.

Cache chunked rather than whole byte[]

Cached data should be stored in < 85k chunks rather than as whole byte[] so they live in GC generations rather than LoH and can be cleaned without requiring a full Gen2

Create a Middleware to propose an implementation of 'IHttpSendFileFeature'

Better repository for issue aspnet/KestrelHttpServer#981...
I have made some performance tests to see the difference between using a cache and using directly a physical file stream.

  • When using a cache, I use a dictionary to store the last modification date (in case of the file is modified) and the file content.
  • When using directly the file, I have more or less copy/paste the StaticFiles.StaticFileContext code (including StreamCopyOperation.CopyToAsync()).
    I created a Console application, and I made tries with different file sizes. For each file size, I loop 1000 times on the same file to copy it to the Null stream (to avoid uninteresting overhead). So it is the most favorable case for the physical file stream, because Windows and the hard disc can do the best use of their caches.

Here are the results on my computer:

Test with cache
10K --> 52 ms
30K --> 38 ms
100K --> 36 ms
500K --> 35 ms
1M --> 36 ms
5M --> 42 ms
10M --> 51 ms

Test direct stream
10K --> 148 ms
30K --> 132 ms
100K --> 179 ms
500K --> 425 ms
1M --> 728 ms
5M --> 4138 ms
10M --> 8525 ms

The performance difference is significant!

So I suggest to add a middleware with the following options:

public class SendPhysicalFileCacheOptions
{
   public int CacheMaximumSize { get; set; }   // The maximum dedicated size in MB (i.e. the sum of all file contents)
   public long FileMaximumSize { get; set; }   // The maximum size of a file to be saved in cache in Bytes (so lower than CacheMaximumSize)
   public IEnumerable<Func<string, long, bool>> Filters { get; set; } // Optional filters F(filePath, fileLength)->bool that allows user the reject files from cache
}

Cache-Control: no-cache breaks the middleware

TL;DR: this breaks with the Cache-Control: no-cache header since the IResponseCachingFeature feature is not set up and we hit this exception.


Hi,

I'm just starting with your middleware, and the basic functionality is great. I just specify a [ResponseCache] and it gets cached automatically, which is awesome :).

But I'm getting an error 500 each time I do "Ctrl+F5" or I disable caching in the Chrome dev tools. The error is the one in the title:

An unhandled exception occurred while processing the request. InvalidOperationException: 'VaryByQueryKeys' requires the response cache middleware.

Microsoft.AspNetCore.Mvc.Internal.ResponseCacheFilter.OnActionExecuting(ActionExecutingContext context)

The error is the same as if I had not called app.UseResponseCaching(); or called it in the wrong order. The exact line is the following, which shows that it's checking for a Feature of type IResponseCachingFeature: https://github.com/aspnet/Mvc/blob/d8c6c4ab34e1368c1b071a01fcdcb9e8cc12e110/src/Microsoft.AspNetCore.Mvc.Core/Internal/ResponseCacheFilter.cs#L132.

I investigated the source code and came to the conclusion that the error is produced because:

  1. Browsers send Cache-Control: no-cache header
  2. The request is marked as not cacheable here
  3. Since it's not cacheable we skip the call to ShimResponseStream
  4. And we don't set up the Feature for the next middlewares.
  5. So we end up with the mentioned exception in this line

If you could give me any workaround until a fix is published I'd really appreciate it!

Thanks,
Martรญn.

Antiforgery tokens

Anti-forgery tokens can't be cached as they are user specific values, even for anonymous users. Hence if a response is rendered with another's token the form will fail.

Options:

  1. This can be done with the anti-forgery token generator create a no-cache header. It's already setting the cookie.
    The issue with this is that this can lead to lots of cache misses. For instance if a layout contains a login form in the header (quite common) or a blog engine rendering a comments form for the posts.
  2. A solution to still cache these would be to substitute the token value with a beacon when storing the cache entry, then substituting it when the page is rendered. Like using a standard ESI one that would also work for edge servers. https://www.varnish-cache.org/docs/3.0/tutorial/esi.html

If done correctly it could be generalized to support other user specific values to extend support for authenticated cached pages.

Allow us to override the method used to determine if response should be served from cache

Hello,

please allow us to override the method used to determine if response should be served from Cache.

If e.g. a browser requests the page with the header "Cache-Control: no-cache" the page won't be served from cache. But we want to override this behaviour, to always let aspnet serve the request from the cache.

Otherwise malicious users could cause uneccessary load on the Server.

Thank you

Investigate request `no-cache` behaviour

In the current implementation, for requests with a no-cache directive, cache lookup is skipped but response capture and cache store still occurs. The RFC only specifies that the cache cannot use a stored response to satisfy the request without validation but explicitly says nothing regarding the response.

This means that for requests with no-cache, writes to the cache will still occur and will overwrite any existing cached entries for the same resource. This can lead to a large amount of potentially wasted writes and we should determine if this behaviour is common in other implementation of HTTP caching.

Note that this can be resolved with user provided implementations of the IResponseCachingPolicyProvider but that is not currently exposed publicly. Regardless, we should investigate whether the current implementation should be the default behaviour.

Make request cacheable when it has "no-cache" header

Why do we trust the client?

For example, "no-cache" header can be used for the ddos attacks. Besides OutputCacheAttribute (ASP.NET MVC 5) doesn't pay attention to this header.

Can we change the behavior of the attribute or add it to the settings?

Partial responses and range requests

Currently we don't cache partial responses with status code 206. These responses are cacheable but right now the user will need to override our cache policy providers to cache them. Also there is no current mechanism to coalesce overlapping partial responses and no way to serve a portion of the response given range requests.

[Question] ResponseCaching and static files.

I've configured MVC via options with some cache profiles which (with my understanding) will be picked up by this middlware and appropriately cached in memory:

options.CacheProfiles.Add(Constants.Caching.DefaultCacheProfile, new CacheProfile
{
    Duration = 60 * 60 * 24
});

All good so far. I however also configure certain static file resources for caching:

//Caching static resources
var cachePathExtensions = new[] { ".jpg", ".png", ".woff", ".woff2", ".js", ".css" };
var cacheMaxAge = new System.TimeSpan(7, 0, 0, 0);
app.UseStaticFiles(new StaticFileOptions
{
    OnPrepareResponse = r => {
        var pathExtension = r.File.PhysicalPath.Substring(r.File.PhysicalPath.LastIndexOf('.')).ToLower();
        if (cachePathExtensions.Contains(pathExtension))
        {
            r.Context.Response.Headers.Add("Cache-Control", "max-age=" + cacheMaxAge.TotalSeconds.ToString("0"));
        }
    }
});

My understanding is that these too would be cached by this middleware? The big issue here, is imagery - I've GB's of images which I want to set cache-control headers for so clients will cache them appropriately. If this middleware is caching them in memory, then I'm going to have a reaaaalllly bad time.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.