[Last Call] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 426
  • Last Modified:

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

0
mychel_normandeau
Asked:
mychel_normandeau
  • 3
  • 2
  • 2
1 Solution
 
Steve BinkCommented:
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.
0
 
ahoffmannCommented:
> 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?
0
 
Steve BinkCommented:
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.
0
NEW Veeam Backup for Microsoft Office 365 1.5

With Office 365, it’s your data and your responsibility to protect it. NEW Veeam Backup for Microsoft Office 365 eliminates the risk of losing access to your Office 365 data.

 
mychel_normandeauAuthor Commented:
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...
0
 
Steve BinkCommented:
>>> 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.
0
 
ahoffmannCommented:
> 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
0
 
mychel_normandeauAuthor Commented:
Thanks for the hints but found the doc I was seeking:
http://rithiur.anthd.com/tutorials/conditionalget.php
0

Featured Post

Nothing ever in the clear!

This technical paper will help you implement VMware’s VM encryption as well as implement Veeam encryption which together will achieve the nothing ever in the clear goal. If a bad guy steals VMs, backups or traffic they get nothing.

  • 3
  • 2
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now