File Coverage

blib/lib/Catalyst/Plugin/PageCache.pm
Criterion Covered Total %
statement 181 198 91.4
branch 89 136 65.4
condition 37 74 50.0
subroutine 14 14 100.0
pod 5 5 100.0
total 326 427 76.3


line stmt bran cond sub pod time code
1             package Catalyst::Plugin::PageCache;
2              
3 12     12   12956376 use strict;
  12         18  
  12         344  
4 12     12   40 use base qw/Class::Accessor::Fast/;
  12         13  
  12         2304  
5 12     12   9457 use MRO::Compat;
  12         2677  
  12         189  
6 12     12   4833 use Digest::SHA1 ();
  12         6145  
  12         20698  
7              
8             our $VERSION = '0.32';
9              
10             # Do we need to cache the current page?
11             __PACKAGE__->mk_accessors('_cache_page');
12              
13             # Keeps track of whether the current request was served from cache
14             __PACKAGE__->mk_accessors('_page_cache_used');
15              
16             # Keeps a safe copy of the initial request parameters, in case the
17             # user changes them during processing
18             __PACKAGE__->mk_accessors('_page_cache_key');
19              
20             sub cache_page {
21 28     28 1 73424 my ( $c, @args ) = @_;
22 28         39 my %options;
23              
24             # Mark that cache_page has been called but defer on selecting the time
25             # period to cache for until finalize. _get_page_cache_expiration_time has
26             # more options at that time, such as various headers which may have been set.
27              
28 28 100       187 if (@args == 1) {
29 21         38 my $expires = shift @args;
30              
31             # Allow specific end time
32 21 50 33     94 $expires = $expires->epoch - time()
33             if ref($expires) && $expires->can('epoch');
34              
35 21         73 $options{cache_seconds} = $expires;
36             }
37             else {
38 7         25 %options = @args;
39             }
40              
41 28         117 $c->_cache_page( \%options );
42             }
43              
44              
45             sub clear_cached_page {
46 2     2 1 5700 my ( $c, $uri ) = @_;
47              
48 2 50       10 return undef unless $c->can( 'cache' );
49              
50 2         6 my $pc_config = $c->config->{'Plugin::PageCache'};
51 2         98 my $is_debug = $pc_config->{debug};
52            
53             # Warn if index was disabled
54 2 50       7 my $index_page_key = $pc_config->{index_page_key} or do {
55 0         0 $c->log->warn("clear_cached_page($uri) did not clear the cache because disable_index is set");
56 0         0 return;
57             };
58            
59 2         6 my $cache = $c->cache; # curry the cache just once, here
60              
61 2   50     69 my $index = $cache->get( $index_page_key ) || {};
62              
63 2         859 my $removed = 0;
64 2         8 foreach my $index_key ( keys %$index ) {
65              
66             # find matching entries, ignoring the language prefix
67 2 50       55 next unless $index_key =~ /^ $uri (?:\#.*)? $/x;
68              
69             # delete from the index and remove the corresponding cache entry
70             # (which may have a different key, e.g., sha1 encoded)
71 2         4 my $cache_key = delete $index->{$index_key};
72 2         7 $cache->remove( $cache_key );
73 2         429 $removed++;
74              
75 2 50       8 $c->log->debug( "Removed $index_key from page cache" ) if $is_debug;
76             }
77              
78             $cache->set( $index_page_key, $index, $pc_config->{no_expire} )
79 2 50       13 if $removed;
80              
81 2         1428 $removed;
82             }
83              
84              
85             # return the time that the item should expire
86             sub _get_page_cache_expiration_time {
87 26     26   37283 my ($c, $options) = @_;
88 26         89 my $pc_config = $c->config->{'Plugin::PageCache'};
89 26         1374 my $is_debug = $pc_config->{debug};
90              
91 26         34 my $expires;
92              
93             # Use the explicitely passed in duration if available.
94             # XXX but why then ignore it if it's <= 0 ?
95 26 100 66     155 if ($options->{cache_seconds} and $options->{cache_seconds} > 0) {
96 13 50       34 $c->log->debug("expires in specified $options->{cache_seconds}s")
97             if $is_debug;
98              
99 13         29 $expires = time() + $options->{cache_seconds};
100             }
101             # else {
102             # ... calculate expiry based on the response headers
103             # }
104             # If all else fails, fallback to the default 'expires' configuration value.
105             else {
106 13 50       33 $c->log->debug("expires in default $pc_config->{expires}s")
107             if $is_debug;
108 13         27 $expires = time() + $pc_config->{expires};
109             }
110              
111 26         132 return $expires;
112             }
113              
114              
115             sub dispatch {
116 48     48 1 11645894 my $c = shift;
117              
118             # only serve GET and HEAD request pages from cache
119             # (never POST, PUT, DELETE etc)
120 48 50       123 return $c->next::method(@_)
121             unless $c->req->method =~ m/^(?:GET|HEAD)$/;
122              
123 48         2328 my $pc_config = $c->config->{'Plugin::PageCache'};
124              
125 48   33     2657 my $hook_name = $pc_config->{cache_dispatch_hook} || $pc_config->{cache_hook};
126 48 100       131 my $hook = $hook_name ? $c->can($hook_name) : undef;
127 48 100 100     147 return $c->next::method(@_) if ( $hook && !$c->$hook() );
128              
129             return $c->next::method(@_)
130             if ( $pc_config->{auto_check_user}
131 46 0 33     172 && $c->can('user_exists')
      33        
132             && $c->user_exists);
133              
134             # check the page cache for a cached copy of this page
135 46 50       168 return $c->next::method(@_)
136             unless my $key = $c->_get_page_cache_key;
137              
138 46         194 my $cache = $c->cache; # curry the cache just once, here
139              
140 46 100       15471 return $c->next::method(@_)
141             unless my $data = $cache->get( $key );
142              
143             # Time to remove page from cache?
144              
145 18 100 66     9618 if ( $data->{expire_time} && $data->{expire_time} <= time ) {
146 3 100       13 if ( my $busy_lock = $pc_config->{busy_lock} ) {
147             # Extend the expiration time for others while
148             # this caller refreshes the cache
149 1         4 $data->{expire_time} = time() + $busy_lock;
150            
151 1         6 $cache->set( $key, $data );
152            
153             $c->log->debug( "$key has expired, being refreshed for $busy_lock seconds" )
154 1 50       976 if ($pc_config->{debug});
155             }
156             else {
157             $c->log->debug( "Expiring $key from page cache" )
158 2 50       8 if ($pc_config->{debug});
159              
160 2         10 $cache->remove( $key );
161              
162 2 50       477 if ( my $index_page_key = $pc_config->{index_page_key} ) {
163 2   50     7 my $index = $cache->get( $index_page_key ) || {};
164 2         696 my $found = delete $index->{ $data->{index_key} };
165             $cache->set( $index_page_key, $index, $pc_config->{no_expire})
166 2 50       13 if $found;
167             }
168             }
169              
170 3         1539 return $c->next::method(@_);
171             }
172              
173             $c->log->debug("Serving $key from page cache, expires in "
174             . ($data->{expire_time} - time)
175             . " seconds")
176 15 50       61 if ($pc_config->{debug});
177              
178 15         66 $c->_page_cache_used( 1 );
179              
180             # Check If-Modified-Since headers
181 15 50       97 return 1 if $c->_page_cache_not_modified( $data );
182              
183             # Serve cached page
184              
185 15         60 $c->res->body( $data->{body} );
186              
187 15         370 $c->res->content_type( join '; ', @{$data->{content_type}} )
188 15 50       742 if $data->{content_type};
189              
190             $c->res->content_encoding( $data->{content_encoding} )
191 15 50       2828 if $data->{content_encoding};
192              
193 15         54 $c->_set_page_cache_headers( $data );
194              
195 15         747 $c->res->header('X-PageCache', 'Catalyst');
196              
197             }
198              
199             # See if request matches last_modified date in cache
200             # if so, arrange to return a 304 Not Modified status
201             # and return true.
202              
203             sub _page_cache_not_modified {
204 41     41   64 my ( $c, $data ) = @_;
205              
206 41 50       117 if ( $c->req->headers->if_modified_since ) {
207              
208 0 0       0 if ( $c->req->headers->if_modified_since == $data->{create_time} ) {
209 0         0 $c->res->status(304); # Not Modified
210 0         0 $c->res->headers->remove_content_headers;
211 0         0 $c->_set_page_cache_headers( $data );
212 0         0 $c->res->body( '' );
213 0         0 return 1;
214             }
215             }
216              
217 41         6424 return;
218             }
219              
220             # Sets cache headers for the page if set_http_headers is true.
221              
222             sub _set_page_cache_headers {
223 41     41   69 my ( $c, $data ) = @_;
224 41         123 my $headers = $c->res->headers;
225 41         4434 my $pc_config = $c->config->{'Plugin::PageCache'};
226              
227 41 100       2284 if ( $pc_config->{cache_headers} ) {
228 4 50       3 for my $header_key ( keys %{ $data->{headers} || {} } ) {
  4         17  
229             $headers->header(
230 2         8 $header_key => $data->{headers}->{$header_key}
231             );
232             }
233             }
234            
235 41 100       196 return unless $pc_config->{set_http_headers};
236              
237 10 100       24 if ( exists $data->{expires} ) {
238              
239             # page cache but not client cache
240 6 100       15 if ( !$data->{expires} ) {
241 4         14 $headers->header( 'Cache-Control' => 'no-cache' );
242 4         118 $headers->header( 'Pragma' => 'no-cache' );
243 4         81 return;
244             }
245              
246             $headers->header(
247 2         9 'Cache-Control' => "max-age=" . $data->{expires});
248              
249 2         60 $headers->expires( time + $data->{expires} );
250              
251             }
252             else {
253              
254             $headers->header(
255 4         16 'Cache-Control' => "max-age=" . ($data->{expire_time} - time));
256              
257 4         105 $headers->expires( $data->{expire_time} );
258             }
259              
260             $headers->last_modified( $data->{create_time} )
261 6 50 33     3360 unless $c->res->status && $c->res->status == 304;
262             }
263              
264             sub finalize {
265 48     48 1 6049226 my $c = shift;
266              
267             # never cache POST requests
268 48 50       126 return $c->next::method(@_) if ( $c->req->method eq "POST" );
269              
270 48         2275 my $pc_config = $c->config->{'Plugin::PageCache'};
271              
272 48   33     2591 my $hook_name = $pc_config->{cache_finalize_hook} || $pc_config->{cache_hook};
273 48 100       121 my $hook = $hook_name ? $c->can($hook_name) : undef;
274 48 100 100     148 return $c->next::method(@_) if ( $hook && !$c->$hook() );
275              
276             return $c->next::method(@_)
277             if ( $pc_config->{auto_check_user}
278 46 0 33     138 && $c->can('user_exists')
      33        
279             && $c->user_exists);
280 46 50       52 return $c->next::method(@_) if ( scalar @{ $c->error } );
  46         125  
281              
282             # if we already served the current request from cache, we can skip the
283             # rest of this method
284 46 100       396 return $c->next::method(@_) if ( $c->_page_cache_used );
285              
286 31 100 100     183 if (!$c->_cache_page
287 7         54 && scalar @{ $pc_config->{auto_cache} })
288             {
289              
290             # is this page part of the auto_cache list?
291 2         6 my $path = "/" . $c->req->path;
292              
293             # For performance, this should be moved to setup, and generate a hash.
294             AUTO_CACHE:
295 2         143 foreach my $auto (@{ $pc_config->{auto_cache} })
  2         6  
296             {
297 3 50       8 next if $auto =~ m/^\d$/;
298 3 100       36 if ( $path =~ /^$auto$/ ) {
299             $c->log->debug( "Auto-caching page $path" )
300 2 50       10 if ($pc_config->{debug});
301 2         9 $c->cache_page;
302 2         12 last AUTO_CACHE;
303             }
304             }
305             }
306              
307 31 100       146 if ($c->_cache_page) {
308 26         127 my $data = $c->_store_page_in_cache($c->_cache_page) ;
309              
310             # Check for If-Modified-Since
311 26 50       210 $c->_page_cache_not_modified( $data ) if $data;
312             }
313              
314 31         186 return $c->next::method(@_);
315             }
316              
317              
318             sub _store_page_in_cache {
319 26     26   139 my ($c, $options) = @_;
320              
321 26         71 my $key = $c->_get_page_cache_key;
322 26         221 my $pc_config = $c->config->{'Plugin::PageCache'};
323 26         1177 my $now = time();
324              
325 26         64 my $headers = $c->res->headers;
326              
327             # Cache some additional metadata along with the content
328             # Some caches don't support expirations, so we do it manually
329             my $data = {
330             body => $c->res->body || undef,
331             content_type => [ $c->res->content_type ] || undef,
332             content_encoding => $c->res->content_encoding || undef,
333             create_time => $options->{last_modified}
334 26   50     3944 || $headers->last_modified
      50        
      50        
      66        
335             || $now,
336             expire_time => $c->_get_page_cache_expiration_time($options),
337             };
338              
339 26 50       85 return undef if $data->{expire_time} <= $now;
340              
341             $c->log->debug(
342             "Caching page $key for ". ($data->{expire_time} - time()) ." seconds"
343 26 50       62 ) if ($pc_config->{debug});
344            
345 26 100       69 if ( $pc_config->{cache_headers} ) {
346             $data->{headers} = {
347 2         7 map { $_ => $headers->header($_) } $headers->header_field_names
  1         15  
348             };
349             }
350              
351 26 50       98 if ($pc_config->{index_page_key}) {
352             # We can't simply use $key for $index_key because $key may have been
353             # mangled by sha1 and/or a key_maker hook. We include $key to ensure
354             # unique entries in the index in cases where a given uri might produce
355             # different results eg due to headers like language.
356 26         104 $data->{index_key} = '/'.$c->req->path;
357 26 100       2115 $data->{index_key} .= '?'.$c->req->uri->query if $c->req->uri->query;
358 26         1661 $data->{index_key} .= '#'.$key;
359             }
360              
361 26 100       83 if (exists $options->{expires}) {
362             $data->{expires} = $options->{expires}
363 3         5 }
364              
365 26         92 my $cache = $c->cache; # curry the cache just once, here
366              
367 26         971 $cache->set( $key, $data );
368              
369 26         28996 $c->_set_page_cache_headers( $data ); # don't forget the first time
370              
371 26 50       783 if ( $data->{index_key} ) {
372             # Keep an index cache of all pages that have been cached, for use
373             # with clear_cached_page. This is error prone. See KNOWN ISSUES.
374 26         42 my $index_page_key = $pc_config->{index_page_key};
375 26   100     120 my $index = $cache->get($index_page_key) || {};
376 26         7565 $index->{ $data->{index_key} } = $key;
377 26         116 $cache->set($index_page_key, $index, $pc_config->{no_expire});
378             }
379              
380 26         18172 return $data;
381             }
382              
383              
384             sub setup {
385 11     11 1 2104670 my $c = shift;
386              
387 11         62 $c->next::method(@_);
388              
389             # allow code using old config key to work
390 11 50 33     181 if ( $c->config->{page_cache} and !$c->config->{'Plugin::PageCache'} ) {
391 0         0 $c->config->{'Plugin::PageCache'} = delete $c->config->{page_cache};
392             }
393              
394 11   50     758 my $pc_config = $c->config->{'Plugin::PageCache'} ||= {};
395              
396 11   50     509 $pc_config->{auto_cache} ||= [];
397 11   50     52 $pc_config->{expires} ||= 60 * 5;
398 11   50     47 $pc_config->{cache_headers} ||= 0;
399 11   50     45 $pc_config->{set_http_headers} ||= 0;
400 11   50     40 $pc_config->{busy_lock} ||= 0;
401 11   33     70 $pc_config->{debug} ||= $c->debug;
402              
403             # default the page key to include the app name to give some measure
404             # of protection if the cache doesn't have a namespace set.
405             $pc_config->{index_page_key} = "$c._page_cache_index"
406 11 50       159 unless defined $pc_config->{index_page_key};
407              
408 11 50       42 if (not defined $pc_config->{disable_index}) {
409 0         0 warn "Plugin::PageCache config does not include disable_index, which currently defaults false but may default true in future\n";
410 0         0 $pc_config->{disable_index} = 0;
411             }
412             $pc_config->{index_page_key} = undef
413 11 50       28 if $pc_config->{disable_index};
414              
415             # detect the cache plugin being used and set appropriate
416             # never-expires syntax
417 11 50       126 if ( $c->can('cache') ) {
418              
419             # Newer C::P::Cache, cannot call $c->cache as a package method
420 11 50       86 if ( $c->isa('Catalyst::Plugin::Cache') ) {
421 11         29 return;
422             }
423              
424 0         0 my $cache = $c->cache; # curry the cache just once, here
425              
426             # Older Cache plugins
427 0 0 0     0 if ( $cache->isa('Cache::FileCache') ) {
    0          
428 0         0 $pc_config->{no_expire} = "never";
429             }
430             elsif ($cache->isa('Cache::Memcached')
431             || $cache->isa('Cache::FastMmap'))
432             {
433              
434             # Memcached defaults to 'never' when not given an expiration
435             # In FastMmap, it's not possible to set an expiration
436 0         0 $pc_config->{no_expire} = undef;
437             }
438             }
439             else {
440 0         0 die __PACKAGE__ . " requires a Catalyst::Plugin::Cache plugin.";
441             }
442             }
443              
444             sub _get_page_cache_key {
445 75     75   187 my $c = shift;
446            
447             # We can't rely on the params after the user's code has run,
448             # so we cache the key created during the initial dispatch phase
449             # and reuse it at finalize time.
450 75 100       209 return $c->_page_cache_key if ( $c->_page_cache_key );
451              
452             # override key if required, else use uri path
453 46         282 my $keymaker = $c->config->{'Plugin::PageCache'}->{key_maker};
454 46 100       2031 my $key = $keymaker ? $keymaker->($c) : "/" . $c->req->path;
455            
456             # prepend language if I18N present.
457 46 50       3645 if ( $c->can('language') ) {
458 0         0 $key = ':' . $c->language . ':' . $key;
459             }
460              
461             # some caches have limits on the max key length (eg for memcached it's 250
462             # minus the namespace length) so if the key is a non-trvial length then
463             # replace the tail with a sha1. (We only replace the tail because it's
464             # useful to be able to see the leading portion of the path in the debug logs)
465 46 100       137 if (length($key) > 100) {
466 1         8 substr($key, 100) = Digest::SHA1::sha1_hex($key); # 40 bytes
467             }
468             # Check for spaces as it's cheap insurance, just in case, for memcached
469 46         116 $key =~ s/\s/~/g;
470              
471             # we always sha1 the parameters/query as they're typically long
472             # and it also avoids issues like spaces in keys for memcached
473 46         52 my $params_key;
474 46         107 my $parameters = $c->req->parameters;
475 46 100       2447 if (%$parameters) {
    100          
476 5         8 local $Storable::canonical = 1;
477 5         19 $params_key = Storable::nfreeze($parameters);
478             }
479             elsif ( my $query = $c->req->uri->query ) {
480 1         45 $params_key = $query;
481             }
482             # use sha1 to avoid problems with over-long params or params
483             # containing values that can't be used as a key (eg spaces for memcached)
484 46 100       2190 $key .= '?' . Digest::SHA1::sha1_hex($params_key) # 40 bytes
485             if $params_key;
486              
487 46         124 $c->_page_cache_key( $key );
488              
489 46         297 return $key;
490             }
491              
492             1;
493             __END__
494              
495             =head1 NAME
496              
497             Catalyst::Plugin::PageCache - Cache the output of entire pages
498              
499             =head1 SYNOPSIS
500              
501             use Catalyst;
502             MyApp->setup( qw/Cache::FileCache PageCache/ );
503              
504             __PACKAGE__->config(
505             'Plugin::PageCache' => {
506             expires => 300,
507             set_http_headers => 1,
508             auto_cache => [
509             '/view/.*',
510             '/list',
511             ],
512             debug => 1,
513              
514             # Optionally, a cache hook method to be called prior to dispatch to
515             # determine if the page should be cached. This is called both
516             # before dispatch, and before finalize.
517             cache_hook => 'some_method',
518              
519             # You may alternatively set different methods to be used as hooks
520             # for dispatch and finalize. The dispatch method will determine
521             # whether the currently cached page will be displayed to the user,
522             # and the finalize hook will determine whether to save the newly
523             # created page.
524             cache_dispatch_hook => 'some_method_for_dispatch',
525             cache_finalize_hook => 'some_method_for_finalize',
526             }
527             );
528            
529             sub some_method {
530             my $c = shift;
531             if ( $c->user_exists and $c->user->some_field ) {
532             return 0; # Don't cache
533             }
534             return 1; # Cache
535             }
536              
537             # in a controller method
538             $c->cache_page( '3600' );
539              
540             $c->clear_cached_page( '/list' );
541              
542             # Expire at a specific time
543             $c->cache_page( $datetime_object );
544              
545              
546             # Fine control
547             $c->cache_page(
548             last_modified => $last_modified,
549             cache_seconds => 24 * 60 * 60, # once a day
550             expires => 300, # allow client caching
551             );
552              
553             =head1 DESCRIPTION
554              
555             Many dynamic websites perform heavy processing on most pages, yet this
556             information may rarely change from request to request. Using the PageCache
557             plugin, you can cache the full output of different pages so they are served to
558             your visitors as fast as possible. This method of caching is very useful for
559             withstanding a Slashdotting, for example.
560              
561             This plugin requires that you also load a Cache plugin. Please see the Known
562             Issues when choosing a cache backend.
563              
564             =head1 WARNINGS
565              
566             PageCache should be placed at the end of your plugin list.
567              
568             You should only use the page cache on pages which have NO user-specific or
569             customized content. Also, be careful if caching a page which may forward to
570             another controller. For example, if you cache a page behind a login screen,
571             the logged-in version may be cached and served to unauthenticated users.
572              
573             Note that pages that result from POST requests will never be cached.
574              
575             =head1 PERFORMANCE
576              
577             On my Athlon XP 1800+ Linux server, a cached page is served in 0.008 seconds
578             when using the HTTP::Daemon server and any of the Cache plugins.
579              
580             =head1 CONFIGURATION
581              
582             Configuration is optional. You may define the following configuration values:
583              
584             expires => $seconds
585              
586             This will set the default expiration time for all page caches. If you do not
587             specify this, expiration defaults to 300 seconds (5 minutes).
588              
589             cache_headers => 1
590              
591             Enable this value if you need your cached responses to include custom HTTP
592             headers set by your application. This may be necessary if you operate behind
593             an edge cache such as Akamai. This option is disabled by default.
594              
595             set_http_headers => 1
596              
597             Enabling this value will cause Catalyst to set the correct HTTP headers to
598             allow browsers and proxy servers to cache your page. This will further reduce
599             the load on your server. The headers are set in such a way that the
600             browser/proxy cache will expire at the same time as your cache. The
601             Last-Modified header will be preserved if you have already specified it. This
602             option is disabled by default.
603              
604             auto_cache => [
605             $uri,
606             ]
607              
608             To automatically cache certain pages, or all pages, you can specify auto-cache
609             URIs as an array reference. Any controller within your application that
610             matches one of the auto_cache URIs will be cached using the default expiration
611             time. URIs may be specified as absolute: '/list' or as a regex: '/view/.*'
612              
613             disable_index => 1
614              
615             To support the L</clear_cached_page> method, PageCache attempts keep an index
616             of all cached pages. This adds overhead by performing extra cache reads and
617             writes to maintain the (possibly very large) page index. It's also not
618             reliable, see L</KNOWN ISSUES>.
619              
620             If you don't intend to use C<clear_cached_page>, you should enable this config
621             option to avoid the overhead of creating and updating the cache index. This
622             option is currently disabled (i.e. the page index is enabled) by default but
623             that may change in a future release.
624              
625             index_page_key => '...'
626              
627             The key string used for the index, Defaults to a string that includes the name
628             of the Catalyst app class.
629              
630             busy_lock => 10
631              
632             On a high traffic site where page re-generation may take many seconds, a common
633             problem encountered is the "dog-pile" effect, where many concurrent connections all
634             hit a page where the cache has expired and all perform the same expensive operation
635             to rebuild the cache. To prevent this situation, you can set the busy_lock option
636             to the maximum number of seconds any of your pages can be expected to take to
637             rebuild the cache. Then, when the cache expires, the first request will rebuild the
638             cache while also extending the expiration time by the number of seconds specified,
639             allowing other requests that arrive before the cache has been rebuilt to use the
640             previously cached page. This option is disabled by default.
641              
642             debug => 1
643              
644             This will print additional debugging information to the Catalyst log. You will
645             need to have -Debug enabled to see these messages.
646              
647             auto_check_user => 1
648              
649             If this option is enabled, automatic caching is disabled for logged in users
650             i.e., if the app class has a user_exists() method and it returns true.
651              
652             cache_hook => 'cache_hook_method'
653             cache_finalize_hook => 'cache_finalize_hook_method'
654             cache_dispatch_hook => 'cache_dispatch_hook_method'
655              
656             Calls a method on the application that is expected to return a true or false.
657             This method is called before dispatch, and before finalize so you can short
658             circuit the pagecache behavior. As an example, if you want to disable
659             PageCache while running under debug mode:
660            
661             package MyApp;
662            
663             ...
664            
665             sub cache_hook_method { return shift->debug; }
666              
667             Or, if you want to not cache for certain roles, say "admin":
668            
669             sub cache_hook_method {
670             my ( $c ) = @_;
671             return !$c->check_user_roles('admin');
672             }
673              
674             Note that this is called BEFORE auto_check_user, so you have more flexibility
675             to determine what to do for not logged in users.
676              
677             To override the generation of page keys:
678              
679             __PACKAGE__->config(
680             'Plugin::PageCache' => {
681             key_maker => sub {
682             my $c = shift;
683             return $c->req->base . '/' . $c->req->path;
684             }
685             }
686             );
687              
688             C<key_maker> can also be the name of a method, which will be invoked as C<<$c->$key_maker>>.
689              
690             In most cases you would use a single cache_hook method for consistency.
691              
692             It is possible to achieve background refreshing of content by disabling
693             caching in cache_dispatch_hook and enabling caching in cache_finalize_hook
694             for a specific IP address (say 127.0.0.1).
695              
696             A cron of wget "http://localhost/foo.html" would cause the content to be
697             generated fresh and cached for future viewers. Useful for content which
698             takes a very long time to build or pages which should be refreshed at
699             a specific time such as always rolling over content at midnight.
700              
701             =head1 METHODS
702              
703             =head2 cache_page
704              
705             Call cache_page in any controller method you wish to be cached.
706              
707             $c->cache_page( $expire );
708              
709             The page will be cached for $expire seconds. Every user who visits the URI(s)
710             referenced by that controller will receive the page directly from cache. Your
711             controller will not be processed again until the cache expires. You can set
712             this value to a low value, such as 60 seconds, if you have heavy traffic, to greatly
713             improve site performance.
714              
715             Pass in a DateTime object to make the cache expire at a given point in time.
716              
717             $two_hours = DateTime->now->add( hours => 2 );
718             $c->cache_page( $two_hours );
719              
720             The page will be stored in the page cache until this time.
721              
722             If set_http_headers is set then Expires and Cache-Control headers will
723             also be set to expire at the given date as well.
724              
725             Pass in a list or hash reference for finer control.
726              
727             $c->cache_page(
728             last_modified => $last_modified,
729             cache_seconds => 24 * 60 * 60,
730             expires => 30,
731             );
732              
733             This allows separate control of the page cache and the header cache
734             values sent to the client.
735              
736             Possible options are:
737              
738             =over 4
739              
740             =item cache_seconds
741              
742             This is the number of seconds to keep the page in the page cache, which may be
743             different (normally longer) than the time that client caches may store the page.
744             This is the value set when only a single parameter is passed.
745              
746             =item expires
747              
748             This is the length of time in seconds that a client may cache the page
749             before revalidating (by asking the server if the document has changed).
750              
751             Unlike above, this is a fixed setting that each client will see. Regardless of
752             how much longer the page will be cached in the page cache the client still sees
753             the same expires time.
754              
755             Setting zero (0) for expires will result in the page being cached, but headers
756             will be sent telling the client to not cache the page. Allows caching expensive
757             content to generate, but any changes will be seen right away.
758              
759             =item last_modified
760              
761             Last modified time in epoch seconds. If not set will use either the
762             current Last-Modified header, or if not set, the current time.
763              
764             =back
765              
766             =head2 clear_cached_page
767              
768             To clear the cached pages for a URI, you may call clear_cached_page.
769              
770             $c->clear_cached_page( '/view/userlist' );
771             $c->clear_cached_page( '/view/.*' );
772             $c->clear_cached_page( '/view/.*\?.*\bparam=value\b' );
773              
774             This method takes an absolute path or regular expression.
775             Returns the number of matching entries found in the index.
776             A warning will be generated if the page index is disabled (see L</CONFIGURATION>).
777              
778             The argument is matched against all the keys in the page index.
779             The page index keys include the request path and query string, if any.
780              
781             Typically you'd call this from a different controller than the cached
782             controller. You may for example wish to build an admin page that lets you clear
783             page caches.
784              
785             =head1 INTERNAL EXTENDED METHODS
786              
787             =head2 dispatch
788              
789             C<dispatch> decides whether or not to serve a particular request from the cache.
790              
791             =head2 finalize
792              
793             C<finalize> caches the result of the current request if needed.
794              
795             =head2 setup
796              
797             C<setup> initializes all default values.
798              
799             =head1 I18N SUPPORT
800              
801             If your application uses L<Catalyst::Plugin::I18N> for localization, a
802             separate cache key will be used for each language a page is displayed in.
803              
804             =head1 KNOWN ISSUES
805              
806             The page index, used to support the L</clear_cached_page> method is unreliable
807             because it uses a read-modify-write approach which will loose data if more than
808             one process attempts to update the page index at the same time.
809              
810             It is not currently possible to cache pages served from the Static plugin. If
811             you're concerned enough about performance to use this plugin, you should be
812             serving static files directly from your web server anyway.
813              
814             Cache::FastMmap does not have the ability to specify different expiration times
815             for cached data. Therefore, if your MyApp->config->{cache}->{expires} value is
816             set to anything other than 0, you may experience problems with the
817             clear_cached_page method, because the cache index may be removed. For best
818             results, you may wish to use Cache::FileCache or Cache::Memcached as your cache
819             backend.
820              
821             =head1 SEE ALSO
822              
823             L<Catalyst>, L<Catalyst::Plugin::Cache::FastMmap>,
824             L<Catalyst::Plugin::Cache::FileCache>,
825             L<Catalyst::Plugin::Cache::Memcached>
826              
827             =head1 AUTHOR
828              
829             Andy Grundman, <andy@hybridized.org>
830              
831             =head1 THANKS
832              
833             Bill Moseley, <mods@hank.org>, for many patches and tests.
834              
835             Roberto Henríquez, <roberto@freekeylabs.com>, for i18n support.
836              
837             =head1 COPYRIGHT
838              
839             This program is free software, you can redistribute it and/or modify it under
840             the same terms as Perl itself.
841              
842             =cut