You are viewing a plain text version of this content. The canonical link for it is here.
Posted to embperl@perl.apache.org by Roman Maeder <ma...@mathconsult.ch> on 2000/12/03 16:05:24 UTC

How to set the Last-Modified header for Embperl pages

Greetings, Embperl hackers!

here's a recipe for setting the "Last-Modified" response header and
handling conditional requests with the "If-Modified-Since" request header
under mod_perl.
The idea is to return a "304 not modified" status code and omit the body
in the reply if the page hasn't been modified since the requested date.
Doing so will reduce the load on your server, improve caching and may
help search spiders to properly index your pages.

The basic method described in the eagle book [1] works
also with Embperl pages, but there are two issues

- determining the correct last modification time for documents handled
  with the EmbperlObject handler

- Embperl 1.3 cannot throw away a partial generated body
  (even though output is buffered and the stuff hasn't left the server yet).
  According the the HTTP/1.1 specs (RFC 2616) a 304 response must not contain
  a body. This issue is on Gerald's TODO list.

If you have a simple Embperl page, the following code near the top of
the page (after setting any headers, but before generating any HTML output)
will handle conditional requests

[- # set modification date and handle conditional requests
   $req_rec->update_mtime((stat _)[9]);

   $req_rec->set_last_modified();
   if ((my $rc = $req_rec->meets_conditions) != OK) { # we can give up
         $req_rec->status($rc);
         exit;
   }
-]

(The _ file handle contains cashed stat() data for the requested file,
per the eagle book)

If you render dynamic content, you might still be able to determine a suitable
mod time, for example, by finding the latest modification time of a database
from where your data are taken. Im MySQL, this works well:

	SELECT max(unix_timestamp(changetime)) FROM mytable;

where 'changetime' is a datetime field that is updated everytime somebody
messes with the data.


In a page handled by EmbperlObject, for example with this configuration
in httpd.conf

<Files *.epl>
    PerlSetEnv EMBPERL_OBJECT_BASE _main.epl
    SetHandler  perl-script
    PerlHandler HTML::EmbperlObject
    Options +ExecCGI
</Files>

there are at least two modification times to consider
- the modtime of the object wrapper, _main.epl
- the modtime of the page requested

The handler code for EmbperlObject puts the original file name requested
into $req_rec->notes('EMBPERL_orgfilename'), and sets $req_rec->filename
to the object wrapper page, so the following code near the top of _main.epl
(before Execute('*'), of course) will set the headers:

[- # set modification date and handle conditional requests
   # object page
   $req_rec->update_mtime((stat $req_rec->filename)[9]);
   # page to be served
   $req_rec->update_mtime((stat $req_rec->notes('EMBPERL_orgfilename'))[9]);

   $req_rec->set_last_modified();
   if ((my $rc = $req_rec->meets_conditions) != OK) { # we can give up
         $req_rec->status($rc);
         exit;
   }
-]


If you have pages whose output depends on other things as well, you 
might still keep track of all mod times and set the Last-Modified header,
but you should not exit with a 304 status after having started to generate
any HTML output.

Roman Maeder

[1] Lincoln Stein & Doug MacEachern, Writing Apache Modules with Perl and C.
    O'Reilly, 1999. page 121


Re: How to set the Last-Modified header for Embperl pages

Posted by Gerald Richter <ri...@ecos.de>.
Thanks Roman for your description. I have two annotations:

> If you have a simple Embperl page, the following code near the top of
> the page (after setting any headers, but before generating any HTML
output)
> will handle conditional requests
>
> [- # set modification date and handle conditional requests
>    $req_rec->update_mtime((stat _)[9]);
>
>    $req_rec->set_last_modified();
>    if ((my $rc = $req_rec->meets_conditions) != OK) { # we can give up
>          $req_rec->status($rc);
>          exit;
>    }
> -]
>
> (The _ file handle contains cashed stat() data for the requested file,
> per the eagle book)
>

That's true for a modperl handler, and it works for an Embperl page too but
this is chance...

It works because Embperl does a stat on the page, before it executes it, but
it is not guarantee to stay so in the future. Especialy for Embperl 2.0 I
have plans to move some of the startup code into C, because it takes a lot
of time for small pages and in this case _ will be undefined.

Fortunately I also have plans to build this sending of the last-modified
header and the 304 response directly into Embperl to integrate it well with
it's cache management.

>[..]
> The handler code for EmbperlObject puts the original file name requested
> into $req_rec->notes('EMBPERL_orgfilename'),

This is true for Embperl 1.3.0 but is only there for compatibility reasons.
Future version will include a documentation of the Embperl request object
and this object will have methods to retrive these filenames (actually they
are already there, but may be subject to change, so I don't like to publish
them here)

Gerald


-------------------------------------------------------------
Gerald Richter    ecos electronic communication services gmbh
Internetconnect * Webserver/-design/-datenbanken * Consulting

Post:       Tulpenstrasse 5         D-55276 Dienheim b. Mainz
E-Mail:     richter@ecos.de         Voice:    +49 6133 925151
WWW:        http://www.ecos.de      Fax:      +49 6133 925152
-------------------------------------------------------------