Merging s-maxage and max-age - .htaccess

I currently have this in my htaccess.
<IfModule mod_headers.c>
Header set Cache-Control 's-maxage=604800'
</IfModule>
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType text/html A86400
</IfModule>
HTTP headers will show as...
Cache-Control: s-maxage=604800
Cache-Control: max-age=86400
Expires: Wed, 18 Dec 2013 03:51:18 GMT
How do I merge s-maxage and max-age so that it will show as:
Cache-Control: max-age=86400, s-maxage=604800
I've tried using Header set, append, merge and add but nothing works. It seems that ExpiresActive On will automatically include Cache-Control: max-age to the headers.

According to the manual, ordering is important. Try re-ordering the two directives and using merge to prevent any duplicates:
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType text/html A86400
</IfModule>
<IfModule mod_headers.c>
Header merge Cache-Control 's-maxage=604800'
</IfModule>

If you use Header edit you can add the s-maxage header depending on the max-age header:
ExpiresByType text/html A86400
ExpiresByType text/xml A86401
Header edit Cache-Control ^(max-age=86400)$ "$1; s-maxage=604800"
Result: s-maxage is only added for text/html

The simple answer is that there may not be an easy way to join your two headers, but it doesn't actually matter. Semantically there is no difference between this form:
Cache-Control: s-maxage=604800
Cache-Control: max-age=86400
and this form:
Cache-Control: s-maxage=604800, max-age=86400
RFC 7234 § 5.2 defines the Cache-Control header field value as a list of directives defined in a specific form:
Cache-Control = 1#cache-directive
cache-directive = token [ "=" ( token / quoted-string ) ]
That form is subject to this HTTP rule from RFC 2616 § 4.2:
Multiple message-header fields with the same field-name MAY be present in a message if and only if the entire field-value for that header field is defined as a comma-separated list [i.e., #(values)]. It MUST be possible to combine the multiple header fields into one "field-name: field-value" pair, without changing the semantics of the message, by appending each subsequent field-value to the first, each separated by a comma. The order in which header fields with the same field-name are received is therefore significant to the interpretation of the combined field value, and thus a proxy MUST NOT change the order of these field values when a message is forwarded.
(Note that the #(values) grammar is defined in § 2.1)
Therefore, if a client is treating those two varieties differently, it is in violation of HTTP/1.1.
In fact, there is a chance that what you are seeing as two headers is actually being sent to the client as a single conjoined header line, but your viewer or output is keeping the directives split into two for display.

Related

PageSpeed insight results are not being updated even after modifying the files

I have the following code in my .htaccess file:
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType image/jpg "access plus 1 year"
ExpiresByType image/jpeg "access plus 1 year"
</IfModule>
This means that jpg and jpeg images should have a cache expiration date of 1 year. The response headers in Chrome's DevTools Console reflect that.
content-type:image/jpeg
date:Mon, 07 Nov 2016 04:05:46 GMT
expires:Tue, 07 Nov 2017 04:05:46 GMT
last-modified:Sun, 06 Nov 2016 18:40:41 GMT
However, on PageSpeed insights, the recommendations show that the cache is only valid for 5 hours and I should increase that time. Why is that?
You should use the newer Cache-Control header:
Cache-Control: max-age=<some-time-in-seconds>, public
The old HTTP/1 Expires header is imprecise and causes problems when intermediate caches are involved.
Google PageSpeed probably assumes that it will not be respected by browsers. In that case the browser reverts to so called heuristic caching where the expiration is typically calculated as a fraction (e.g. 20%) of the difference between the Last-Modified date and now - which would yield a value similar to the one you saw.

Which Cache-control value will browser pick up

In our Web app response headers i am seeing Cache-control values like this
Cache-control : private
xxxx
Cache-control : no-cache, no-store
I am not clear on which value the browser will consider. I think browser will take the first Cache-control value or will it consolidate all Cache-control values?
Even if it consolidate all Cache-control values then which one it will consider?
Can anyone help in making this point clear

How can i get started using Etag URL fingerprinting for my Opencart website?

Im pretty new to scripting and coding. I have now picked an interest in speeding up my website. To do this i would like to begin leveraging browser caching.
I've read up on a couple of things but i'm now struggeling to make the right decision.
As far as i understand there are three options:
-expires
-max age
-Etag (while using max age)
The first two are not suitable for an e-commerce website (opencart btw) in my opinion. But are far easier to implement than the Etag as i understand.
I got as far as getting the expire and max age working in my testing eviroment but then i get problems with outdated client side rendering of my webpage.
So in conclusion i wanna go for the Etag but i have no clue where to start! Is there anyone (maybe with opencart experience aswell?) who can help me get on the way?
Thanks in advance!
Regards,
George
ETags are not that complicated to implement. Here's a snippet of code for your .htaccess file that will enable ETags for your images and other files that don't change that often:
# ETags Settings (for Cache purposes)
<ifModule mod_headers.c>
<FilesMatch \.(?i:jpeg|jpg|gif|png|css|js|xml)$>
FileETag MTime Size
</FilesMatch>
<FilesMatch \.(?i:php)$>
Header unset ETag
Header set Cache-Control "max-age=0, private, no-store, no-cache, must-revalidate"
Header set Pragma "no-cache"
FileETag None
</FilesMatch>
</ifModule>
# Expires Settings
<IfModule mod_expires.c>
ExpiresActive On
ExpiresDefault "access plus 1 month"
# Images
ExpiresByType image/gif "access plus 1 month"
ExpiresByType image/png "access plus 1 month"
ExpiresByType image/jpg "access plus 1 month"
ExpiresByType image/jpeg "access plus 1 month"
</IfModule>
Just a little background (though I'm sure you already know) and explanation:
ETags are more reliable than expires due to the fact that browsers that honor the expire directive will not change the image/file for the lifetime it is given, regardless if there are any changes. However ETags can be configured to indicate a browser when to change the image.
In the code provided above FileETag MTime Size will have browser updating the images, css, js and xml files (the ?i: is to do a case-insensitive match) if there are any changes in size or modification time. And the best part: it supersedes expires directives!
Also, the code above will disable ETags for php files due to the dynamic nature of the content.
I included the expires directives for images because, at the time of me writing this, many speed checkers and validators will rank you a little bit down for not having them, even if ETags are set.

Why `mod_headers` cannot match based on the content-type?

I can't get my mind wrapped around the comments and way of coding, to set a header only for .html in for example the .htaccess file in html5 boilerplate.
The clue for a big codeblock lays in the fact that 'mod_headers can't match on the content type' (as # commented). So I wander 1: why is there a 'Header unset' in a <FilesMatch>, that just has been announced to be impossible?
<IfModule mod_headers.c>
Header set Content-Security-Policy "script-src 'self'; object-src 'self'"
# `mod_headers` cannot match based on the content-type, however,
# the `Content-Security-Policy` response header should be send
# only for HTML documents and not for the other resources.
<FilesMatch "\.(appcache|atom|bbaw|bmp|crx|css|cur|eot|f4[abpv]|flv|geojson|gif|htc|ico|jpe?g|js|json(ld)?|m4[av]|manifest|map|mp4|oex|og[agv]|opus|otf|pdf|png|rdf|rss|safariextz|svgz?|swf|topojson|tt[cf]|txt|vcard|vcf|vtt|webapp|web[mp]|woff2?|xloc|xml|xpi)$">
Header unset Content-Security-Policy
</FilesMatch>
</IfModule>
I looked everywhere, but only land on pages that have the same, almost ritual used codeblock, without further explanation. So question 2: why is a simple declaration like this not possible?:
<IfModule mod_headers.c>
# Content-Security-Policy for .html files
<FilesMatch "\.(html)$">
Header set Content-Security-Policy "script-src 'self'; object-src 'self'"
</FilesMatch>
# OR like this
<Files ~ "\.(html)$">
Header set Cache-Control "public, must-revalidate"
</Files>
</IfModule>
It is possible to do that as per your second example. But .html are not the only files that could be sent as documents. You could also use .php or .htm or any other number of files. Some of these (like .php) may execute and then ultimately return HTML but the server doesn't know that as all it knows at this stage is the file extension.
CSP should be set on all documents but, to save header bandwidth, does not need to be set on assets used by those documents (e.g. images, style sheets, javascript... etc). Other than wasted bandwidth there is no really harm in setting it on other documents.
Ideally you would set it based on the mime-type returned (which in the PHP example above would be HTML). So anytime a HTML document is returned then set it, else don't. However as this is not possible you're left with two choices:
Set it on everything by default but then explicitly unset it for known media types. This pretty much guarantees it will be set on the document but also risks it being set on a few other file types (e.g. if you don't explicitly unset it for that type) - which, as I say isn't really that bad.
Explicitly state your HTML document types (like your second example). The risk here is you miss a file type (e.g. .php) either now or when someone else starts using php on your site in future.
The first option is the safer option. Particularly for html5boiler plate where they have no idea what technology will be used on the site it's used on. A site might use .php, .cgi, .asp or any number of technologies to generate the HTML document. They could even proxy the request to a back end server so they would be no file extension.
Make sense?

Far future Expires header ignored

Following the advice given by Yahoo / YSlow at http://developer.yahoo.com/performance/rules.html#expires I am trying to set a far future Expires header for my images.
In my .htacess I have:
<filesMatch "\.(jpg|jpeg|png|gif)$">
Header unset Pragma
FileETag None
Header unset ETag
Header set Cache-Control "public"
Header set Expires "Thu, 15 Apr 2014 20:00:00 GMT"
Header unset Last-Modified
</filesMatch>
Using Live HTTP Headers in Firefox I can see that there is no ETag and the Expires date shows as 2014. Also, looking at the cache I can confirm the Expires date and that there is no ETag or Server Last Modified date.
Again following the information given at YSlow I was expecting that if I now alter an image without altering its filename no changes would take effect until the Expires date is reached. YSlow points out that “if you use a far future Expires header you have to change the component's filename whenever the component changes”.
However, testing on localhost with XAMPP any change I make to an image is still immediately reflected on the web page if I refresh it.
Is this a local server thing or have I misunderstood how this is intended to work?
Thanks.

Resources