6

For the purposes of CDN invalidation I need to add a prefix to the path element of a site's URL. This is changed whenever a new version of the asset is released.

The URL is then rewritten using mod_rewrite from: http://example.com/cdn/20111030/images/image.jpg to http://example.com/images/image.jpg which is where the asset actually resides.

I would like to add long expiry headers (at least 3 months) to the response (for the first URL which doesn't actually exist in the filesystem). Does anyone know how to do this?

Benedict Dodd
  • 255
  • 3
  • 9

3 Answers3

5

It appears that if you add the RewriteEngine/Rule in the Apache configuration for your own solution, the Location is picked up correctly and serves the Expires/Cache-Control on /cdn calls and doesn't serve them for non-cdn calls, with a minor changee:

    # in apache config
    RewriteEngine On
    RewriteRule ^/cdn/[^/]*/(.*) /$1 [L]

    <Location "/cdn">
      Header unset ETag
      FileETag None
      ExpiresActive on
      ExpiresDefault "access plus 1 year"
    </Location>

I can't see a reason this should be a problem in the Apache config.

Andy
  • 970
  • 8
  • 12
  • The problem with this is that is not useable in .htaccess, which is where the rest of the mod_rewrite rules are. And if you leave the RewriteRule in .htaccess, by the time the request makes it to the in the Vhost, for example, the /cdn prefix has already been removed. – Benedict Dodd Nov 05 '11 at 16:36
  • Why can't both be in the apache configuration? That solves the issue. – Andy Nov 05 '11 at 19:22
  • You can have RewriteRules in both the apache configuration and .htaccess at the same time, and they wont conflict unless you tell them to. – Andy Nov 05 '11 at 19:24
  • Using something almost identical on our project now. Appears to work correctly. – Andy Nov 08 '11 at 13:41
4

From http://drupal.org/node/974350#comment-5305368
These rules are for 480 weeks but you can adjust the time accordingly.

<IfModule mod_rewrite.c>
  RewriteEngine on
  <IfModule mod_headers.c>
    # Transform /cdn/***/ to /
    RewriteCond %{REQUEST_URI} ^/cdn/([0-9a-zA-Z])*/(.+)$
    RewriteRule .* /%2 [L,E=CDN:1]
    # Apache will change CDN to REDIRECT_CDN.

    # Set a far future Cache-Control header (480 weeks), which prevents
    # intermediate caches from transforming the data and allows any
    # intermediate cache to cache it, since it's marked as a public resource.
    Header set Cache-Control "max-age=290304000, no-transform, public" env=REDIRECT_CDN

    # Set a far future Expires header. The maximum UNIX timestamp is somewhere
    # in 2038. Set it to a date in 2037, just to be safe.
    Header set Expires "Tue, 20 Jan 2037 04:20:42 GMT" env=REDIRECT_CDN

    # Pretend the file was last modified a long time ago in the past, this will
    # prevent browsers that don't support Cache-Control nor Expires headers to
    # still request a new version too soon (these browsers calculate a
    # heuristic to determine when to request a new version, based on the last
    # time the resource has been modified).
    # Also see http://code.google.com/speed/page-speed/docs/caching.html.
    Header set Last-Modified "Wed, 20 Jan 1988 04:20:42 GMT" env=REDIRECT_CDN

    # Do not use etags for cache validation.
    Header unset ETag env=REDIRECT_CDN
  </IfModule>
</IfModule>

Also see the AdvAgg rules as these handle servers that do not have mod_headers or mod_expires installed. It uses a FilesMatch directive; advagg files have a fairly unique filename, thus I can do this. The AdvAgg fallbacks wont work in this case because mod_expires can't use environmental variables; neither can FileETag. From what I can see, mod_headers is the desired way to set far future times in apache.

mikeytown2
  • 1,744
  • 24
  • 37
  • Thanks, this works great. On Apache 2.2 CDN is not getting changed to REDIRECT_CDN for me so I had to change REDIRECT_CDN to CDN. – Sarel Botha Jun 14 '13 at 16:19
0

A solution could be to apply the Expires to all assets, the use mod_headers to remove the headers from the non-cdn version, e.g.:

 RewriteEngine on
 RewriteRule ^cdn/([0-9a-z])*/(.*) /$2 [L,E=cdn:1]

 ExpiresActive on
 ExpiresDefault "access plus 1 year"
 Header unset Expires env=!cdn
 Header unset Cache-Control env=!cdn

It's a bit overkill for the root of the website, but if only applied to the assets, would be less of an issue.

Andy
  • 970
  • 8
  • 12