File Coverage

blib/lib/Nginx/FastCGI/Cache.pm
Criterion Covered Total %
statement 89 92 96.7
branch 26 38 68.4
condition 20 25 80.0
subroutine 13 13 100.0
pod 3 3 100.0
total 151 171 88.3


line stmt bran cond sub pod time code
1 1     1   75108 use 5.12.1;
  1         4  
  1         46  
2 1     1   6 use warnings;
  1         1  
  1         59  
3              
4             package Nginx::FastCGI::Cache;
5             $Nginx::FastCGI::Cache::VERSION = '0.010';
6 1     1   5 use Digest::MD5 'md5_hex';
  1         6  
  1         48  
7 1     1   897 use URI;
  1         5529  
  1         30  
8 1     1   7 use feature qw/switch say/;
  1         2  
  1         116  
9 1     1   5 use Carp;
  1         1  
  1         1916  
10              
11             # ABSTRACT: Conveniently manage the nginx fastcgi cache
12              
13             sub new {
14 12     12 1 5602 my ( $class, $args ) = @_;
15 12         21 my $self = {};
16              
17             # directory must exist
18 12 100       218 croak "location argument is mandatory $!" unless exists $args->{location};
19 11 100 66     530 croak "unable to read location directory $args->{location} $!"
20             unless -e $args->{location} && -x $args->{location};
21 10         28 $self->{location} = $args->{location};
22              
23             # Must be 1-3 levels and have a value of 1 or 2
24 10 100       26 if ( exists $args->{levels} ) {
25              
26 6 100 100     22 if ( ref $args->{levels} eq 'ARRAY'
  5   100     22  
      100        
27 4         19 and @{ $args->{levels} } > 0
28 3         7 and @{ $args->{levels} } < 4
29 8 50       39 and @{ $args->{levels} } == grep { $_ > 0 and $_ < 3 }
  3         6  
30             @{ $args->{levels} } )
31             {
32 2         5 $self->{levels} = $args->{levels};
33             }
34             else {
35 4         525 croak "Invalid levels argument received $!";
36             }
37             }
38             else {
39 4         10 $self->{levels} = [ 1, 2 ];
40             }
41              
42             # check only valid fastcgi cache key variables used
43 6 100       15 if ( exists $args->{fastcgi_cache_key} ) {
44              
45 3 50 100     11 if ( ref $args->{fastcgi_cache_key} eq 'ARRAY'
  2   66     9  
46 1         11 and @{ $args->{fastcgi_cache_key} } > 0
47 1         16 and @{ $args->{fastcgi_cache_key} } ==
48             grep /scheme|request_method|host|request_uri/,
49             @{ $args->{fastcgi_cache_key} } )
50             {
51 0         0 $self->{fastcgi_cache_key} = $args->{fastcgi_cache_key};
52             }
53             else {
54 3         295 croak "invalid fastcgi_cache_key received $!";
55             }
56             }
57             else {
58 3         10 $self->{fastcgi_cache_key} =
59             [qw/scheme request_method host request_uri/];
60             }
61              
62 3         21 return bless $self, $class;
63             }
64              
65             # builds plaintext key using the fastcgi_cache_key elements
66             sub _build_fastcgi_key {
67 4     4   11 my ( $self, $url, $method ) = @_;
68 4 50       12 croak "missing url argument $!" unless $url;
69              
70 4         27 my $uri = URI->new($url);
71 4         8835 my $fastcgi_key;
72              
73 4         8 foreach ( @{ $self->{fastcgi_cache_key} } ) {
  4         10  
74 16         333 given ($_) {
75 16         41 when ('scheme') {
76 4         22 $fastcgi_key .= $uri->scheme;
77             }
78 12         16 when ('request_method') {
79 4   100     26 $fastcgi_key .= $method || 'GET';
80             }
81 8         11 when ('host') {
82 4         15 $fastcgi_key .= $uri->host;
83             }
84 4         8 when ('request_uri') {
85 4   50     15 $fastcgi_key .= $uri->path || '/';
86             }
87             }
88             }
89 4         80 return $fastcgi_key;
90             }
91              
92             sub purge_file {
93 2     2 1 6 my ( $self, $url, $method ) = @_;
94 2 50       7 croak "missing url argument $!" unless $url;
95              
96 2         7 my $md5_key = md5_hex( $self->_build_fastcgi_key( $url, $method ) );
97 2         6 my $path = $self->_build_path($md5_key);
98 2         8 return $self->_purge_file($path);
99             }
100              
101             sub _purge_file {
102 4     4   8 my ( $self, $path_to_purge ) = @_;
103 4 50       10 croak "missing path argument $!" unless $path_to_purge;
104              
105 4 50 33     213 if ( -e $path_to_purge and -w $path_to_purge ) {
106 4 50       511 unlink $path_to_purge
107             or croak "unable to purge cache at $path_to_purge $!";
108 4         25 return 1;
109             }
110 0         0 croak "cache does not exist or is not writable at $path_to_purge";
111 0         0 return 0;
112             }
113              
114             sub purge_cache {
115 2     2 1 3 my $self = shift;
116 2         5 $self->{count_of_files_deleted} = 0;
117 2         5 $self->_purge_cache( $self->{location} );
118 2         10 return $self->{count_of_files_deleted};
119             }
120              
121             # purge entire cache directory
122             sub _purge_cache {
123 10     10   15 my ( $self, $dir ) = @_;
124 10 50       18 croak "missing directory argument" unless $dir;
125              
126 10 50       28 $dir .= '/' unless '/' eq substr $dir, -1;
127              
128 10 50       282 opendir( my $DH, $dir ) or croak "Failed to open $dir $!";
129              
130 10         159 while ( readdir $DH ) {
131 30         48 my $path = $dir . $_;
132 30 100       501 if ( -d $path ) {
    50          
133              
134             # recurse but ignore Unix symlinks . and ..
135 28 100       252 $self->_purge_cache($path) if $_ !~ /^\.{1,2}$/;
136             }
137             elsif ( -f $path ) {
138 2         8 $self->{count_of_files_deleted} += $self->_purge_file($path);
139             }
140             }
141             }
142              
143             # builds absolute path of file to purge
144             sub _build_path {
145 6     6   16 my ( $self, $md5_key ) = @_;
146 6 50       16 croak "missing md5 key argument $!" unless $md5_key;
147              
148 6         15 my $path = $self->{location};
149 6         9 my $md5_path_key = $md5_key; #the last few chars form the directory path
150 6         7 for ( @{ $self->{levels} } ) {
  6         17  
151 14         22 $path .= '/' . substr $md5_path_key, -$_;
152 14         31 $md5_path_key = substr $md5_path_key, 0, -$_;
153             }
154 6         31 return "$path/$md5_key";
155             }
156              
157             1;
158              
159             __END__