CORS and the HTML5 Application cache manifest don't work together (neither do CORS and Apache)

Posted by Matt Bryson on 28-Feb-2014 19:10:24
Find me on:

If you are looking to make cross domain requests with ajax for items in a cache manifest, don't. It wont work.

We recently embarked on building a web application that runs completely offline on mobile devices.

It was fully content managed from our CMS, which published assets and a cache.manifest file to a couple of amazon S3 buckets.

Our set up was this:

  • The CMS and API run off an EC2 server on a domain A
  • The assets are published to a S3 bucket on domain B
  • The web app is hosted on a S3 static website bucket on domain C

You can't cross domain the cache manifest itself, but you can cross domain the items in it, as long as its not HTTPS.

So, we need the web app on domain C to load the API on domain A. As well as allow the web app on domain C to load the assets on domain B all via Ajax. This is not allowed due to security restrictions.

CORS to the rescue. or so we thought....


Apache and CORS

Apache does not like CORS.

At least not for cached responses. If you request a resource that returns a 304 not modified, Apache will remove any CORS headers!!

The preflight request is made successfully, and then the actual request is made, but if this hits a cached resource, apache will remove the CORS headers from the response, and then the ajax client rejects the request as it no longer supports CORS.

So any hits to our API that would return a cached response would fail. The only 2 solutions were to disable caching (not desirable) or export the output of this API endpoint when changes are made to a static file on S3.

A bug ticket in 2011 was opened, obviously not rush to fix it.

S3 and CORS

S3 does like CORS, and follows the CORS spec.

Enabling CORS in S3 is in fact quite simple, you login in to your S3 control panel, select the bucket, go to security and hit the CORS button.

Then, any request that passes the Origin header, S3 will return your CORS settings for that request. All good.

App Cache and CORS

Webkit app-cache doesn't like CORS either.

The CORS spec states that the request MUST pass the origin header for CORS to work. When the browser finds an entry in the cache.manifest, it requests this from the server and caches the response headers. What it doesn't do is pass the Origin header. This means any server respecting the CORS spec will NOT return any CORS headers.

The cache manifest request does not need to make a CORS request, as it is not an ajax call so it will succeed without one. The problem arrises when you load a file from your cache manifest with ajax. The request never makes it to the server, it comes from the app cache, and the cached response does not contain any CORS headers and thus the ajax client rejects the request.

If you have full control over the headers on your server, you can force the CORS headers regardless of the Origin header, but this goes against the CORS spec.

So, in summary, don't try to do any cross domain app cache, and don't try to use apache to return cached cross domain requests - you will be banging you head against a wall trying to work out why it doesn't work.


Topics: appcache, CORS, Apache