Catalyst::Plugin::Cache::HTTP::Preempt - preemptive HTTP cache control
This is a Catalyst plugin handles HTTP 1.1 cache-control queries.
The functionality is similar to Catalyst::Plugin::Cache::HTTP, except that it processes the cache control queries before data-intensive queries, rather rather than delaying processing until the view is generated.
use Catalyst qw/ Cache::HTTP::Preempt /; __PACKAGE__->config( 'Plugin::Cache::HTTP::Preempt' => { no_preempt_head => 0, etag_generator => sub { my ($c, $config) = @_; return "W/" . sprintf("%x", $c->res->headers->last_modified); }, }, );
By default, the "not_cached" method will return false for HEAD requests (even though it will still process cache control headers).
false
HEAD
If you still want to handle HEAD requests, then set this option to a true value.
true
Do not set the ETag header.
ETag
Do not set the Last-Modified header.
Last-Modified
Do not set the Expires header.
Expires
You can change how the ETag is generated by using the etag_generator option:
etag_generator
sub etag_generator { my ($c, $config) = @_; my $mtime = $c->req->headers->last_modified; return sprintf( $config->{strong} ? "%x" : "W/%x" , $mtime); } if ($c->not_cached({ etag_generator => \&etag_generator }) { ... }
This is useful if you want to use something other than the modification date of an entity for generating the ETag.
The purpose of this function is to only generate the ETag. No headers should be changed.
Returning an undef value corresponds to not setting an ETag.
undef
Generate a strong ETag. By default, a weak ETag is used, since the ETag is based on the Last-Modified time rather than the content.
As per the HTTP 1.1 specification, weak ETags will not work with the If-Match header.
ETags
If-Match
When this option, is true, it will check for the If-Range and Range headers. The controller is responsible for sending the correct response. (See the discussion for the "not_cached" method below.)
If-Range
Range
$c->res->headers->last_modified( $obj->mtime ); ... if ($c->not_cached(\%options)) { # The response is not cached, so should be generated ... } else { ... }
Checks the requests for HTTP 1.1 cache control headers and handles them accordingly.
This method sets the ETag header based on the Last-Modified header (unless one is already set) and checks for the If-Modified-Since, If-Unmodified-Since, If-Match and If-None-Match request headers to see if generating the entity can be preempted.
If-Modified-Since
If-Unmodified-Since
If-None-Match
If the entity can be preempted (i.e. if it has not been modified since the given date), then the status is set appropriately, and this method returns false.
Otherwise it returns true. This allows you to avoid reading data from a database or otherwise data-intensive processing when it's not actually needed.
If %options are given, then they will override the global options.
%options
If the Last-Modified header is unset, then this function will assume the last-modification time is the current time.
If no Expires header is set and the function will return a true value, then it will set it to the current time. (This is important for web browsers that aggressively cache responses, such as Firefox.)
Cache control options will be processed for HEAD requests, but this method will always return false, unless the no_preempt_head option is true.
no_preempt_head
If the status is already set to something other than 2xx when this method is called, then the the If-Match, If-None-Match and If-Unmodified-Since headers will be ignored. However, the ETag, Expires and Last-Modified headers will still be set. (Ideally, you would not be calling the "not_cached" method if there is an error.)
2xx
If the check_if_range option is true, then you must check whether the status code has been set to 206 or 200, and respond accordingly:
check_if_range
206
200
if ($c->not_cached( { check_if_range => 1 }) { if ($c->res->code == 206) { # Return partial content as per the Range header. ... } else { # Return full content. Note that the status is set to 200, so # it must be updated if there are other errors ... } }
This module can be used with Catalyst::Plugin::Cache::HTTP in a Catalyst application, although it is not recommended that you use it in the same method.
If you are using both plugins, then you should modify the view processing method to check if an ETag header has already been set:
sub process { my $self = shift; my $c = $_[0]; $self->next::method(@_) or return 0; my $method = $c->req->method; return 1 if ((($method ne 'GET') and ($method ne 'HEAD')) or $c->stash->{nocache}); # disable caching explicitely unless ($c->res->headers->etag || $c->stash->{no_etag}) { ... } }
Catalyst::Controller::REST does not have status helpers for "304 Not Modified" and and "412 Precondition Failed" responses.
To work around this, you need to manually set the entity using an undocumented method:
$c->res->headers->last_modified( $obj->mtime ); if ($c->modified) { # Do more processing to generate the page } else { $self->_set_entity($c, { error => "Not Modified" }); return 1; }
Catalyst
Catalyst::Plugin::Cache::HTTP
HTTP 1.1
Interactive Information, Ltd <cpan at interactive.co.uk>
<cpan at interactive.co.uk>
You can find documentation for this module with the perldoc command.
perldoc Catalyst::Plugin::Cache::HTTP::Preempt
You can also find information at:
RT: CPAN's request tracker (report bugs here)
http://rt.cpan.org/NoAuth/Bugs.html?Dist=Catalyst-Plugin-Cache-HTTP-Preempt
AnnoCPAN: Annotated CPAN documentation
http://annocpan.org/dist/Catalyst-Plugin-Cache-HTTP-Preempt
CPAN Ratings
http://cpanratings.perl.org/d/Catalyst-Plugin-Cache-HTTP-Preempt
Search CPAN
http://search.cpan.org/dist/Catalyst-Plugin-Cache-HTTP-Preempt/
Copyright (c) 2012-2013 Interactive Information, Ltd
This program is free software; you can redistribute it and/or modify it under the terms of the the Artistic License (2.0). You may obtain a copy of the full license at:
http://www.perlfoundation.org/artistic_license_2_0
Any use, modification, and distribution of the Standard or Modified Versions is governed by this Artistic License. By using, modifying or distributing the Package, you accept this license. Do not use, modify, or distribute the Package, if you do not accept this license.
If your Modified Version has been derived from a Modified Version made by someone other than you, you are nevertheless required to ensure that your Modified Version complies with the requirements of this license.
This license does not grant you the right to use any trademark, service mark, tradename, or logo of the Copyright Holder.
This license includes the non-exclusive, worldwide, free-of-charge patent license to make, have made, use, offer to sell, sell, import and otherwise transfer the Package with respect to any patent claims licensable by the Copyright Holder that are necessarily infringed by the Package. If you institute patent litigation (including a cross-claim or counterclaim) against any party alleging that the Package constitutes direct or contributory patent infringement, then this Artistic License to you shall terminate on the date that such litigation is filed.
Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
To install Catalyst::Plugin::Cache::HTTP::Preempt, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Catalyst::Plugin::Cache::HTTP::Preempt
CPAN shell
perl -MCPAN -e shell install Catalyst::Plugin::Cache::HTTP::Preempt
For more information on module installation, please visit the detailed CPAN module installation guide.