Link to home
Start Free TrialLog in
Avatar of mychel_normandeau
mychel_normandeauFlag for Canada

asked on

How to know when to send a 304 Not Modified HTTP response

I have a cacheable (by proxies and clients) Web application generated in PHP 5.1.0. My headers fields already allow public cache and also include an "ETag" header and a "Last-Modified" header.

Since everything is cacheable, I want to answer IF-MODIFIED-SINCE and IF-NONE-MATCH HTTP requests with a 304 "Not Modified" answer when conditions match.

Now I'm not sure in which cases to send the 304. What are the conditions to serve a 304 instead of the whole content? Must the IF-MODIFIED-SINCE sent by the client must match my document and also the IF-NONE-MATCH sent must match my ETags? Or if only one of these two match I can serve a 304?

I'm actually looking in conditions where to serve a 304... Can be answered in PHP or in (understandable and well explained) pseudo-code.

PS: So far I found some snippets showing what I want but they are all different and not documented (see attached code snippet). I'm looking for the right way to do this...

Thanks!
$ifModifiedSince = array_key_exists('HTTP_IF_MODIFIED_SINCE', $_SERVER) ? $_SERVER['HTTP_IF_MODIFIED_SINCE'] : false;
$ifNoneMatch = array_key_exists('HTTP_IF_NONE_MATCH', $_SERVER) ? $_SERVER['HTTP_IF_NONE_MATCH'] : false;

//VERSION 1
if ((($ifNoneMatch && $ifNoneMatch == $this->GetETag()) || (!$ifNoneMatch)) &&
    ($ifModifiedSince && $ifModifiedSince == $this->GetLastModified()))
{
    header('Not Modified', true, 304);
    exit();
}

//VERSION 2
if ($ifModifiedSince == $this->GetLastModified() || $ifNoneMatch == $this->GetETag())
{
    header('Not Modified', true, 304);
    exit();
}

Open in new window

Avatar of Steve Bink
Steve Bink
Flag of United States of America image

What exactly is undocumented about about the snippets?

http://www.php.net/manual/en/function.header.php

Be sure you read the full description of the first parameter.  Your header text is malformed.
> I have a cacheable ..
and
> I want to answer IF-MODIFIED-SINCE and IF-NONE-MATCH HTTP requests ..

if you have a cache, your application never gets these requests, or do I misunderstand something?
http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.25 (and following section)

In the case of IF-MODIFIED-SINCE, your application should never have to send its own 304.  The web server will draw the comparison based on the date of the cached resource and respond appropriately.  If the cache has been modified since the provided date, the cache is sent.  The modification date of the cached resource is dependent on local cache controls, not the body of a request, so your application should not see the request unless the cache has also expired.

For IF-NONE-MATCH, if the entity matches, then your application will not see the request at all.  If a match is not found, the specification prohibits sending a 304.
Avatar of mychel_normandeau

ASKER

routinet:
"What exactly is undocumented about about the snippets?"
What is not documented is why they do it this way?
"Be sure you read the full description of the first parameter.  Your header text is malformed."
Not it is not, it's not even used. Did you knew that by specifieng a http_response_code, PHP will create the correct header?

ahoffmann:
"if you have a cache, your application never gets these requests, or do I misunderstand something?"
I think you dont understand cache... When proxies/clients will need to revalidate their cache THEY WILL send these headers to ask if their cache is still valid (if they are not sure if still valid).

routinet:
"In the case of IF-MODIFIED-SINCE, your application should never have to send its own 304.  The web server will draw the comparison based on the date of the cached resource and respond appropriately."
Oh yeah, Apache can know if a database field used in a query in a PHP page has been modified since last time and will send the headers automatically? I don't think so...

Still at point zero here...
>>> What is not documented is why they do it this way?

Why who did what in what way?  You posted a small snippet of code that checks for the presence of headers, and based on those may call a method of a class you did not describe in your post.  What is the $this object you are referencing there?  What are the methods being called?  It looks like an *application level* caching strategy, but you posted this in the Apache zone.  Which is it?

>>> Did you knew that by specifieng a http_response_code, PHP will create the correct header?

I did not know this...I only know that the examples in the manual show a complete HTTP response formed for the first parameter.  Of course, it does lack good examples of the usage of the third parameter.  One of the user comments make the same claim about PHP creating the response for you, but I have not tried it first-hand.

>>> I think you dont understand cache... When proxies/clients will need to revalidate their cache THEY WILL send these headers to ask if their cache is
>>> still valid (if they are not sure if still valid).
[ ... ]
>>> Oh yeah, Apache can know if a database field used in a query in a PHP page has been modified since last time and will send the headers automatically? I don't think so...

Take a look at which zones you used for this post.  You posted this in the Apache zone, and ahoffmann's question and my comments are valid in the context of Apache.  If you are using Apache's caching mechanisms, this is handled above the application, i.e., the application will never see the header because Apache handles the request through its cache.  

If you are trying to create an application-level caching mechanism (which would be necessary to use granular database changes as a basis for expiration), then the code you posted makes perfect sense and does not really need any further explanation.  What do you not understand about it?  The first version checks for equality.  The second version checks for passing an expiration milestone.  The specification finds both methods acceptable per the link I posted earlier.  See the third note under section 14.25.  That implies it is your choice as to which method you will use to verify the status of the cache.  If you ever plan to revert content, I recommend you use the equality check.
> When proxies/clients will need to revalidate their cache ..
my question/comment was about a caching server, which never sends such headers, except the resource is not under its control.
So if you application gets these headers you either have
  - no cache (server) in front
  - the cache server is buggy or mis configured
ASKER CERTIFIED SOLUTION
Avatar of mychel_normandeau
mychel_normandeau
Flag of Canada image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial