line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
2
|
|
|
2
|
|
153302
|
use strict; |
|
2
|
|
|
|
|
6
|
|
|
2
|
|
|
|
|
121
|
|
2
|
|
|
|
|
|
|
package Plack::Middleware::Cache::CHI; |
3
|
|
|
|
|
|
|
our $AUTHORITY = 'cpan:PNU'; |
4
|
|
|
|
|
|
|
# ABSTRACT: Caching Reverse Proxy for Plack |
5
|
|
|
|
|
|
|
|
6
|
2
|
|
|
2
|
|
12
|
use warnings; |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
74
|
|
7
|
2
|
|
|
2
|
|
664
|
use parent qw/Plack::Middleware/; |
|
2
|
|
|
|
|
311
|
|
|
2
|
|
|
|
|
16
|
|
8
|
|
|
|
|
|
|
|
9
|
2
|
|
|
2
|
|
16453
|
use Plack::Util::Accessor qw( chi rules scrub cachequeries trace ); |
|
2
|
|
|
|
|
6
|
|
|
2
|
|
|
|
|
15
|
|
10
|
2
|
|
|
2
|
|
1087
|
use Data::Dumper; |
|
2
|
|
|
|
|
6973
|
|
|
2
|
|
|
|
|
137
|
|
11
|
2
|
|
|
2
|
|
1692
|
use Plack::Request; |
|
2
|
|
|
|
|
2382933
|
|
|
2
|
|
|
|
|
63
|
|
12
|
2
|
|
|
2
|
|
1278
|
use Plack::Response; |
|
2
|
|
|
|
|
5817
|
|
|
2
|
|
|
|
|
54
|
|
13
|
2
|
|
|
2
|
|
814
|
use Time::HiRes qw( gettimeofday ); |
|
2
|
|
|
|
|
1443
|
|
|
2
|
|
|
|
|
16
|
|
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
our $VERSION = '0.102'; # VERSION |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
our @trace; |
18
|
|
|
|
|
|
|
our $timer_call; |
19
|
|
|
|
|
|
|
our $timer_pass; |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
sub _uinterval { |
22
|
8
|
|
|
8
|
|
25
|
my ( $t0, $t1 ) = ( @_, [gettimeofday] ); |
23
|
8
|
|
|
|
|
29
|
($t1->[0] - $t0->[0]) * 1_000_000 + $t1->[1] - $t0->[1]; |
24
|
|
|
|
|
|
|
} |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
sub call { |
27
|
5
|
|
|
5
|
1
|
43764
|
my ($self,$env) = @_; |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
## Pass-thru streaming responses |
30
|
5
|
50
|
|
|
|
21
|
return $self->app->($env) |
31
|
|
|
|
|
|
|
if ( ref $env eq 'CODE' ); |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
## Localize trace for this request |
34
|
5
|
|
|
|
|
12
|
local @trace = (); |
35
|
5
|
|
|
|
|
7
|
local $timer_pass = undef; |
36
|
5
|
|
|
|
|
24
|
local $timer_call = [gettimeofday]; |
37
|
|
|
|
|
|
|
|
38
|
5
|
|
|
|
|
32
|
my $req = Plack::Request->new($env); |
39
|
5
|
|
|
|
|
47
|
my $r = $self->handle($req); |
40
|
5
|
|
|
|
|
36
|
my $res = Plack::Response->new(@$r); |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
## Add trace and cache key to response headers |
43
|
5
|
|
|
|
|
428
|
$timer_call = _uinterval($timer_call); |
44
|
5
|
|
|
|
|
17
|
my $trace = join q{, }, @trace; |
45
|
5
|
|
|
|
|
15
|
my $key = $self->cachekey($req); |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
## The subrequest is timed separately |
48
|
5
|
100
|
|
|
|
29
|
if ( $timer_pass ) { |
49
|
3
|
|
|
|
|
4
|
$timer_call -= $timer_pass; |
50
|
3
|
|
|
|
|
9
|
$res->headers->push_header( |
51
|
|
|
|
|
|
|
'X-Plack-Cache-Time-Pass' => "$timer_pass us", |
52
|
|
|
|
|
|
|
); |
53
|
|
|
|
|
|
|
} |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
$res->headers->push_header( |
56
|
5
|
|
|
|
|
112
|
'X-Plack-Cache' => $trace, |
57
|
|
|
|
|
|
|
'X-Plack-Cache-Key' => $key, |
58
|
|
|
|
|
|
|
'X-Plack-Cache-Time' => "$timer_call us", |
59
|
|
|
|
|
|
|
); |
60
|
|
|
|
|
|
|
|
61
|
5
|
|
|
|
|
324
|
$res->finalize; |
62
|
|
|
|
|
|
|
} |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
sub handle { |
65
|
5
|
|
|
5
|
0
|
6
|
my ($self,$req) = @_; |
66
|
|
|
|
|
|
|
|
67
|
5
|
50
|
33
|
|
|
18
|
if ( $req->method eq 'GET' or $req->method eq 'HEAD' ) { |
68
|
5
|
50
|
|
|
|
54
|
if ( $req->headers->header('Expect') ) { |
69
|
0
|
|
|
|
|
0
|
push @trace, 'expect'; |
70
|
0
|
|
|
|
|
0
|
$self->pass($req); |
71
|
|
|
|
|
|
|
} else { |
72
|
5
|
|
|
|
|
638
|
$self->lookup($req); |
73
|
|
|
|
|
|
|
} |
74
|
|
|
|
|
|
|
} else { |
75
|
0
|
|
|
|
|
0
|
$self->invalidate($req); |
76
|
|
|
|
|
|
|
} |
77
|
|
|
|
|
|
|
} |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
sub pass { |
80
|
3
|
|
|
3
|
0
|
4
|
my ($self,$req) = @_; |
81
|
3
|
|
|
|
|
7
|
push @trace, 'pass'; |
82
|
3
|
|
|
|
|
14
|
$timer_pass = [gettimeofday]; |
83
|
|
|
|
|
|
|
|
84
|
3
|
|
|
|
|
10
|
my $res = $self->app->($req->env); |
85
|
|
|
|
|
|
|
|
86
|
3
|
|
|
|
|
691
|
$timer_pass = _uinterval($timer_pass); |
87
|
3
|
|
|
|
|
8
|
return $res; |
88
|
|
|
|
|
|
|
} |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
sub invalidate { |
91
|
0
|
|
|
0
|
0
|
0
|
my ($self,$req) = @_; |
92
|
0
|
|
|
|
|
0
|
push @trace, 'invalidate'; |
93
|
0
|
|
|
|
|
0
|
$self->chi->remove( $self->cachekey($req) ); |
94
|
0
|
|
|
|
|
0
|
$self->pass($req); |
95
|
|
|
|
|
|
|
} |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
sub match { |
98
|
5
|
|
|
5
|
0
|
7
|
my ($self, $req) = @_; |
99
|
|
|
|
|
|
|
|
100
|
5
|
|
|
|
|
6
|
my $path; |
101
|
|
|
|
|
|
|
my $opts; |
102
|
|
|
|
|
|
|
|
103
|
5
|
50
|
|
|
|
6
|
my @rules = @{ $self->rules || [] }; |
|
5
|
|
|
|
|
19
|
|
104
|
5
|
|
100
|
|
|
112
|
while ( @rules || return ) { |
105
|
10
|
|
|
|
|
16
|
my $match = shift @rules; |
106
|
10
|
|
|
|
|
15
|
$opts = shift @rules; |
107
|
10
|
|
|
|
|
27
|
$path = $req->path_info; |
108
|
10
|
50
|
|
|
|
110
|
last if 'CODE' eq ref $match ? $match->($path) : $path =~ $match; |
|
|
100
|
|
|
|
|
|
109
|
|
|
|
|
|
|
} |
110
|
4
|
|
|
|
|
8
|
return $opts; |
111
|
|
|
|
|
|
|
} |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
sub lookup { |
114
|
5
|
|
|
5
|
0
|
9
|
my ($self, $req) = @_; |
115
|
5
|
|
|
|
|
15
|
push @trace, 'lookup'; |
116
|
|
|
|
|
|
|
|
117
|
5
|
|
|
|
|
13
|
my $opts = $self->match($req); |
118
|
|
|
|
|
|
|
|
119
|
5
|
100
|
|
|
|
17
|
return $self->pass($req) |
120
|
|
|
|
|
|
|
if not defined $opts; |
121
|
|
|
|
|
|
|
|
122
|
4
|
50
|
33
|
|
|
16
|
return $self->invalidate($req) |
123
|
|
|
|
|
|
|
if ( $req->param and not $self->cachequeries ); |
124
|
|
|
|
|
|
|
|
125
|
4
|
|
|
|
|
708
|
my $entry = $self->fetch( $req ); |
126
|
4
|
|
|
|
|
508
|
my $res = [ 500, ['Content-Type','text/plain'], ['ISE'] ]; |
127
|
|
|
|
|
|
|
|
128
|
4
|
100
|
|
|
|
11
|
if ( defined $entry ) { |
129
|
2
|
|
|
|
|
4
|
push @trace, 'hit'; |
130
|
2
|
|
|
|
|
4
|
$res = $entry->[1]; |
131
|
2
|
50
|
|
|
|
7
|
return $self->invalidate($req) |
132
|
|
|
|
|
|
|
if not $self->valid($req,$res); |
133
|
|
|
|
|
|
|
} else { |
134
|
2
|
|
|
|
|
5
|
push @trace, 'miss'; |
135
|
2
|
|
|
|
|
6
|
$res = $self->delegate($req); |
136
|
2
|
50
|
|
|
|
9
|
$self->store($req,$res,$opts) |
137
|
|
|
|
|
|
|
if $self->valid($req,$res); |
138
|
|
|
|
|
|
|
} |
139
|
4
|
|
|
|
|
1269
|
return $res; |
140
|
|
|
|
|
|
|
} |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
sub valid { |
143
|
4
|
|
|
4
|
0
|
7
|
my ($self, $req, $res) = @_; |
144
|
|
|
|
|
|
|
|
145
|
4
|
|
|
|
|
7
|
my $res_status = $res->[0]; |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
return |
148
|
|
|
|
|
|
|
unless ( |
149
|
4
|
50
|
66
|
|
|
44
|
$res_status == 200 or |
|
|
|
66
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
150
|
|
|
|
|
|
|
$res_status == 203 or |
151
|
|
|
|
|
|
|
$res_status == 300 or |
152
|
|
|
|
|
|
|
$res_status == 301 or |
153
|
|
|
|
|
|
|
$res_status == 302 or |
154
|
|
|
|
|
|
|
$res_status == 404 or |
155
|
|
|
|
|
|
|
$res_status == 410 |
156
|
|
|
|
|
|
|
); |
157
|
|
|
|
|
|
|
|
158
|
4
|
|
|
|
|
17
|
return 1; |
159
|
|
|
|
|
|
|
} |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
sub cachekey { |
162
|
11
|
|
|
11
|
0
|
13
|
my ($self, $req) = @_; |
163
|
|
|
|
|
|
|
|
164
|
11
|
|
|
|
|
29
|
my $uri = $req->uri->canonical; |
165
|
|
|
|
|
|
|
|
166
|
11
|
50
|
|
|
|
2757
|
$uri->query(undef) |
167
|
|
|
|
|
|
|
if not $self->cachequeries; |
168
|
|
|
|
|
|
|
|
169
|
11
|
|
|
|
|
74
|
$uri->as_string; |
170
|
|
|
|
|
|
|
} |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
sub fetch { |
173
|
4
|
|
|
4
|
0
|
8
|
my ($self, $req) = @_; |
174
|
4
|
|
|
|
|
8
|
push @trace, 'fetch'; |
175
|
|
|
|
|
|
|
|
176
|
4
|
|
|
|
|
9
|
my $key = $self->cachekey($req); |
177
|
4
|
|
|
|
|
24
|
$self->chi->get( $key ); |
178
|
|
|
|
|
|
|
} |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
sub store { |
181
|
2
|
|
|
2
|
0
|
3
|
my ($self, $req, $res, $opts) = @_; |
182
|
2
|
|
|
|
|
5
|
push @trace, 'store'; |
183
|
|
|
|
|
|
|
|
184
|
2
|
|
|
|
|
5
|
my $key = $self->cachekey($req); |
185
|
2
|
|
|
|
|
12
|
$self->chi->set( $key, [$req->headers,$res], $opts ); |
186
|
|
|
|
|
|
|
} |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
sub delegate { |
189
|
2
|
|
|
2
|
0
|
4
|
my ($self, $req, $opts) = @_; |
190
|
2
|
|
|
|
|
3
|
push @trace, 'delegate'; |
191
|
|
|
|
|
|
|
|
192
|
2
|
|
|
|
|
7
|
my $res = $self->pass($req); |
193
|
2
|
50
|
|
|
|
4
|
foreach ( @{ $self->scrub || [] } ) { |
|
2
|
|
|
|
|
7
|
|
194
|
2
|
|
|
|
|
22
|
Plack::Util::header_remove( $res->[1], $_ ); |
195
|
|
|
|
|
|
|
} |
196
|
|
|
|
|
|
|
|
197
|
2
|
|
|
|
|
43
|
my $body; |
198
|
|
|
|
|
|
|
Plack::Util::foreach( $res->[2], sub { |
199
|
2
|
50
|
|
2
|
|
135
|
$body .= $_[0] if $_[0]; |
200
|
2
|
|
|
|
|
13
|
}); |
201
|
|
|
|
|
|
|
|
202
|
2
|
|
|
|
|
64
|
return [ $res->[0], $res->[1], [$body] ]; |
203
|
|
|
|
|
|
|
} |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
1; |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
__END__ |