line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Test::HTTP; |
2
|
4
|
|
|
4
|
|
65693
|
use warnings; |
|
4
|
|
|
|
|
7
|
|
|
4
|
|
|
|
|
118
|
|
3
|
4
|
|
|
4
|
|
22
|
use strict; |
|
4
|
|
|
|
|
7
|
|
|
4
|
|
|
|
|
221
|
|
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
our $VERSION = 0.18; |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
=head1 NAME |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
Test::HTTP - Test HTTP interactions. |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
=head1 SYNOPSIS |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
use Test::HTTP tests => 9; |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
{ |
16
|
|
|
|
|
|
|
my $uri = "$BASE/data/page/Foo_Bar_Baz"; |
17
|
|
|
|
|
|
|
my $type = 'text/x.waki-wiki'; |
18
|
|
|
|
|
|
|
my $test = Test::HTTP->new('HTTP page creation and deletion'); |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
$test->get($uri, [Accept => $type]); |
21
|
|
|
|
|
|
|
$test->status_code_is(404, "Page not yet there."); |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
$test->put($uri, ['Content-type' => $type], 'xyzzy'); |
24
|
|
|
|
|
|
|
$test->status_code_is(201, "PUT returns 201."); # Created |
25
|
|
|
|
|
|
|
$test->header_is( |
26
|
|
|
|
|
|
|
'Content-type' => $type, |
27
|
|
|
|
|
|
|
"Content-type matches on PUT."); |
28
|
|
|
|
|
|
|
$test->header_like( |
29
|
|
|
|
|
|
|
Location => qr{^$BASE/data/page/}, |
30
|
|
|
|
|
|
|
"Created page location makes sense."); |
31
|
|
|
|
|
|
|
$test->body_is('xyzzy'); |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
$test->get($uri, [Accept => $type]); |
34
|
|
|
|
|
|
|
$test->status_code_is(200, "Page is now there."); |
35
|
|
|
|
|
|
|
$test->header_is( |
36
|
|
|
|
|
|
|
'Content-type' => $type, |
37
|
|
|
|
|
|
|
"Content-type matches on GET."); |
38
|
|
|
|
|
|
|
$test->body_is('xyzzy'); |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
$test->delete($uri); |
41
|
|
|
|
|
|
|
$test->status_code_is(204, "DELETE returns 204."); # No content |
42
|
|
|
|
|
|
|
} |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
=head1 DESCRIPTION |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
L is designed to make it easier to write tests which are mainly |
47
|
|
|
|
|
|
|
about HTTP-level things, such as REST-type services. |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
Each C object can contain state about a current request and its |
50
|
|
|
|
|
|
|
response. This allows convenient shorthands for sending requests, checking |
51
|
|
|
|
|
|
|
status codes, headers, and message bodies. |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
=cut |
54
|
|
|
|
|
|
|
|
55
|
4
|
|
|
4
|
|
20
|
use base 'Exporter'; |
|
4
|
|
|
|
|
10
|
|
|
4
|
|
|
|
|
454
|
|
56
|
4
|
|
|
4
|
|
20
|
use Carp 'croak'; |
|
4
|
|
|
|
|
5
|
|
|
4
|
|
|
|
|
279
|
|
57
|
4
|
|
|
4
|
|
3261
|
use Class::Field 'field'; |
|
4
|
|
|
|
|
104186
|
|
|
4
|
|
|
|
|
316
|
|
58
|
4
|
|
|
4
|
|
42
|
use Encode qw(encode_utf8 is_utf8); |
|
4
|
|
|
|
|
7
|
|
|
4
|
|
|
|
|
319
|
|
59
|
4
|
|
|
4
|
|
4737
|
use Filter::Util::Call; |
|
4
|
|
|
|
|
4759
|
|
|
4
|
|
|
|
|
301
|
|
60
|
4
|
|
|
4
|
|
3580
|
use HTTP::Request; |
|
4
|
|
|
|
|
196059
|
|
|
4
|
|
|
|
|
165
|
|
61
|
4
|
|
|
4
|
|
3953
|
use Test::Builder; |
|
4
|
|
|
|
|
42198
|
|
|
4
|
|
|
|
|
9037
|
|
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
our $Builder = Test::Builder->new; |
64
|
|
|
|
|
|
|
our $BasicPassword; |
65
|
|
|
|
|
|
|
our $BasicUsername; |
66
|
|
|
|
|
|
|
our $UaClass = 'LWP::UserAgent'; |
67
|
|
|
|
|
|
|
our $TODO = undef; |
68
|
|
|
|
|
|
|
our @EXPORT = qw($TODO); |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
sub _partition(&@); |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
sub import { |
73
|
4
|
|
|
4
|
|
41
|
my $class = shift; |
74
|
|
|
|
|
|
|
|
75
|
4
|
|
|
|
|
36
|
$Builder->exported_to(scalar caller); |
76
|
|
|
|
|
|
|
|
77
|
4
|
|
|
8
|
|
56
|
my ( $syntax, $nargs ) = _partition { $_ eq '-syntax' } @_; |
|
8
|
|
|
|
|
43
|
|
78
|
4
|
|
|
|
|
34
|
$Builder->plan(@$nargs); |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
# WARNING: This only exports the stuff in @EXPORT. |
81
|
4
|
|
|
|
|
1389
|
$class->export_to_level(1, $class); |
82
|
|
|
|
|
|
|
|
83
|
4
|
100
|
|
|
|
2758
|
if (@$syntax) { |
84
|
2
|
|
|
|
|
7
|
@_ = (); |
85
|
2
|
|
|
|
|
1493
|
require Test::HTTP::Syntax; |
86
|
2
|
|
|
|
|
20
|
goto &Test::HTTP::Syntax::import; |
87
|
|
|
|
|
|
|
} |
88
|
|
|
|
|
|
|
} |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
=head1 CONSTRUCTOR |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
=head2 Test::HTTP->new($name); |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
C<$name> is a name for the test, used to help write test descriptions when you |
95
|
|
|
|
|
|
|
don't specify them. |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
=cut |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
sub new { |
100
|
6
|
|
|
6
|
1
|
3824
|
my $class = shift; |
101
|
|
|
|
|
|
|
|
102
|
6
|
|
|
|
|
25
|
my $new_object = bless {}, $class; |
103
|
6
|
|
|
|
|
40
|
$new_object->_initiliaze(@_); |
104
|
6
|
|
|
|
|
117
|
return $new_object; |
105
|
|
|
|
|
|
|
} |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
sub _initiliaze { |
108
|
6
|
|
|
6
|
|
18
|
my ( $self, $name ) = @_; |
109
|
|
|
|
|
|
|
|
110
|
6
|
|
|
|
|
583
|
$self->name($name); |
111
|
|
|
|
|
|
|
} |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
# Given a predicate and a list, return two listrefs. The elements in the |
114
|
|
|
|
|
|
|
# first listref satisfy the predicate, and those in the second do not. The |
115
|
|
|
|
|
|
|
# predicate acts on a localized value of $_ rather than any arguments to it. |
116
|
|
|
|
|
|
|
sub _partition(&@) { |
117
|
4
|
|
|
4
|
|
14
|
my ( $pred, @l ) = @_; |
118
|
4
|
|
|
|
|
12
|
my ( $tl, $fl ) = ( [], [] ); |
119
|
|
|
|
|
|
|
|
120
|
4
|
100
|
|
|
|
18
|
push @{ &$pred ? $tl : $fl }, $_ for @l; |
|
8
|
|
|
|
|
16
|
|
121
|
|
|
|
|
|
|
|
122
|
4
|
|
|
|
|
13
|
return ( $tl, $fl ); |
123
|
|
|
|
|
|
|
} |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
=head1 OBJECT FIELDS |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
You can get/set any of these by saying C<< $test->foo >> or |
128
|
|
|
|
|
|
|
C<< $test->foo(5) >>, respectively. |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
=head2 $test->name |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
The name for the test. |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
=head2 $test->request |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
The current L being constructed or most recently sent. |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
=head2 $test->response |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
The most recently received L. |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
=head2 $test->ua |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
The User Agent object (usually an L). |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
=head2 $test->username |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
=head2 $test->password |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
A username and password to be used for HTTP basic auth. Default to the values |
151
|
|
|
|
|
|
|
of C<$Test::HTTP::BasicUsername> and C<$Test::HTTP::BasicPassword>, |
152
|
|
|
|
|
|
|
respectively. If both are undef, then authentication is not attempted. |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
=cut |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
field 'name'; |
157
|
|
|
|
|
|
|
field 'request'; |
158
|
|
|
|
|
|
|
field 'response'; |
159
|
|
|
|
|
|
|
field 'ua', -init => '$self->_ua_class->new'; |
160
|
|
|
|
|
|
|
field 'username', -init => '$Test::HTTP::BasicUsername'; |
161
|
|
|
|
|
|
|
field 'password', -init => '$Test::HTTP::BasicPassword'; |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
=head1 REQUEST METHODS |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
=head2 head, get, put, post, and delete |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
Any of these methods may be used to do perform the expected HTTP request. |
168
|
|
|
|
|
|
|
They are all equivalent to |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
$obj->run_request(METHOD => ARGS); |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
=cut |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
sub head { |
175
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
176
|
0
|
|
|
|
|
0
|
$self->run_request(HEAD => @_); |
177
|
|
|
|
|
|
|
} |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
sub get { |
180
|
3
|
|
|
3
|
1
|
20
|
my $self = shift; |
181
|
3
|
|
|
|
|
12
|
$self->run_request(GET => @_); |
182
|
|
|
|
|
|
|
} |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
sub put { |
185
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
186
|
0
|
|
|
|
|
0
|
$self->run_request(PUT => @_); |
187
|
|
|
|
|
|
|
} |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
sub post { |
190
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
191
|
0
|
|
|
|
|
0
|
$self->run_request(POST => @_); |
192
|
|
|
|
|
|
|
} |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
sub delete { |
195
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
196
|
0
|
|
|
|
|
0
|
$self->run_request(DELETE => @_); |
197
|
|
|
|
|
|
|
} |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
=head2 $test->run_request([METHOD => $uri [, $headers [, $content]]]); |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
If there are any arguments, they are all passed to the L |
202
|
|
|
|
|
|
|
constructor to create a new C<< $test->request >>. |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
C<< $test->request >> is then executed, and C<< $test->response >> will hold |
205
|
|
|
|
|
|
|
the resulting L. |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
=cut |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
sub run_request { |
210
|
6
|
|
|
6
|
1
|
49
|
my ( $self, @request_args ) = @_; |
211
|
6
|
100
|
|
|
|
33
|
$self->new_request(@request_args) if @request_args; |
212
|
6
|
50
|
|
|
|
168
|
if ($self->request->method ne 'GET') { |
213
|
0
|
0
|
|
|
|
0
|
if (is_utf8($self->request->content)) { |
214
|
0
|
|
|
|
|
0
|
my $content = $self->request->content; |
215
|
0
|
|
|
|
|
0
|
$content = encode_utf8($content); |
216
|
0
|
|
|
|
|
0
|
$self->request->content($content); |
217
|
|
|
|
|
|
|
} |
218
|
|
|
|
|
|
|
} |
219
|
|
|
|
|
|
|
|
220
|
6
|
|
|
|
|
253
|
$self->response( $self->ua->simple_request( $self->request ) ); |
221
|
6
|
50
|
|
|
|
3156484
|
croak( $self->request->uri . ': ' . $self->response->status_line ) |
222
|
|
|
|
|
|
|
if $self->response->status_line =~ /500 Can't connect to /; |
223
|
6
|
|
|
|
|
356
|
return $self->response; |
224
|
|
|
|
|
|
|
} |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
=head2 $test->new_request(METHOD => $uri [, $headers [, $content]]); |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
Set up a new request object as in run_request, but do not execute it yet. |
229
|
|
|
|
|
|
|
This is handy if you want to call assorted methods on the request to tweak it |
230
|
|
|
|
|
|
|
before running it with C<< $test->run_request >>. |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
=cut |
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
sub new_request { |
235
|
6
|
|
|
6
|
1
|
30
|
my ( $self, $method, $uri, @args ) = @_; |
236
|
6
|
|
|
|
|
57
|
$self->request( |
237
|
|
|
|
|
|
|
HTTP::Request->new( $method => $uri, @args ) ); |
238
|
6
|
50
|
33
|
|
|
30838
|
$self->request->authorization_basic($self->username, $self->password) |
239
|
|
|
|
|
|
|
if (defined $self->username) || (defined $self->password); |
240
|
6
|
|
|
|
|
574
|
return $self->request; |
241
|
|
|
|
|
|
|
} |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
=head1 TEST METHODS |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
=head2 $test->status_code_is($code [, $description]); |
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
Compares the last response status code with the given code using |
248
|
|
|
|
|
|
|
Cis>. |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
=cut |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
sub status_code_is { |
253
|
6
|
|
|
6
|
1
|
104
|
local $Test::Builder::Level = $Test::Builder::Level + 1; |
254
|
6
|
|
|
|
|
19
|
my ( $self, $expected_code, $description ) = @_; |
255
|
|
|
|
|
|
|
|
256
|
6
|
|
33
|
|
|
176
|
$description ||= $self->name . " status is $expected_code."; |
257
|
|
|
|
|
|
|
|
258
|
6
|
|
|
|
|
395
|
$Builder->is_eq( $self->response->code, $expected_code, $description ); |
259
|
|
|
|
|
|
|
} |
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
=head2 $test->header_is($header_name, $value [, $description]); |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
Compares the response header C<$header_name> with the value C<$value> using |
264
|
|
|
|
|
|
|
Cis>. |
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
=cut |
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
sub header_is { |
269
|
0
|
|
|
0
|
1
|
0
|
local $Test::Builder::Level = $Test::Builder::Level + 1; |
270
|
0
|
|
|
|
|
0
|
my ( $self, $header_name, $expected_value, $description ) = @_; |
271
|
|
|
|
|
|
|
|
272
|
0
|
|
0
|
|
|
0
|
$description ||= $self->name . " $header_name matches '$expected_value'."; |
273
|
|
|
|
|
|
|
|
274
|
0
|
|
|
|
|
0
|
$Builder->is_eq( |
275
|
|
|
|
|
|
|
scalar $self->response->header($header_name), |
276
|
|
|
|
|
|
|
$expected_value, |
277
|
|
|
|
|
|
|
$description |
278
|
|
|
|
|
|
|
); |
279
|
|
|
|
|
|
|
} |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
=head2 $test->header_like($header_name, $regex, [, $description]); |
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
Compares the response header C<$header_name> with the regex C<$regex> using |
284
|
|
|
|
|
|
|
Clike>. |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
=cut |
287
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
sub header_like { |
289
|
1
|
|
|
1
|
1
|
894
|
local $Test::Builder::Level = $Test::Builder::Level + 1; |
290
|
1
|
|
|
|
|
3
|
my ( $self, $header_name, $regex, $description ) = @_; |
291
|
|
|
|
|
|
|
|
292
|
1
|
|
33
|
|
|
37
|
$description ||= $self->name . " $header_name matches $regex."; |
293
|
|
|
|
|
|
|
|
294
|
1
|
|
|
|
|
45
|
$Builder->like( |
295
|
|
|
|
|
|
|
scalar $self->response->header($header_name), |
296
|
|
|
|
|
|
|
$regex, |
297
|
|
|
|
|
|
|
$description |
298
|
|
|
|
|
|
|
); |
299
|
|
|
|
|
|
|
} |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
=head2 $test->body_is($expected_body [, $description]); |
302
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
Verifies that the HTTP response body is exactly C<$expected_body>. |
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
=cut |
306
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
sub body_is { |
308
|
0
|
|
|
0
|
1
|
0
|
local $Test::Builder::Level = $Test::Builder::Level + 1; |
309
|
0
|
|
|
|
|
0
|
my ( $self, $expected_body, $description ) = @_; |
310
|
|
|
|
|
|
|
|
311
|
0
|
|
0
|
|
|
0
|
$description ||= $self->name . " body is '$expected_body'."; |
312
|
|
|
|
|
|
|
|
313
|
0
|
|
|
|
|
0
|
$Builder->is_eq( $self->_decoded_content, $expected_body, $description ); |
314
|
|
|
|
|
|
|
} |
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
=head2 $test->body_like($regex [, $description]); |
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
Compares the HTTP response body with C<$regex>. |
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
=cut |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
sub body_like { |
323
|
0
|
|
|
0
|
1
|
0
|
local $Test::Builder::Level = $Test::Builder::Level + 1; |
324
|
0
|
|
|
|
|
0
|
my ( $self, $regex, $description ) = @_; |
325
|
|
|
|
|
|
|
|
326
|
0
|
|
0
|
|
|
0
|
$description ||= $self->name . " body matches $regex."; |
327
|
|
|
|
|
|
|
|
328
|
0
|
|
|
|
|
0
|
$Builder->like($self->_decoded_content, $regex, $description); |
329
|
|
|
|
|
|
|
} |
330
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
=head1 USER AGENT GENERATION |
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
The user agent (UA) is created when the C object is constructed. |
334
|
|
|
|
|
|
|
By default, L is used to create this object, but it may be |
335
|
|
|
|
|
|
|
handy to test your HTTP handlers without going through an actual HTTP server |
336
|
|
|
|
|
|
|
(for speed, e.g.), so there are a couple of ways to override the chosen class. |
337
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
If the environment variable C is set, this value is used |
339
|
|
|
|
|
|
|
instead. If not, then the current value of C<$Test::HTTP::UaClass> |
340
|
|
|
|
|
|
|
(C by default) is used. Thus, the incantation below may prove |
341
|
|
|
|
|
|
|
useful. |
342
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
{ |
344
|
|
|
|
|
|
|
local $Test::HTTP::UaClass = 'MyCorp::REST::FakeUserAgent'; |
345
|
|
|
|
|
|
|
my $test = Test::HTTP->new("widget HTTP access"); |
346
|
|
|
|
|
|
|
# ... |
347
|
|
|
|
|
|
|
} |
348
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
=cut |
350
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
sub _ua_class { |
352
|
6
|
|
|
6
|
|
73
|
my $self = shift; |
353
|
|
|
|
|
|
|
|
354
|
6
|
50
|
|
|
|
261
|
my $class = exists $ENV{TEST_HTTP_UA_CLASS} |
355
|
|
|
|
|
|
|
? $ENV{TEST_HTTP_UA_CLASS} |
356
|
|
|
|
|
|
|
: $UaClass; |
357
|
|
|
|
|
|
|
|
358
|
6
|
|
|
|
|
394
|
eval "require $class"; |
359
|
6
|
50
|
|
|
|
113155
|
die if $@; |
360
|
6
|
|
|
|
|
50
|
$class->import; |
361
|
|
|
|
|
|
|
|
362
|
6
|
|
|
|
|
51
|
return $class; |
363
|
|
|
|
|
|
|
} |
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
sub _decoded_content { |
366
|
0
|
|
|
0
|
|
|
my $self = shift; |
367
|
0
|
|
|
|
|
|
my $content = $self->response->decoded_content; |
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
# Work around a bug in HTTP::Message where only text or xml content types |
370
|
|
|
|
|
|
|
# are decoded |
371
|
0
|
|
|
|
|
|
my $response = $self->response; |
372
|
0
|
|
|
|
|
|
my $ct = $self->response->header("Content-Type"); |
373
|
0
|
0
|
0
|
|
|
|
unless ($response->content_is_text or $response->content_is_xml) { |
374
|
0
|
|
|
|
|
|
my ($charset) = $ct =~ m{charset=(\S+)}; |
375
|
0
|
|
0
|
|
|
|
$charset ||= "ISO-8859-1"; |
376
|
0
|
|
|
|
|
|
require Encode; |
377
|
0
|
|
|
|
|
|
$content = Encode::decode($charset, $content); |
378
|
|
|
|
|
|
|
} |
379
|
|
|
|
|
|
|
|
380
|
0
|
|
|
|
|
|
return $content; |
381
|
|
|
|
|
|
|
} |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
=head1 SEE ALSO |
384
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
L, |
386
|
|
|
|
|
|
|
L, |
387
|
|
|
|
|
|
|
L, |
388
|
|
|
|
|
|
|
L, |
389
|
|
|
|
|
|
|
L, |
390
|
|
|
|
|
|
|
L |
391
|
|
|
|
|
|
|
|
392
|
|
|
|
|
|
|
=head1 AUTHOR |
393
|
|
|
|
|
|
|
|
394
|
|
|
|
|
|
|
Socialtext, Inc. C<< >> |
395
|
|
|
|
|
|
|
|
396
|
|
|
|
|
|
|
=head1 COPYRIGHT & LICENSE |
397
|
|
|
|
|
|
|
|
398
|
|
|
|
|
|
|
Copyright 2006 Socialtext, Inc., all rights reserved. |
399
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
Same terms as Perl. |
401
|
|
|
|
|
|
|
|
402
|
|
|
|
|
|
|
=cut |
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
1; |