line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Plack::Middleware::ESI; |
2
|
1
|
|
|
1
|
|
1062
|
use strict; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
43
|
|
3
|
1
|
|
|
1
|
|
6
|
use warnings; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
63
|
|
4
|
|
|
|
|
|
|
our $VERSION = '0.1'; |
5
|
1
|
|
|
1
|
|
17
|
use parent qw(Plack::Middleware); |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
9
|
|
6
|
1
|
|
|
1
|
|
63
|
use Plack::Util; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
24
|
|
7
|
1
|
|
|
1
|
|
1274
|
use Plack::Request; |
|
1
|
|
|
|
|
98262
|
|
|
1
|
|
|
|
|
35
|
|
8
|
1
|
|
|
1
|
|
5456
|
use LWP::UserAgent; |
|
1
|
|
|
|
|
57332
|
|
|
1
|
|
|
|
|
39
|
|
9
|
1
|
|
|
1
|
|
11
|
use HTTP::Request; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
28
|
|
10
|
1
|
|
|
1
|
|
1162
|
use HTTP::Message::PSGI; |
|
1
|
|
|
|
|
5856
|
|
|
1
|
|
|
|
|
1225
|
|
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
sub call { |
13
|
1
|
|
|
1
|
1
|
32443
|
my ($self, $env) = @_; |
14
|
1
|
|
|
|
|
19
|
my $res = $self->app->($env); |
15
|
|
|
|
|
|
|
$self->response_cb($res, sub { |
16
|
1
|
|
|
1
|
|
20
|
my $res = shift; |
17
|
1
|
|
|
|
|
6
|
my $h = Plack::Util::headers($res->[1]); |
18
|
1
|
|
|
|
|
51
|
my $r = Plack::Request->new($env); |
19
|
1
|
|
|
|
|
17
|
my $ct = $h->get('Content-Type'); |
20
|
1
|
50
|
33
|
|
|
51
|
if ($ct =~ /^text\// || $ct =~ /^application\/xh?t?ml\b/) { #"{} |
21
|
|
|
|
|
|
|
return sub { |
22
|
6
|
|
|
|
|
62
|
my $chunk = shift; |
23
|
6
|
100
|
|
|
|
21
|
return unless defined $chunk; |
24
|
5
|
|
|
|
|
15
|
return $self->_process_esi($chunk, $r); |
25
|
1
|
|
|
|
|
19
|
}; |
26
|
|
|
|
|
|
|
} |
27
|
1
|
|
|
|
|
154
|
}); |
28
|
|
|
|
|
|
|
} |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
sub _process_esi { |
31
|
5
|
|
|
5
|
|
13
|
my ($self, $chunk, $r) = @_; |
32
|
5
|
|
|
|
|
23
|
my $chk_rx = qr{
|
33
|
5
|
50
|
|
|
|
42
|
return $chunk unless $chunk =~ $chk_rx; |
34
|
5
|
|
|
|
|
18
|
my $rem_rx = qr{.*?}; #"{} |
35
|
5
|
|
|
|
|
15
|
my $cmt_rx = qr{}; #"{} |
36
|
5
|
|
|
|
|
18
|
my $inc_rx = qr{(]+?src="([^"]+)"[^>]*/>)}; #"{} |
37
|
5
|
|
|
|
|
23
|
$chunk =~ s/$rem_rx//gs; |
38
|
5
|
|
|
|
|
20
|
$chunk =~ s/$cmt_rx/$1/gs; |
39
|
5
|
|
|
|
|
37
|
while ($chunk =~ $inc_rx) { |
40
|
4
|
|
|
|
|
13
|
my $esi = $1; |
41
|
4
|
|
|
|
|
8
|
my $url = $2; |
42
|
4
|
|
|
|
|
16
|
my $content = $self->_get_content($url, $r); |
43
|
4
|
|
|
|
|
149
|
$chunk =~ s/\Q$esi\E/$content/g; |
44
|
|
|
|
|
|
|
} |
45
|
5
|
|
|
|
|
43
|
return $chunk; |
46
|
|
|
|
|
|
|
} |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
sub _expand_url { |
49
|
3
|
|
|
3
|
|
6
|
my ($self, $url, $r) = @_; |
50
|
3
|
|
|
|
|
15
|
my $prefix = $r->scheme . '://localhost:' . $r->port; |
51
|
3
|
50
|
|
|
|
51
|
if ($url =~ m{^/}) { |
52
|
3
|
|
|
|
|
12
|
return $prefix . $url; |
53
|
|
|
|
|
|
|
} |
54
|
|
|
|
|
|
|
else { |
55
|
0
|
|
|
|
|
0
|
my $path = $r->path; |
56
|
0
|
0
|
|
|
|
0
|
$path .= '/' unless $path =~ /\/$/; |
57
|
0
|
|
|
|
|
0
|
return $prefix . $path . $url; |
58
|
|
|
|
|
|
|
} |
59
|
|
|
|
|
|
|
} |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
sub _get_content { |
62
|
4
|
|
|
4
|
|
6
|
my ($self, $url, $r) = @_; |
63
|
4
|
|
|
|
|
7
|
my $expanded_url = $url; |
64
|
4
|
100
|
|
|
|
16
|
unless ($url =~ m{^https?://}) { |
65
|
3
|
|
|
|
|
31
|
$expanded_url = $self->_expand_url($url, $r); |
66
|
|
|
|
|
|
|
} |
67
|
4
|
|
|
|
|
7
|
my $content = ''; |
68
|
4
|
|
|
|
|
8
|
eval { |
69
|
4
|
100
|
|
|
|
15
|
if ($url ne $expanded_url) { # internal request |
70
|
3
|
|
|
|
|
42
|
my $httpreq = HTTP::Request->new(GET=>$url); |
71
|
3
|
50
|
|
|
|
301
|
$httpreq->uri->scheme('http') unless defined $httpreq->uri->scheme; |
72
|
3
|
50
|
|
|
|
278
|
$httpreq->uri->host('localhost') unless defined $httpreq->uri->host; |
73
|
3
|
|
|
|
|
295
|
my $reqenv = $httpreq->to_psgi; |
74
|
3
|
|
|
|
|
2020
|
my $resp = HTTP::Response->from_psgi($self->app->($reqenv)); |
75
|
3
|
|
|
|
|
1437
|
$resp->request($httpreq); |
76
|
3
|
100
|
|
|
|
36
|
$content = $resp->content if $resp->code == 200; |
77
|
|
|
|
|
|
|
} |
78
|
4
|
100
|
|
|
|
100
|
unless ($content) { # external request (or retrying an apparently internal req) |
79
|
2
|
|
|
|
|
8
|
my $resp = $self->_ua->get($expanded_url); |
80
|
2
|
100
|
|
|
|
468898
|
if ($resp->code == 200) { |
|
|
50
|
|
|
|
|
|
81
|
1
|
|
|
|
|
27
|
$content = $resp->content; |
82
|
|
|
|
|
|
|
} |
83
|
|
|
|
|
|
|
elsif ($r->logger) { |
84
|
0
|
|
|
|
|
0
|
$r->logger->({level=>'warning', message=>"ESI: URL $expanded_url returned non-OK status code " . $resp->code}); |
85
|
|
|
|
|
|
|
} |
86
|
|
|
|
|
|
|
} |
87
|
|
|
|
|
|
|
}; |
88
|
4
|
50
|
|
|
|
161
|
if ($@) { |
89
|
0
|
0
|
|
|
|
0
|
if ($r->logger) { |
90
|
0
|
|
|
|
|
0
|
$r->logger->({level=>'warning', message=>"ESI: ERROR while fetching $url: $@"}); |
91
|
|
|
|
|
|
|
} |
92
|
|
|
|
|
|
|
} |
93
|
4
|
|
|
|
|
16
|
return $content; |
94
|
|
|
|
|
|
|
} |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
sub _ua { |
97
|
2
|
|
|
2
|
|
4
|
my $self = shift; |
98
|
2
|
100
|
|
|
|
14
|
return $self->{_ua} if $self->{_ua}; |
99
|
1
|
|
|
|
|
11
|
my $ua = LWP::UserAgent->new; |
100
|
1
|
|
|
|
|
17461
|
$ua->timeout(10); |
101
|
1
|
|
|
|
|
22
|
$self->{_ua} = $ua; |
102
|
1
|
|
|
|
|
7
|
return $ua; |
103
|
|
|
|
|
|
|
} |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
1; |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
__END__ |