line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
|
2
|
|
|
|
|
|
|
############################################################################ |
3
|
|
|
|
|
|
|
# Request |
4
|
|
|
|
|
|
|
############################################################################ |
5
|
|
|
|
|
|
|
|
6
|
1
|
|
|
1
|
|
7
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
30
|
|
7
|
1
|
|
|
1
|
|
5
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
36
|
|
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
package App::HTTP_Proxy_IMP::Request; |
10
|
1
|
|
|
1
|
|
5
|
use base 'Net::Inspect::Flow'; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
128
|
|
11
|
|
|
|
|
|
|
use fields ( |
12
|
1
|
|
|
|
|
5
|
'conn', # App::HTTP_Proxy_IMP::Connection object |
13
|
|
|
|
|
|
|
'meta', # meta data |
14
|
|
|
|
|
|
|
'me_proxy', # defined if I'm proxy, if true will be used for Via: |
15
|
|
|
|
|
|
|
'up_proxy', # address of upstream proxy if any |
16
|
|
|
|
|
|
|
'acct', # some accounting data |
17
|
|
|
|
|
|
|
'connected', # false|CONN_HOST|CONN_INTERNAL |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
'imp_analyzer', # App::HTTP_Proxy_IMP::IMP object |
20
|
|
|
|
|
|
|
'defer_rqhdr', # deferred request header (wait until body length known) |
21
|
|
|
|
|
|
|
'defer_rqbody', # deferred request body (wait until header can be sent) |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
'method', # request method |
24
|
|
|
|
|
|
|
'rqhost', # hostname from request |
25
|
|
|
|
|
|
|
'rq_version', # version of request |
26
|
|
|
|
|
|
|
'rp_encoder', # sub to encode response body (chunked) |
27
|
|
|
|
|
|
|
'keep_alive', # do we use keep_alive in response |
28
|
1
|
|
|
1
|
|
6
|
); |
|
1
|
|
|
|
|
2
|
|
29
|
|
|
|
|
|
|
|
30
|
1
|
|
|
1
|
|
145
|
use App::HTTP_Proxy_IMP::Debug qw(debug $DEBUG debug_context); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
121
|
|
31
|
1
|
|
|
1
|
|
7
|
use Scalar::Util 'weaken'; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
45
|
|
32
|
1
|
|
|
1
|
|
5
|
use Net::Inspect::Debug 'trace'; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
6
|
|
33
|
1
|
|
|
1
|
|
77
|
use Net::IMP qw(:DEFAULT :log); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
181
|
|
34
|
1
|
|
|
1
|
|
7
|
use Net::IMP::HTTP; # constants |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
87
|
|
35
|
1
|
|
|
1
|
|
519
|
use Sys::Hostname 'hostname'; |
|
1
|
|
|
|
|
1077
|
|
|
1
|
|
|
|
|
69
|
|
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
my $HOSTNAME = hostname(); |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
# connected to host or do we fake the response internally |
40
|
1
|
|
|
1
|
|
8
|
use constant CONN_HOST => 1; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
56
|
|
41
|
1
|
|
|
1
|
|
6
|
use constant CONN_INTERNAL => 2; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
4602
|
|
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
sub DESTROY { |
44
|
0
|
0
|
|
0
|
|
|
$DEBUG && debug("destroy request"); |
45
|
|
|
|
|
|
|
#Devel::TrackObjects->show_tracked; |
46
|
|
|
|
|
|
|
} |
47
|
|
|
|
|
|
|
sub new_request { |
48
|
0
|
|
|
0
|
0
|
|
my ($factory,$meta,$conn) = @_; |
49
|
0
|
|
|
|
|
|
my $self = $factory->new; |
50
|
0
|
0
|
|
|
|
|
$DEBUG && $conn->xdebug("new request $self"); |
51
|
|
|
|
|
|
|
|
52
|
0
|
|
|
|
|
|
$self->{meta} = $meta; |
53
|
0
|
|
|
|
|
|
weaken($self->{conn} = $conn); |
54
|
0
|
|
|
|
|
|
$self->{defer_rqhdr} = $self->{defer_rqbody} = ''; |
55
|
|
|
|
|
|
|
|
56
|
0
|
|
|
|
|
|
$self->{acct} = { %$meta, Id => $self->id }; |
57
|
0
|
0
|
|
|
|
|
if ( my $f = $conn->{imp_factory} ) { |
58
|
0
|
|
|
|
|
|
$self->{imp_analyzer} = $f->new_analyzer($self,$meta); |
59
|
|
|
|
|
|
|
} |
60
|
|
|
|
|
|
|
|
61
|
0
|
|
|
|
|
|
$self->{me_proxy} = $HOSTNAME; |
62
|
0
|
|
|
|
|
|
$self->{up_proxy} = $meta->{upstream}; |
63
|
|
|
|
|
|
|
|
64
|
0
|
|
|
|
|
|
return $self; |
65
|
|
|
|
|
|
|
} |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
sub xdebug { |
68
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
69
|
0
|
|
|
|
|
|
my $ctx = debug_context( id => $self->id ); |
70
|
0
|
|
|
|
|
|
goto &debug; |
71
|
|
|
|
|
|
|
} |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
sub id { |
74
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
75
|
0
|
0
|
|
|
|
|
$self->{conn} or return ''; |
76
|
|
|
|
|
|
|
return $$.'.'.$self->{conn}{connid}.'.'.$self->{meta}{reqid} |
77
|
0
|
|
|
|
|
|
} |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
sub fatal { |
80
|
0
|
|
|
0
|
0
|
|
my ($self,$reason) = @_; |
81
|
0
|
|
|
|
|
|
warn "[fatal] ".$self->id." $reason\n"; |
82
|
0
|
0
|
|
|
|
|
if ( my $conn = $self->{conn} ) { |
83
|
0
|
|
|
|
|
|
my $relay = $conn->{relay}; |
84
|
0
|
|
|
|
|
|
$relay->account('fatal'); |
85
|
0
|
|
|
|
|
|
$relay->close; |
86
|
|
|
|
|
|
|
} |
87
|
|
|
|
|
|
|
} |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
sub deny { |
90
|
0
|
|
|
0
|
0
|
|
my ($self,$reason) = @_; |
91
|
0
|
|
|
|
|
|
warn "[deny] ".$self->id." $reason\n"; |
92
|
0
|
0
|
0
|
|
|
|
if ( my $relay = $self->{conn} && $self->{conn}{relay} ) { |
93
|
0
|
|
|
|
|
|
$relay->account('deny', status => 'DENIED', reason => $reason ); |
94
|
|
|
|
|
|
|
$relay->forward(1,0,"HTTP/1.0 403 $reason\r\n\r\n") |
95
|
0
|
0
|
|
|
|
|
if ! $self->{acct}{code}; |
96
|
0
|
|
|
|
|
|
$relay->close; |
97
|
|
|
|
|
|
|
} |
98
|
|
|
|
|
|
|
} |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
sub xtrace { |
101
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
102
|
0
|
|
|
|
|
|
my $msg = shift; |
103
|
0
|
|
|
|
|
|
$msg = "$$.$self->{conn}{connid}.$self->{meta}{reqid} $msg"; |
104
|
0
|
|
|
|
|
|
unshift @_,$msg; |
105
|
0
|
|
|
|
|
|
goto &trace; |
106
|
|
|
|
|
|
|
} |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
############################################################################ |
110
|
|
|
|
|
|
|
# process HTTP request header |
111
|
|
|
|
|
|
|
# called from HTTP connection object |
112
|
|
|
|
|
|
|
# if IMP plugin is configured it will send the received header to the plugin |
113
|
|
|
|
|
|
|
# and continue from the IMP callback to _request_header_after_imp. |
114
|
|
|
|
|
|
|
# if no IMP is configured it will immediatly go there |
115
|
|
|
|
|
|
|
############################################################################ |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
my %default_port = ( http => 80, ftp => 21, https => 443 ); |
118
|
|
|
|
|
|
|
sub in_request_header { |
119
|
0
|
|
|
0
|
0
|
|
my ($self,$hdr,$time,$xhdr) = @_; |
120
|
0
|
0
|
|
|
|
|
my $conn = $self->{conn} or return; |
121
|
0
|
0
|
|
|
|
|
if ( $conn->{spool} ) { |
122
|
|
|
|
|
|
|
# we have an active request, spool this new one (pipelining) |
123
|
0
|
0
|
|
|
|
|
$DEBUG && $self->xdebug("spool new request"); |
124
|
0
|
|
|
|
|
|
push @{$conn->{spool}}, [ \&in_request_header, @_ ]; |
|
0
|
|
|
|
|
|
|
125
|
0
|
|
|
|
|
|
return; |
126
|
|
|
|
|
|
|
} |
127
|
|
|
|
|
|
|
|
128
|
0
|
0
|
|
|
|
|
my $relay = $conn->{relay} or return; |
129
|
0
|
|
|
|
|
|
$relay->acctinfo($self->{acct}); |
130
|
0
|
|
|
|
|
|
$conn->{spool} = []; # mark connection as processing request |
131
|
|
|
|
|
|
|
|
132
|
0
|
0
|
|
|
|
|
$DEBUG && $self->xdebug("incoming request header ".$hdr); |
133
|
|
|
|
|
|
|
|
134
|
0
|
|
|
|
|
|
$self->{method} = $xhdr->{method}; |
135
|
0
|
|
|
|
|
|
$self->{rq_version} = $xhdr->{version}; |
136
|
|
|
|
|
|
|
|
137
|
0
|
0
|
|
|
|
|
if ( my $imp = $self->{imp_analyzer} ) { |
138
|
|
|
|
|
|
|
# pass thru IMP |
139
|
0
|
|
0
|
|
|
|
my $debug = $DEBUG && debug_context( id => $self->id); |
140
|
0
|
|
|
|
|
|
$imp->request_header($hdr,$xhdr, |
141
|
|
|
|
|
|
|
\&_request_header_after_imp,$self); |
142
|
|
|
|
|
|
|
} else { |
143
|
|
|
|
|
|
|
# pass directly |
144
|
0
|
|
|
|
|
|
_request_header_after_imp($self,$hdr,$xhdr); |
145
|
|
|
|
|
|
|
} |
146
|
|
|
|
|
|
|
} |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
############################################################################ |
150
|
|
|
|
|
|
|
# process HTTP request header, which might have been modified by IMP |
151
|
|
|
|
|
|
|
# if not IMP is used this is called directly from in_request_header, else |
152
|
|
|
|
|
|
|
# via callback from IMP |
153
|
|
|
|
|
|
|
############################################################################ |
154
|
|
|
|
|
|
|
sub _request_header_after_imp { |
155
|
0
|
|
|
0
|
|
|
my ($self,$hdr,$xhdr) = @_; |
156
|
0
|
0
|
|
|
|
|
my $conn = $self->{conn} or return; |
157
|
0
|
0
|
|
|
|
|
my $relay = $conn->{relay} or return; |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
# with IMP method should not change |
160
|
0
|
|
|
|
|
|
my $met = $self->{method}; |
161
|
|
|
|
|
|
|
die "method should not change in IMP plugin" |
162
|
0
|
0
|
|
|
|
|
if $met ne $xhdr->{method}; |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
# work with original client version |
165
|
0
|
|
|
|
|
|
my $version = $self->{rq_version}; |
166
|
0
|
|
|
|
|
|
my $url = $xhdr->{url}; |
167
|
|
|
|
|
|
|
|
168
|
0
|
|
|
|
|
|
my $head = $xhdr->{fields}; |
169
|
0
|
0
|
|
|
|
|
$xhdr->{junk} and $relay->error( |
170
|
|
|
|
|
|
|
"Bad request header lines: $xhdr->{junk}"); |
171
|
|
|
|
|
|
|
|
172
|
0
|
|
|
|
|
|
my ($proto,$host,$port,$path); |
173
|
0
|
0
|
|
|
|
|
if ( $met eq 'CONNECT' ) { |
174
|
|
|
|
|
|
|
# only possible if we work as proxy |
175
|
|
|
|
|
|
|
return $self->fatal("connect request only allowed on proxy") |
176
|
0
|
0
|
|
|
|
|
if ! defined $self->{me_proxy}; |
177
|
|
|
|
|
|
|
return $self->fatal("connect request not allowed inside ssl tunnel") |
178
|
0
|
0
|
|
|
|
|
if $conn->{intunnel}; |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
# url should be host[:port] |
181
|
0
|
0
|
|
|
|
|
$url =~m{^(?:\[([\w\-.:]+)\]|([\w\-.]+))(?::(\d+))$} or |
182
|
|
|
|
|
|
|
return $self->fatal("invalid host[:port] in connect: $url"); |
183
|
0
|
|
|
|
|
|
$proto = 'https'; |
184
|
0
|
|
0
|
|
|
|
$host = lc($1||$2); |
185
|
0
|
|
0
|
|
|
|
$port = $3 || $default_port{$proto}; |
186
|
0
|
|
|
|
|
|
$path = ''; |
187
|
0
|
0
|
|
|
|
|
$url = ( $host =~m{:} ? "[$host]":$host ) . ":$port"; |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
} else { |
190
|
0
|
0
|
|
|
|
|
if ( $url =~m{^(\w+)://(?:\[([\w\-.:]+)\]|([\w\-.]+))(?::(\d+))?(.+)?} ) { |
191
|
|
|
|
|
|
|
# absolute url, valid for HTTP/1.1 or proxy requests |
192
|
0
|
|
|
|
|
|
$proto = lc($1); |
193
|
0
|
|
0
|
|
|
|
$host = lc($2||$3); |
194
|
0
|
|
|
|
|
|
$port = $4; |
195
|
0
|
|
0
|
|
|
|
$path = $5 // '/'; |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
} else { |
198
|
|
|
|
|
|
|
# relativ url, needs Host header if we want to get target |
199
|
|
|
|
|
|
|
# from request |
200
|
0
|
|
|
|
|
|
$proto = 'http'; |
201
|
0
|
|
|
|
|
|
$path = $url; |
202
|
0
|
0
|
|
|
|
|
if ( my $h = $head->{host} ) { |
203
|
0
|
0
|
|
|
|
|
$relay->error("Ignoring multiple host headers") if @$h>1; |
204
|
0
|
0
|
|
|
|
|
$h->[0] =~m{^(?:\[([\w\-.:]+)\]|([\w\-.]+))(?::(\d+))?$} or |
205
|
|
|
|
|
|
|
return $self->fatal("bad host line '$h->[0]'"); |
206
|
0
|
|
0
|
|
|
|
$host = $1||$2; |
207
|
0
|
|
|
|
|
|
$port = $3; |
208
|
|
|
|
|
|
|
} else { |
209
|
0
|
|
|
|
|
|
return $self->fatal("cannot determine target host"); |
210
|
|
|
|
|
|
|
} |
211
|
|
|
|
|
|
|
} |
212
|
|
|
|
|
|
|
|
213
|
0
|
|
0
|
|
|
|
$port //= $default_port{$proto}; |
214
|
0
|
0
|
0
|
|
|
|
return $self->fatal("invalid port $port") |
215
|
|
|
|
|
|
|
if ! $port or $port > 2**16-1; |
216
|
|
|
|
|
|
|
|
217
|
0
|
0
|
|
|
|
|
$path !~m{^/} and return $self->fatal("invalid path $path ($url)"); |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
# set/replace host header with target from URL and normalize URL |
220
|
0
|
|
|
|
|
|
$host =~s{\.\.+}{.}g; |
221
|
0
|
0
|
|
|
|
|
my $hp = $host =~m{:} ? "[$host]":$host; |
222
|
0
|
0
|
|
|
|
|
$hp .= ":$port" if $default_port{$proto} != $port; |
223
|
0
|
|
|
|
|
|
$head->{host} = [ $hp ]; |
224
|
0
|
|
|
|
|
|
$url = "$proto://$hp$path"; |
225
|
|
|
|
|
|
|
} |
226
|
|
|
|
|
|
|
|
227
|
0
|
|
|
|
|
|
$self->{acct}{url} = $url; |
228
|
0
|
0
|
|
|
|
|
$self->{acct}{url} =~s{://}{s://} if $conn->{intunnel}; |
229
|
0
|
|
|
|
|
|
$self->{acct}{method} = $met; |
230
|
0
|
|
|
|
|
|
$self->{acct}{reqid} = $self->{meta}{reqid}; |
231
|
0
|
|
|
|
|
|
$self->{rqhost} = $host; |
232
|
|
|
|
|
|
|
|
233
|
0
|
0
|
0
|
|
|
|
if ( $met eq 'CONNECT' and ! $self->{up_proxy} ) { |
234
|
|
|
|
|
|
|
# just skip all the header manipulation and normalization, we don't |
235
|
|
|
|
|
|
|
# need your stinkin header! |
236
|
0
|
|
|
|
|
|
$hdr = ''; |
237
|
0
|
|
|
|
|
|
goto SRVCON; |
238
|
|
|
|
|
|
|
} |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
# do we want/support persistence? |
241
|
0
|
|
|
|
|
|
my %conn = map { lc($_) => 1 } grep { m{\b(close|keep-alive)\b}i } ( |
|
0
|
|
|
|
|
|
|
242
|
0
|
0
|
|
|
|
|
@{ delete $head->{connection} || [] }, |
243
|
|
|
|
|
|
|
defined($self->{me_proxy}) |
244
|
0
|
0
|
|
|
|
|
? @{ delete $head->{'proxy-connection'} || [] } : () |
|
0
|
0
|
|
|
|
|
|
245
|
|
|
|
|
|
|
); |
246
|
0
|
0
|
|
|
|
|
if ( keys %conn > 1 ) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
247
|
|
|
|
|
|
|
# fall back to close |
248
|
0
|
|
|
|
|
|
$self->{keep_alive} = 0; |
249
|
0
|
|
|
|
|
|
$head->{connection} = [ 'close' ]; |
250
|
|
|
|
|
|
|
} elsif ( $conn{close} ) { |
251
|
0
|
|
|
|
|
|
$self->{keep_alive} = 0; |
252
|
|
|
|
|
|
|
# default in 1.1 is keep-alive |
253
|
0
|
0
|
|
|
|
|
$head->{connection} = [ 'close' ] if $version eq '1.1'; |
254
|
|
|
|
|
|
|
} elsif ( $conn{'keep-alive'} ) { |
255
|
0
|
|
|
|
|
|
$self->{keep_alive} = 1; |
256
|
|
|
|
|
|
|
# default in 1.0 is close |
257
|
0
|
0
|
|
|
|
|
$head->{connection} = [ 'keep-alive' ] if $version eq '1.0'; |
258
|
|
|
|
|
|
|
} else { |
259
|
|
|
|
|
|
|
# use default of version |
260
|
0
|
|
|
|
|
|
$self->{keep_alive} = $version eq '1.1'; |
261
|
|
|
|
|
|
|
} |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
# if we are a proxy set a via tag |
264
|
0
|
0
|
|
|
|
|
if ( my $via = $self->{me_proxy} ) { |
265
|
0
|
|
|
|
|
|
push @{$head->{via}}, "$version $via"; |
|
0
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
} |
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
# normalize header before forwarding it |
269
|
|
|
|
|
|
|
# sort keys, normalize case of keys etc |
270
|
0
|
0
|
|
|
|
|
$hdr = "$met ".( $self->{up_proxy} ? $url : $path )." HTTP/$version\r\n"; |
271
|
0
|
|
|
|
|
|
for my $k ( sort keys %$head) { |
272
|
0
|
|
|
|
|
|
$hdr .= "\u$k: $_\r\n" for @{$head->{$k}}; |
|
0
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
} |
274
|
0
|
|
|
|
|
|
$hdr .= "\r\n"; |
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
SRVCON: |
277
|
|
|
|
|
|
|
|
278
|
0
|
0
|
|
|
|
|
if ( $xhdr->{internal_url} ) { |
279
|
|
|
|
|
|
|
# the IMP plugin rewrote the url to internal://smthg, |
280
|
|
|
|
|
|
|
# meaning, that the plugin will provide us with the real response |
281
|
0
|
|
|
|
|
|
$self->{acct}{internal} = 1; |
282
|
0
|
|
|
|
|
|
$self->{connected} = CONN_INTERNAL; |
283
|
0
|
|
|
|
|
|
$self->{keep_alive} = 0; |
284
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
# accept more body data |
286
|
0
|
|
|
|
|
|
_call_spooled_this($conn); |
287
|
0
|
|
|
|
|
|
$relay->mask(0,r=>1); |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
# inject minimal response into Net::Inspect, which than can modify |
290
|
|
|
|
|
|
|
# it at will |
291
|
|
|
|
|
|
|
# IMP let us not change nothing (e.g. empty body) into something, so |
292
|
|
|
|
|
|
|
# we need to provide minimal content where content is expected |
293
|
0
|
0
|
|
|
|
|
$conn->in(1, |
294
|
|
|
|
|
|
|
$met eq 'HEAD' |
295
|
|
|
|
|
|
|
? "HTTP/$version 200 Ok\r\n\r\n" |
296
|
|
|
|
|
|
|
: "HTTP/$version 200 Ok\r\nContent-length: 1\r\n\r\n%", |
297
|
|
|
|
|
|
|
1, # eof |
298
|
|
|
|
|
|
|
0, # time |
299
|
|
|
|
|
|
|
); |
300
|
0
|
|
|
|
|
|
return; |
301
|
|
|
|
|
|
|
} |
302
|
|
|
|
|
|
|
|
303
|
0
|
0
|
|
|
|
|
if ( my $imp = $self->{imp_analyzer} ) { |
304
|
0
|
0
|
|
|
|
|
if ( defined( my $len = $xhdr->{content_length} )) { |
305
|
|
|
|
|
|
|
# length is given, fix header |
306
|
0
|
|
0
|
|
|
|
my $debug = $DEBUG && debug_context( id => $self->id); |
307
|
0
|
|
|
|
|
|
$imp->fixup_request_header(\$hdr, content => $len); |
308
|
|
|
|
|
|
|
} else { |
309
|
0
|
|
|
|
|
|
$self->{defer_rqhdr} = $hdr; |
310
|
|
|
|
|
|
|
} |
311
|
|
|
|
|
|
|
} |
312
|
|
|
|
|
|
|
|
313
|
0
|
0
|
|
|
|
|
if ( $conn->{intunnel} ) { |
314
|
0
|
|
|
|
|
|
_fwd_request_after_connect($self,$hdr); |
315
|
|
|
|
|
|
|
} else { |
316
|
|
|
|
|
|
|
$relay->connect( 1, |
317
|
0
|
0
|
|
|
|
|
@{ $self->{up_proxy} || [ $host,$port ] }, |
318
|
0
|
|
|
0
|
|
|
sub { _fwd_request_after_connect($self,$hdr) } |
319
|
0
|
|
|
|
|
|
); |
320
|
|
|
|
|
|
|
} |
321
|
|
|
|
|
|
|
} |
322
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
sub _fwd_request_after_connect { |
324
|
0
|
|
|
0
|
|
|
my ($self,$hdr) = @_; |
325
|
0
|
|
|
|
|
|
$self->{connected} = CONN_HOST; |
326
|
|
|
|
|
|
|
|
327
|
0
|
0
|
|
|
|
|
if ($hdr eq '') { |
328
|
|
|
|
|
|
|
# no header, e.g we have a CONNECT to a non-proxy |
329
|
|
|
|
|
|
|
# put a fake response into Net::Inspect to keep state |
330
|
0
|
|
|
|
|
|
$self->{conn}->in(1,"HTTP/1.0 200 Connection established\r\n\r\n"); |
331
|
0
|
|
|
|
|
|
return _call_spooled_this($self->{conn}); |
332
|
|
|
|
|
|
|
} |
333
|
|
|
|
|
|
|
|
334
|
0
|
0
|
|
|
|
|
if ( my $imp = $self->{imp_analyzer} ) { |
335
|
0
|
|
0
|
|
|
|
my $debug = $DEBUG && debug_context( id => $self->id); |
336
|
0
|
0
|
|
|
|
|
if ( $imp->fixup_request_header(\$hdr, defered => 0) ) { |
337
|
0
|
|
|
|
|
|
$self->{defer_rqhdr} = ''; |
338
|
|
|
|
|
|
|
} else { |
339
|
|
|
|
|
|
|
# keep deferring sending header, length not known |
340
|
0
|
|
|
|
|
|
_call_spooled_this($self->{conn}); # any body already ? |
341
|
0
|
|
|
|
|
|
return; |
342
|
|
|
|
|
|
|
} |
343
|
|
|
|
|
|
|
} |
344
|
|
|
|
|
|
|
|
345
|
0
|
0
|
|
|
|
|
my $relay = $self->{conn}{relay} or return; |
346
|
0
|
0
|
|
|
|
|
$relay->forward(0,1,$hdr) if $self->{connected} == CONN_HOST; |
347
|
0
|
|
|
|
|
|
_call_spooled_this($self->{conn}); # any body already ? |
348
|
|
|
|
|
|
|
} |
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
sub _call_spooled_this { |
351
|
0
|
|
|
0
|
|
|
my $conn = shift; |
352
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
# call spooled request_bodies, e.g. until we see a new request |
354
|
0
|
|
|
|
|
|
debug("check for spooled subs in this request"); |
355
|
0
|
0
|
|
|
|
|
my $spool = $conn->{spool} or return; |
356
|
0
|
|
|
|
|
|
$conn->{spool} = undef; |
357
|
0
|
|
0
|
|
|
|
while (@$spool && ! $conn->{spool} ) { |
358
|
0
|
|
|
|
|
|
my ($sub,@arg) = @{ $spool->[0] }; |
|
0
|
|
|
|
|
|
|
359
|
0
|
0
|
|
|
|
|
last if $sub == \&in_request_header; |
360
|
0
|
|
|
|
|
|
shift(@$spool); |
361
|
0
|
0
|
|
|
|
|
$DEBUG && debug("handle spooled event $sub"); |
362
|
0
|
|
|
|
|
|
$sub->(@arg); |
363
|
|
|
|
|
|
|
} |
364
|
0
|
0
|
|
|
|
|
push @{ $conn->{spool}}, @$spool if @$spool; # put back |
|
0
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
} |
366
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
sub _call_spooled_next { |
368
|
0
|
|
|
0
|
|
|
my $conn = shift; |
369
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
# skip until we have a next request, then continue |
371
|
0
|
|
|
|
|
|
debug("check for spooled requests, ignoring subs for this"); |
372
|
0
|
0
|
|
|
|
|
my $spool = $conn->{spool} or return; |
373
|
0
|
|
|
|
|
|
$conn->{spool} = undef; |
374
|
0
|
|
|
|
|
|
while (@$spool) { |
375
|
0
|
|
|
|
|
|
my ($sub,@arg) = @{ $spool->[0] }; |
|
0
|
|
|
|
|
|
|
376
|
0
|
0
|
|
|
|
|
last if $sub == \&in_request_header; |
377
|
0
|
0
|
|
|
|
|
$DEBUG && debug("skip spooled event $sub"); |
378
|
0
|
|
|
|
|
|
shift(@$spool); |
379
|
|
|
|
|
|
|
} |
380
|
0
|
|
0
|
|
|
|
while (@$spool && ! $conn->{spool} ) { |
381
|
0
|
|
|
|
|
|
my ($sub,@arg) = @{ $spool->[0] }; |
|
0
|
|
|
|
|
|
|
382
|
0
|
0
|
|
|
|
|
$DEBUG && debug("handle spooled event $sub"); |
383
|
0
|
|
|
|
|
|
$sub->(@arg); |
384
|
|
|
|
|
|
|
} |
385
|
0
|
0
|
|
|
|
|
push @{ $conn->{spool}}, @$spool if @$spool; # put back |
|
0
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
} |
387
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
############################################################################ |
389
|
|
|
|
|
|
|
# process request body data |
390
|
|
|
|
|
|
|
# if IMP, we might need to wait for a callback to decide what to do with |
391
|
|
|
|
|
|
|
# the data, otherwise the data are further send directly |
392
|
|
|
|
|
|
|
# if IMP might modify the data, we need to defer sending the header to get |
393
|
|
|
|
|
|
|
# the final content-length and fixup the header accordingly |
394
|
|
|
|
|
|
|
############################################################################ |
395
|
|
|
|
|
|
|
sub in_request_body { |
396
|
0
|
|
|
0
|
0
|
|
my ($self,$data,$eof) = @_; |
397
|
0
|
0
|
|
|
|
|
my $conn = $self->{conn} or return; |
398
|
0
|
0
|
|
|
|
|
my $relay = $conn->{relay} or return; |
399
|
0
|
0
|
|
|
|
|
if ( ! $self->{connected} ) { |
400
|
|
|
|
|
|
|
# not connected yet |
401
|
0
|
0
|
|
|
|
|
$DEBUG && $self->xdebug("spool request body data"); |
402
|
0
|
|
|
|
|
|
push @{$conn->{spool}}, [ \&in_request_body, @_ ]; |
|
0
|
|
|
|
|
|
|
403
|
0
|
|
|
|
|
|
return; |
404
|
|
|
|
|
|
|
} |
405
|
|
|
|
|
|
|
|
406
|
0
|
0
|
|
|
|
|
$DEBUG && $self->xdebug("got request body data len=%d eof=%d",length($data),$eof); |
407
|
0
|
|
|
|
|
|
my $imp = $self->{imp_analyzer}; |
408
|
0
|
0
|
|
|
|
|
if ( ! $imp ) { |
409
|
|
|
|
|
|
|
# fast path w/o imp |
410
|
|
|
|
|
|
|
$relay->forward(0,1,$data) if $data ne '' |
411
|
0
|
0
|
0
|
|
|
|
and $self->{connected} == CONN_HOST; |
412
|
0
|
|
|
|
|
|
return; |
413
|
|
|
|
|
|
|
} |
414
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
# feed data into IMP |
416
|
0
|
0
|
|
|
|
|
$DEBUG && $self->xdebug("fwd request body to IMP"); |
417
|
0
|
|
0
|
|
|
|
my $debug = $DEBUG && debug_context( id => $self->id); |
418
|
0
|
0
|
|
|
|
|
$imp->request_body($data,\&_request_body_after_imp,$self) if $data ne ''; |
419
|
0
|
0
|
|
|
|
|
$imp->request_body('',\&_request_body_after_imp,$self) if $eof; |
420
|
|
|
|
|
|
|
} |
421
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
############################################################################ |
423
|
|
|
|
|
|
|
# process request body data in case of IMP |
424
|
|
|
|
|
|
|
# called from IMP callback working on request body data |
425
|
|
|
|
|
|
|
############################################################################ |
426
|
|
|
|
|
|
|
sub _request_body_after_imp { |
427
|
0
|
|
|
0
|
|
|
my ($self,$data,$eof) = @_; |
428
|
0
|
0
|
|
|
|
|
my $conn = $self->{conn} or return; |
429
|
0
|
0
|
|
|
|
|
my $relay = $conn->{relay} or return; |
430
|
|
|
|
|
|
|
|
431
|
0
|
|
0
|
|
|
|
my $debug = $DEBUG && debug_context( id => $self->id); |
432
|
|
|
|
|
|
|
|
433
|
0
|
0
|
|
|
|
|
if ( $self->{defer_rqhdr} ne '') { |
434
|
0
|
|
|
|
|
|
$self->{defer_rqbody} .= $data; |
435
|
0
|
0
|
|
|
|
|
if ( not $self->{imp_analyzer}->fixup_request_header( |
436
|
|
|
|
|
|
|
\$self->{defer_rqhdr}, |
437
|
|
|
|
|
|
|
defered => length($self->{defer_rqbody}) |
438
|
|
|
|
|
|
|
)) { |
439
|
|
|
|
|
|
|
# body length still not known |
440
|
0
|
0
|
|
|
|
|
$DEBUG && debug("request body length still unknown"); |
441
|
0
|
|
|
|
|
|
$self->{defer_rqbody} .= $data; |
442
|
0
|
0
|
|
|
|
|
$eof or return; |
443
|
|
|
|
|
|
|
} |
444
|
|
|
|
|
|
|
|
445
|
|
|
|
|
|
|
$DEBUG && debug("forward %d bytes header + %d bytes body", |
446
|
|
|
|
|
|
|
length($self->{defer_rqhdr}), |
447
|
0
|
0
|
|
|
|
|
length($self->{defer_rqbody})); |
448
|
|
|
|
|
|
|
|
449
|
|
|
|
|
|
|
$relay->forward(0,1,$self->{defer_rqhdr}.$self->{defer_rqbody} ) |
450
|
0
|
0
|
|
|
|
|
if $self->{connected} == CONN_HOST; |
451
|
0
|
|
|
|
|
|
$self->{defer_rqhdr} = $self->{defer_rqbody} = ''; |
452
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
} else { |
454
|
0
|
0
|
|
|
|
|
$DEBUG && debug("forward %d bytes body",length($data)); |
455
|
0
|
0
|
|
|
|
|
$relay->forward( 0,1,$data ) if $self->{connected} == CONN_HOST; |
456
|
|
|
|
|
|
|
} |
457
|
|
|
|
|
|
|
} |
458
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
############################################################################ |
460
|
|
|
|
|
|
|
# process response header |
461
|
|
|
|
|
|
|
# jumps to _response_header_after_imp, directly or from IMP |
462
|
|
|
|
|
|
|
############################################################################ |
463
|
|
|
|
|
|
|
sub in_response_header { |
464
|
0
|
|
|
0
|
0
|
|
my ($self,$hdr,$time,$xhdr) = @_; |
465
|
0
|
0
|
|
|
|
|
return if $xhdr->{code} == 100; # ignore preliminary response |
466
|
|
|
|
|
|
|
|
467
|
0
|
0
|
|
|
|
|
if ( my $imp = $self->{imp_analyzer} ) { |
468
|
0
|
|
0
|
|
|
|
my $debug = $DEBUG && debug_context( id => $self->id); |
469
|
0
|
|
|
|
|
|
$imp->response_header($hdr,$xhdr, |
470
|
|
|
|
|
|
|
\&_response_header_after_imp,$self); |
471
|
|
|
|
|
|
|
} else { |
472
|
0
|
|
|
|
|
|
_response_header_after_imp($self,$hdr,$xhdr); |
473
|
|
|
|
|
|
|
} |
474
|
|
|
|
|
|
|
} |
475
|
|
|
|
|
|
|
|
476
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
############################################################################ |
478
|
|
|
|
|
|
|
# process response header, maybe it got manipulated by IMP |
479
|
|
|
|
|
|
|
############################################################################ |
480
|
|
|
|
|
|
|
sub _response_header_after_imp { |
481
|
0
|
|
|
0
|
|
|
my ($self,$hdr,$xhdr) = @_; |
482
|
0
|
0
|
|
|
|
|
my $relay = $self->{conn}{relay} or return; |
483
|
|
|
|
|
|
|
|
484
|
0
|
|
|
|
|
|
my $version = $xhdr->{version}; |
485
|
0
|
|
|
|
|
|
my $code = $self->{acct}{code} = $xhdr->{code}; |
486
|
0
|
|
|
|
|
|
my $clen = $xhdr->{content_length}; |
487
|
|
|
|
|
|
|
|
488
|
0
|
0
|
|
|
|
|
$DEBUG && $self->xdebug("input header: $hdr"); |
489
|
0
|
|
|
|
|
|
my $status_line = "HTTP/$version $code $xhdr->{reason}\r\n"; # normalized |
490
|
|
|
|
|
|
|
|
491
|
0
|
|
|
|
|
|
my $head = $xhdr->{fields}; |
492
|
|
|
|
|
|
|
#warn Dumper($head); use Data::Dumper; |
493
|
0
|
0
|
|
|
|
|
$xhdr->{junk} and $relay->error( |
494
|
|
|
|
|
|
|
"Bad response header lines: $xhdr->{junk}"); |
495
|
|
|
|
|
|
|
|
496
|
|
|
|
|
|
|
# check if the response is chunked and strip any transfer-encoding header |
497
|
|
|
|
|
|
|
# it will be added, when we know, how we talk to the client |
498
|
0
|
0
|
|
|
|
|
if ( $xhdr->{chunked} ) { |
499
|
0
|
|
|
|
|
|
delete $head->{'transfer-encoding'}; |
500
|
|
|
|
|
|
|
# if chunked is given content-length should be ignored |
501
|
|
|
|
|
|
|
# better strip, so that client will parse it correctly |
502
|
0
|
|
|
|
|
|
delete $head->{'content-length'}; |
503
|
|
|
|
|
|
|
} |
504
|
|
|
|
|
|
|
|
505
|
|
|
|
|
|
|
# if we don't know the content_length we try chunked, but only if client |
506
|
|
|
|
|
|
|
# and server used version 1.1. Otherwise we will close connection |
507
|
|
|
|
|
|
|
# at request end. |
508
|
|
|
|
|
|
|
# if only client supports chunking we better don't change response header |
509
|
|
|
|
|
|
|
# to 1.1, because in the 1.0 response might contain 1.0 specific headers |
510
|
|
|
|
|
|
|
# (Pragma...) which we don't know how to translate |
511
|
0
|
0
|
|
|
|
|
if ( defined $clen ) { |
|
|
0
|
|
|
|
|
|
512
|
0
|
0
|
|
|
|
|
$DEBUG && $self->xdebug("have content-length $clen"); |
513
|
|
|
|
|
|
|
} elsif ( $self->{method} eq 'CONNECT' ) { |
514
|
0
|
0
|
|
|
|
|
$DEBUG && $self->xdebug("have connect request"); |
515
|
|
|
|
|
|
|
} else { |
516
|
0
|
0
|
0
|
|
|
|
if ( $version eq '1.1' and $self->{rq_version} eq '1.1' ) { |
517
|
0
|
|
|
|
|
|
$head->{'transfer-encoding'} = [ 'chunked' ]; |
518
|
0
|
|
|
|
|
|
delete $head->{'content-length'}; |
519
|
0
|
0
|
|
|
|
|
$DEBUG && $self->xdebug("no clen known - use chunked encoding"); |
520
|
|
|
|
|
|
|
$self->{rp_encoder} = sub { |
521
|
0
|
|
|
0
|
|
|
my $data = shift; |
522
|
0
|
|
|
|
|
|
sprintf("%x\r\n%s\r\n", length($data),$data) |
523
|
0
|
|
|
|
|
|
}; |
524
|
|
|
|
|
|
|
} else { |
525
|
|
|
|
|
|
|
# disable persistance, we will end with EOF |
526
|
0
|
0
|
|
|
|
|
$DEBUG && $self->xdebug("no clen known - use eof to end response"); |
527
|
0
|
|
|
|
|
|
$self->{keep_alive} = 0; |
528
|
|
|
|
|
|
|
} |
529
|
|
|
|
|
|
|
} |
530
|
|
|
|
|
|
|
|
531
|
|
|
|
|
|
|
# set connection header if behavior is not default |
532
|
0
|
0
|
0
|
|
|
|
if ( $version eq '1.1' and ! $self->{keep_alive} ) { |
|
|
0
|
0
|
|
|
|
|
533
|
0
|
|
|
|
|
|
$head->{connection} = [ 'close' ]; |
534
|
|
|
|
|
|
|
} elsif ( $version eq '1.0' and $self->{keep_alive} ) { |
535
|
0
|
|
|
|
|
|
$head->{connection} = [ 'keep-alive' ]; |
536
|
|
|
|
|
|
|
} else { |
537
|
|
|
|
|
|
|
delete $head->{connection} |
538
|
0
|
|
|
|
|
|
} |
539
|
|
|
|
|
|
|
|
540
|
|
|
|
|
|
|
|
541
|
|
|
|
|
|
|
# create normalized header |
542
|
0
|
|
|
|
|
|
$hdr = $status_line; |
543
|
0
|
|
|
|
|
|
for my $k ( sort keys %$head) { |
544
|
0
|
|
|
|
|
|
$hdr .= "\u$k: $_\r\n" for @{$head->{$k}}; |
|
0
|
|
|
|
|
|
|
545
|
|
|
|
|
|
|
} |
546
|
0
|
|
|
|
|
|
$hdr .= "\r\n"; |
547
|
|
|
|
|
|
|
|
548
|
|
|
|
|
|
|
# forward header |
549
|
0
|
0
|
|
|
|
|
$DEBUG && $self->xdebug("output hdr: $hdr"); |
550
|
0
|
|
|
|
|
|
$relay->forward(1,0,$hdr); |
551
|
|
|
|
|
|
|
|
552
|
0
|
0
|
|
|
|
|
if ( $self->{method} eq 'CONNECT' ) { |
553
|
|
|
|
|
|
|
# upgrade server side and client side with SSL, but intercept traffic. |
554
|
|
|
|
|
|
|
# need to be called outside the current event handler, because $hdr |
555
|
|
|
|
|
|
|
# will only be removed from rbuf after the current handler is done |
556
|
|
|
|
|
|
|
App::HTTP_Proxy_IMP->once( sub { |
557
|
0
|
|
|
0
|
|
|
$relay->sslify(1,0,$self->{rqhost}); |
558
|
0
|
|
|
|
|
|
}); |
559
|
|
|
|
|
|
|
} |
560
|
|
|
|
|
|
|
} |
561
|
|
|
|
|
|
|
|
562
|
|
|
|
|
|
|
|
563
|
|
|
|
|
|
|
############################################################################ |
564
|
|
|
|
|
|
|
# handle response body data |
565
|
|
|
|
|
|
|
# will be forwarded to _response_body_after_imp with data or '' (eof) |
566
|
|
|
|
|
|
|
# maybe it will forwarded before to IMP analyzer |
567
|
|
|
|
|
|
|
############################################################################ |
568
|
|
|
|
|
|
|
sub in_response_body { |
569
|
0
|
|
|
0
|
0
|
|
my ($self,$data,$eof) = @_; |
570
|
|
|
|
|
|
|
|
571
|
0
|
|
|
|
|
|
$self->xdebug("len=".length($data)." eof=$eof"); |
572
|
0
|
0
|
|
|
|
|
if ( my $imp = $self->{imp_analyzer} ) { |
573
|
0
|
|
0
|
|
|
|
my $debug = $DEBUG && debug_context( id => $self->id); |
574
|
0
|
0
|
|
|
|
|
$data ne '' && $imp->response_body($data, |
575
|
|
|
|
|
|
|
\&_response_body_after_imp,$self); |
576
|
0
|
0
|
|
|
|
|
$eof && $imp->response_body('', |
577
|
|
|
|
|
|
|
\&_response_body_after_imp,$self); |
578
|
|
|
|
|
|
|
} else { |
579
|
0
|
|
|
|
|
|
_response_body_after_imp($self,$data,$eof); |
580
|
|
|
|
|
|
|
} |
581
|
|
|
|
|
|
|
} |
582
|
|
|
|
|
|
|
|
583
|
|
|
|
|
|
|
sub _response_body_after_imp { |
584
|
0
|
|
|
0
|
|
|
my ($self,$data,$eof) = @_; |
585
|
0
|
|
|
|
|
|
$self->xdebug("len=".length($data)." eof=$eof"); |
586
|
0
|
0
|
|
|
|
|
my $relay = $self->{conn}{relay} or return; |
587
|
|
|
|
|
|
|
|
588
|
|
|
|
|
|
|
# chunking, compression ... |
589
|
0
|
0
|
|
|
|
|
if ( my $encode = $self->{rp_encoder} ) { |
590
|
0
|
0
|
|
|
|
|
$data = $encode->($data) if $data ne ''; |
591
|
0
|
0
|
|
|
|
|
$data.= $encode->('') if $eof; |
592
|
|
|
|
|
|
|
} |
593
|
0
|
0
|
|
|
|
|
if ( $data ne '' ) { |
594
|
0
|
0
|
|
|
|
|
$DEBUG && $self->xdebug("send ".length($data)." bytes to c"); |
595
|
0
|
|
|
|
|
|
$relay->forward(1,0,$data); |
596
|
|
|
|
|
|
|
} |
597
|
|
|
|
|
|
|
|
598
|
0
|
0
|
|
|
|
|
if ($eof) { |
599
|
0
|
|
|
|
|
|
$relay->account('request'); |
600
|
0
|
0
|
|
|
|
|
if ( ! $self->{keep_alive} ) { |
601
|
|
|
|
|
|
|
# close connection |
602
|
0
|
0
|
|
|
|
|
$DEBUG && $self->xdebug("end of request: close"); |
603
|
0
|
|
|
|
|
|
return $relay->close; |
604
|
|
|
|
|
|
|
} |
605
|
|
|
|
|
|
|
|
606
|
|
|
|
|
|
|
# keep connection open |
607
|
|
|
|
|
|
|
# and continue with next request if we have one |
608
|
0
|
0
|
|
|
|
|
$DEBUG && $self->xdebug("end of request: keep-alive"); |
609
|
0
|
|
|
|
|
|
_call_spooled_next( $self->{conn} ); |
610
|
|
|
|
|
|
|
} |
611
|
|
|
|
|
|
|
} |
612
|
|
|
|
|
|
|
|
613
|
|
|
|
|
|
|
############################################################################ |
614
|
|
|
|
|
|
|
# Websockets, TLS upgrades etc |
615
|
|
|
|
|
|
|
# if not IMP the forwarding will be done inside this function, otherwise it |
616
|
|
|
|
|
|
|
# will be done in _in_data_imp, which gets called by IMP callback |
617
|
|
|
|
|
|
|
############################################################################ |
618
|
|
|
|
|
|
|
sub in_data { |
619
|
0
|
|
|
0
|
0
|
|
my ($self,$dir,$data,$eof) = @_; |
620
|
|
|
|
|
|
|
|
621
|
0
|
0
|
|
|
|
|
if ( my $imp = $self->{imp_analyzer} ) { |
622
|
0
|
|
0
|
|
|
|
my $debug = $DEBUG && debug_context( id => $self->id); |
623
|
0
|
0
|
|
|
|
|
$data ne '' and $imp->data($dir,$data,\&_in_data_imp,$self); |
624
|
0
|
0
|
|
|
|
|
$eof and $imp->data($dir,'',\&_in_data_imp,$self); |
625
|
|
|
|
|
|
|
} else { |
626
|
0
|
0
|
|
|
|
|
my $relay = $self->{conn}{relay} or return; |
627
|
0
|
0
|
|
|
|
|
$DEBUG && $self->xdebug("got %d bytes from %d, eof=%d",length($data),$dir,$eof); |
628
|
0
|
0
|
|
|
|
|
if ( $data ne '' ) { |
629
|
0
|
0
|
|
|
|
|
if ( $dir == 1 ) { |
630
|
0
|
|
|
|
|
|
$relay->forward(1,0,$data) |
631
|
|
|
|
|
|
|
} else { |
632
|
0
|
0
|
|
|
|
|
$relay->forward(0,1,$data) if $self->{connected} == CONN_HOST; |
633
|
|
|
|
|
|
|
} |
634
|
|
|
|
|
|
|
} |
635
|
0
|
0
|
|
|
|
|
$relay->account('upgrade') if $eof; |
636
|
|
|
|
|
|
|
} |
637
|
|
|
|
|
|
|
} |
638
|
|
|
|
|
|
|
sub _in_data_imp { |
639
|
0
|
|
|
0
|
|
|
my ($self,$dir,$data,$eof) = @_; |
640
|
0
|
0
|
|
|
|
|
my $relay = $self->{conn}{relay} or return; |
641
|
0
|
0
|
|
|
|
|
$DEBUG && $self->xdebug("imp got %d bytes from %d, eof=%d",length($data),$dir,$eof); |
642
|
0
|
0
|
|
|
|
|
if ( $data ne '' ) { |
643
|
0
|
0
|
|
|
|
|
if ( $dir == 1 ) { |
644
|
0
|
|
|
|
|
|
$relay->forward(1,0,$data) |
645
|
|
|
|
|
|
|
} else { |
646
|
0
|
0
|
|
|
|
|
$relay->forward(0,1,$data) if $self->{connected} == CONN_HOST; |
647
|
|
|
|
|
|
|
} |
648
|
|
|
|
|
|
|
} |
649
|
|
|
|
|
|
|
|
650
|
0
|
0
|
|
|
|
|
$relay->account('upgrade') if $eof; |
651
|
|
|
|
|
|
|
} |
652
|
|
|
|
|
|
|
|
653
|
|
|
|
|
|
|
############################################################################ |
654
|
|
|
|
|
|
|
# chunks and junk gets ignored |
655
|
|
|
|
|
|
|
# - we decide ourself, when we will forward data chunked and do the |
656
|
|
|
|
|
|
|
# chunking ourself |
657
|
|
|
|
|
|
|
# - junk data will not be forwarded |
658
|
|
|
|
|
|
|
############################################################################ |
659
|
|
|
|
|
|
|
|
660
|
|
|
|
0
|
0
|
|
sub in_chunk_header {} |
661
|
|
|
|
0
|
0
|
|
sub in_chunk_trailer {} |
662
|
|
|
|
0
|
0
|
|
sub in_junk {} |
663
|
|
|
|
|
|
|
|
664
|
|
|
|
|
|
|
|
665
|
|
|
|
|
|
|
1; |
666
|
|
|
|
|
|
|
|