File Coverage

blib/lib/Plack/Middleware/ETag.pm
Criterion Covered Total %
statement 55 56 98.2
branch 17 24 70.8
condition 7 14 50.0
subroutine 9 9 100.0
pod 1 1 100.0
total 89 104 85.5


line stmt bran cond sub pod time code
1             package Plack::Middleware::ETag;
2             $Plack::Middleware::ETag::VERSION = '0.05';
3             # ABSTRACT: Adds automatically an ETag header.
4              
5 3     3   23771 use strict;
  3         8  
  3         131  
6 3     3   17 use warnings;
  3         6  
  3         120  
7 3     3   253756 use Digest::SHA;
  3         5054  
  3         168  
8 3     3   815 use Plack::Util;
  3         11267  
  3         90  
9             use Plack::Util::Accessor
10 3     3   439 qw( file_etag cache_control check_last_modified_header);
  3         199  
  3         23  
11              
12 3     3   169 use parent qw/Plack::Middleware/;
  3         4  
  3         19  
13              
14             sub call {
15 8     8 1 66554 my $self = shift;
16 8         55 my $res = $self->app->(@_);
17              
18             $self->response_cb(
19             $res,
20             sub {
21 8     8   136 my $res = shift;
22 8         16 my $headers = $res->[1];
23 8 50       30 return if ( !defined $res->[2] );
24 8 100       26 return if ( Plack::Util::header_exists( $headers, 'ETag' ) );
25             return
26 7 100 66     116 if ( $self->check_last_modified_header()
27             && Plack::Util::header_exists( $headers, 'Last-Modified' ) );
28              
29 6         52 my $etag;
30              
31 6 100       24 if ( Plack::Util::is_real_fh( $res->[2] ) ) {
32              
33 1   50     74 my $file_attr = $self->file_etag || [qw/inode mtime size/];
34 1         26 my @stats = stat $res->[2];
35 1 50       13 if ( $stats[9] == time - 1 ) {
36             # if the file was modified less than one second before the request
37             # it may be modified in a near future, so we return a weak etag
38 0         0 $etag = "W/";
39             }
40 1 50       3 if ( grep {/inode/} @$file_attr ) {
  3         10  
41 1         6 $etag .= ( sprintf "%x", $stats[1] );
42             }
43 1 50       3 if ( grep {/mtime/} @$file_attr ) {
  3         8  
44 1 50 33     12 $etag .= "-" if ( $etag && $etag !~ /-$/ );
45 1         8 $etag .= ( sprintf "%x", $stats[9] );
46             }
47 1 50       3 if ( grep {/size/} @$file_attr ) {
  3         22  
48 1 50 33     10 $etag .= "-" if ( $etag && $etag !~ /-$/ );
49 1         6 $etag .= ( sprintf "%x", $stats[7] );
50             }
51             } else {
52 5         208 my $sha = Digest::SHA->new;
53 5         75 $sha->add( @{ $res->[2] } );
  5         34  
54 5         68 $etag = $sha->hexdigest;
55             }
56 6         27 Plack::Util::header_set( $headers, 'ETag', $etag );
57 6         151 $self->_set_cache_control($headers);
58 6         67 return;
59             }
60 8         254 );
61             }
62              
63             sub _set_cache_control {
64 6     6   13 my ( $self, $headers ) = @_;
65 6 100       30 return unless $self->cache_control;
66              
67 2 100 66     20 if ( ref $self->cache_control && ref $self->cache_control eq 'ARRAY' ) {
68             Plack::Util::header_set( $headers, 'Cache-Control',
69 1         19 join( ', ', @{ $self->cache_control } ) );
  1         5  
70             } else {
71 1         12 Plack::Util::header_set( $headers, 'Cache-Control',
72             'must-revalidate' );
73             }
74             }
75              
76             1;
77              
78             __END__