File Coverage

blib/lib/Plack/Middleware/StaticShared.pm
Criterion Covered Total %
statement 27 73 36.9
branch 0 16 0.0
condition 0 6 0.0
subroutine 9 12 75.0
pod 2 3 66.6
total 38 110 34.5


line stmt bran cond sub pod time code
1             package Plack::Middleware::StaticShared;
2 1     1   12796 use strict;
  1         2  
  1         21  
3 1     1   3 use warnings;
  1         1  
  1         20  
4              
5 1     1   395 use parent qw(Plack::Middleware);
  1         213  
  1         3  
6 1     1   11117 use Plack::Request;
  1         41709  
  1         22  
7 1     1   411 use LWP::Simple qw($ua);
  1         27943  
  1         4  
8 1     1   514 use Digest::SHA1 qw(sha1_hex);
  1         447  
  1         42  
9 1     1   430 use DateTime::Format::HTTP;
  1         68953  
  1         26  
10 1     1   6 use DateTime;
  1         1  
  1         12  
11 1     1   403 use Path::Class;
  1         11105  
  1         401  
12              
13             our $VERSION = '0.06';
14              
15             __PACKAGE__->mk_accessors(qw(cache base binds verifier));
16              
17             sub new {
18 0     0 1   my ($class, @args) = @_;
19 0           my $self = $class->SUPER::new(@args);
20             }
21              
22             sub call {
23 0     0 1   my ($self, $env) = @_;
24 0           for my $static (@{ $self->binds }) {
  0            
25 0           my $prefix = $static->{prefix};
26             # Some browsers (eg. Firefox) always access if the url has query string,
27             # so use `:' for parameters
28 0 0         my ($version, $files) = ($env->{PATH_INFO} =~ /^$prefix:([^:\s]{1,32}):(.+)$/) or next;
29 0           my $req = Plack::Request->new($env);
30 0           my $res = $req->new_response;
31              
32 0 0 0       if ($self->verifier && !$self->verifier->(local $_ = $version, $prefix)) {
33 0           $res->code(400);
34 0           return $res->finalize;
35             }
36              
37 0           my $key = join(':', $version, $files);
38 0           my $etag = sha1_hex($key);
39              
40 0 0 0       if ($req->header('If-None-Match') || '' eq $etag) {
41             # Browser cache is avaialable but force reloaded by user.
42 0           $res->code(304);
43             } else {
44 0           my $content = eval {
45 0           my $ret = $self->cache->get($etag);
46 0 0         if (not defined $ret) {
47 0           $ret = $self->concat(split /,/, $files);
48 0 0         $ret = $static->{filter}->(local $_ = $ret) if $static->{filter};
49 0           $self->cache->set($etag => $ret);
50             }
51 0           $ret;
52             };
53              
54 0 0         if ($@) {
55 0           $res->code(503);
56 0           $res->header('Retry-After' => 10);
57 0           $res->content($@);
58             } else {
59             # Cache control:
60             # IE requires both Last-Modified and Etag to ignore checking updates.
61 0           $res->code(200);
62 0           $res->header("Cache-Control" => "public; max-age=315360000; s-maxage=315360000");
63 0           $res->header("Expires" => DateTime::Format::HTTP->format_datetime(DateTime->now->add(years => 10)));
64 0           $res->header("Last-Modified" => DateTime::Format::HTTP->format_datetime(DateTime->from_epoch(epoch => 0)));
65 0           $res->header("ETag" => $etag);
66 0           $res->content_type($static->{content_type});
67 0           $res->content($content);
68             }
69             }
70              
71 0           return $res->finalize;
72             }
73              
74 0           $self->app->($env);
75             }
76              
77             sub concat {
78 0     0 0   my ($self, @files) = @_;
79 0           my $base = dir($self->base);
80              
81 0           my $concat = '';
82 0           for my $f (@files) {
83 0           my $file = $base->file($f);
84 0 0         next unless -e $file;
85              
86 0           $file->resolve;
87 0 0         next unless $base->contains($file);
88              
89 0           $concat .= $file->slurp;
90             }
91              
92 0           return $concat;
93             }
94              
95             1;
96             __END__