line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package HTTP::Request::FromCurl; |
2
|
13
|
|
|
13
|
|
326491
|
use strict; |
|
13
|
|
|
|
|
114
|
|
|
13
|
|
|
|
|
409
|
|
3
|
13
|
|
|
13
|
|
70
|
use warnings; |
|
13
|
|
|
|
|
32
|
|
|
13
|
|
|
|
|
457
|
|
4
|
13
|
|
|
13
|
|
96
|
use File::Basename 'basename'; |
|
13
|
|
|
|
|
35
|
|
|
13
|
|
|
|
|
1527
|
|
5
|
13
|
|
|
13
|
|
5998
|
use HTTP::Request; |
|
13
|
|
|
|
|
315553
|
|
|
13
|
|
|
|
|
480
|
|
6
|
13
|
|
|
13
|
|
6852
|
use HTTP::Request::Common; |
|
13
|
|
|
|
|
32239
|
|
|
13
|
|
|
|
|
958
|
|
7
|
13
|
|
|
13
|
|
104
|
use URI; |
|
13
|
|
|
|
|
26
|
|
|
13
|
|
|
|
|
421
|
|
8
|
13
|
|
|
13
|
|
77
|
use URI::Escape; |
|
13
|
|
|
|
|
26
|
|
|
13
|
|
|
|
|
653
|
|
9
|
13
|
|
|
13
|
|
10473
|
use Getopt::Long; |
|
13
|
|
|
|
|
144875
|
|
|
13
|
|
|
|
|
69
|
|
10
|
13
|
|
|
13
|
|
2071
|
use File::Spec::Unix; |
|
13
|
|
|
|
|
45
|
|
|
13
|
|
|
|
|
604
|
|
11
|
13
|
|
|
13
|
|
7476
|
use HTTP::Request::CurlParameters; |
|
13
|
|
|
|
|
69
|
|
|
13
|
|
|
|
|
648
|
|
12
|
13
|
|
|
13
|
|
7513
|
use HTTP::Request::Generator 'generate_requests'; |
|
13
|
|
|
|
|
308076
|
|
|
13
|
|
|
|
|
1048
|
|
13
|
13
|
|
|
13
|
|
124
|
use PerlX::Maybe; |
|
13
|
|
|
|
|
46
|
|
|
13
|
|
|
|
|
140
|
|
14
|
13
|
|
|
13
|
|
7193
|
use MIME::Base64 'encode_base64'; |
|
13
|
|
|
|
|
8820
|
|
|
13
|
|
|
|
|
881
|
|
15
|
13
|
|
|
13
|
|
119
|
use File::Basename 'basename'; |
|
13
|
|
|
|
|
29
|
|
|
13
|
|
|
|
|
628
|
|
16
|
|
|
|
|
|
|
|
17
|
13
|
|
|
13
|
|
108
|
use Filter::signatures; |
|
13
|
|
|
|
|
36
|
|
|
13
|
|
|
|
|
100
|
|
18
|
13
|
|
|
13
|
|
363
|
use feature 'signatures'; |
|
13
|
|
|
|
|
45
|
|
|
13
|
|
|
|
|
1054
|
|
19
|
13
|
|
|
13
|
|
102
|
no warnings 'experimental::signatures'; |
|
13
|
|
|
|
|
28
|
|
|
13
|
|
|
|
|
44368
|
|
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
our $VERSION = '0.52'; |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
=head1 NAME |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
HTTP::Request::FromCurl - create a HTTP::Request from a curl command line |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
=head1 SYNOPSIS |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
my $req = HTTP::Request::FromCurl->new( |
30
|
|
|
|
|
|
|
# Note - curl itself may not appear |
31
|
|
|
|
|
|
|
argv => ['https://example.com'], |
32
|
|
|
|
|
|
|
); |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
my $req = HTTP::Request::FromCurl->new( |
35
|
|
|
|
|
|
|
command => 'https://example.com', |
36
|
|
|
|
|
|
|
); |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
my $req = HTTP::Request::FromCurl->new( |
39
|
|
|
|
|
|
|
command_curl => 'curl -A mycurl/1.0 https://example.com', |
40
|
|
|
|
|
|
|
); |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
my @requests = HTTP::Request::FromCurl->new( |
43
|
|
|
|
|
|
|
command_curl => 'curl -A mycurl/1.0 https://example.com https://www.example.com', |
44
|
|
|
|
|
|
|
); |
45
|
|
|
|
|
|
|
# Send the requests |
46
|
|
|
|
|
|
|
for my $r (@requests) { |
47
|
|
|
|
|
|
|
$ua->request( $r->as_request ) |
48
|
|
|
|
|
|
|
} |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
=head1 RATIONALE |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
C command lines are found everywhere in documentation. The Firefox |
53
|
|
|
|
|
|
|
developer tools can also copy network requests as C command lines from |
54
|
|
|
|
|
|
|
the network panel. This module enables converting these to Perl code. |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
=head1 METHODS |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
=head2 C<< ->new >> |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
my $req = HTTP::Request::FromCurl->new( |
61
|
|
|
|
|
|
|
# Note - curl itself may not appear |
62
|
|
|
|
|
|
|
argv => ['--user-agent', 'myscript/1.0', 'https://example.com'], |
63
|
|
|
|
|
|
|
); |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
my $req = HTTP::Request::FromCurl->new( |
66
|
|
|
|
|
|
|
# Note - curl itself may not appear |
67
|
|
|
|
|
|
|
command => '--user-agent myscript/1.0 https://example.com', |
68
|
|
|
|
|
|
|
); |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
The constructor returns one or more L objects |
71
|
|
|
|
|
|
|
that encapsulate the parameters. If the command generates multiple requests, |
72
|
|
|
|
|
|
|
they will be returned in list context. In scalar context, only the first request |
73
|
|
|
|
|
|
|
will be returned. Note that the order of URLs between C<--url> and unadorned URLs will be changed in the sense that all unadorned URLs will be handled first. |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
my $req = HTTP::Request::FromCurl->new( |
76
|
|
|
|
|
|
|
command => '--data-binary @/etc/passwd https://example.com', |
77
|
|
|
|
|
|
|
read_files => 1, |
78
|
|
|
|
|
|
|
); |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
=head3 Options |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
=over 4 |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
=item B |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
An arrayref of commands as could be given in C< @ARGV >. |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
=item B |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
A scalar in a command line, excluding the C command |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
=item B |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
A scalar in a command line, including the C command |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
=item B |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
Do read in the content of files specified with (for example) |
99
|
|
|
|
|
|
|
C<< --data=@/etc/passwd >>. The default is to not read the contents of files |
100
|
|
|
|
|
|
|
specified this way. |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
=back |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
=head1 GLOBAL VARIABLES |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
=head2 C<< %default_headers >> |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
Contains the default headers added to every request |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
=cut |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
our %default_headers = ( |
113
|
|
|
|
|
|
|
'Accept' => '*/*', |
114
|
|
|
|
|
|
|
'User-Agent' => 'curl/7.55.1', |
115
|
|
|
|
|
|
|
); |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
=head2 C<< @option_spec >> |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
Contains the L specification of the recognized command line |
120
|
|
|
|
|
|
|
parameters. |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
The following C options are recognized but largely ignored: |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
=over 4 |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
=item C< --disable > |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
=item C< --dump-header > |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
=item C< --include > |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
=item C< --location > |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
=item C< --progress-bar > |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
=item C< --show-error > |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
=item C< --fail > |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
=item C< --silent > |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
=item C< --verbose > |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
=item C< --junk-session-cookies > |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
If you want to keep session cookies between subsequent requests, you need to |
147
|
|
|
|
|
|
|
provide a cookie jar in your user agent. |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
=item C<--next> |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
Resetting the UA between requests is something you need to handle yourself |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
=item C<--parallel> |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
=item C<--parallel-immediate> |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
=item C<--parallel-max> |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
Parallel requests is something you need to handle in the UA |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
=back |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
=cut |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
our @option_spec = ( |
166
|
|
|
|
|
|
|
'user-agent|A=s', |
167
|
|
|
|
|
|
|
'verbose|v', # ignored |
168
|
|
|
|
|
|
|
'show-error|S', # ignored |
169
|
|
|
|
|
|
|
'fail|f', # ignored |
170
|
|
|
|
|
|
|
'silent|s', # ignored |
171
|
|
|
|
|
|
|
'anyauth', # ignored |
172
|
|
|
|
|
|
|
'basic', |
173
|
|
|
|
|
|
|
'buffer!', |
174
|
|
|
|
|
|
|
'capath=s', |
175
|
|
|
|
|
|
|
'cert|E=s', |
176
|
|
|
|
|
|
|
'compressed', |
177
|
|
|
|
|
|
|
'cookie|b=s', |
178
|
|
|
|
|
|
|
'cookie-jar|c=s', |
179
|
|
|
|
|
|
|
'data|d=s@', |
180
|
|
|
|
|
|
|
'data-ascii=s@', |
181
|
|
|
|
|
|
|
'data-binary=s@', |
182
|
|
|
|
|
|
|
'data-raw=s@', |
183
|
|
|
|
|
|
|
'data-urlencode=s@', |
184
|
|
|
|
|
|
|
'digest', |
185
|
|
|
|
|
|
|
'disable|q!', # ignored |
186
|
|
|
|
|
|
|
'dump-header|D=s', # ignored |
187
|
|
|
|
|
|
|
'referrer|e=s', |
188
|
|
|
|
|
|
|
'form|F=s@', |
189
|
|
|
|
|
|
|
'form-string=s@', |
190
|
|
|
|
|
|
|
'get|G', |
191
|
|
|
|
|
|
|
'globoff|g', |
192
|
|
|
|
|
|
|
'head|I', |
193
|
|
|
|
|
|
|
'header|H=s@', |
194
|
|
|
|
|
|
|
'include|i', # ignored |
195
|
|
|
|
|
|
|
'interface=s', |
196
|
|
|
|
|
|
|
'insecure|k', |
197
|
|
|
|
|
|
|
'json=s@', |
198
|
|
|
|
|
|
|
'location|L', # ignored, we always follow redirects |
199
|
|
|
|
|
|
|
'max-filesize=s', |
200
|
|
|
|
|
|
|
'max-time|m=s', |
201
|
|
|
|
|
|
|
'ntlm', |
202
|
|
|
|
|
|
|
'keepalive!', |
203
|
|
|
|
|
|
|
'range=s', |
204
|
|
|
|
|
|
|
'request|X=s', |
205
|
|
|
|
|
|
|
'oauth2-bearer=s', |
206
|
|
|
|
|
|
|
'output|o=s', |
207
|
|
|
|
|
|
|
'progress-bar|#', # ignored |
208
|
|
|
|
|
|
|
'user|u=s', |
209
|
|
|
|
|
|
|
'next', # ignored |
210
|
|
|
|
|
|
|
'parallel|Z', # ignored |
211
|
|
|
|
|
|
|
'parallel-immediate', # ignored |
212
|
|
|
|
|
|
|
'parallel-max', # ignored |
213
|
|
|
|
|
|
|
'junk-session-cookies|j', # ignored, must be set in code using the HTTP request |
214
|
|
|
|
|
|
|
'unix-socket=s', |
215
|
|
|
|
|
|
|
'url=s@', |
216
|
|
|
|
|
|
|
); |
217
|
|
|
|
|
|
|
|
218
|
5
|
|
|
5
|
1
|
4963
|
sub new( $class, %options ) { |
|
5
|
|
|
|
|
12
|
|
|
5
|
|
|
|
|
12
|
|
|
5
|
|
|
|
|
9
|
|
219
|
5
|
|
|
|
|
8
|
my $cmd = $options{ argv }; |
220
|
|
|
|
|
|
|
|
221
|
5
|
100
|
|
|
|
20
|
if( $options{ command }) { |
|
|
50
|
|
|
|
|
|
222
|
1
|
|
|
|
|
460
|
require Text::ParseWords; |
223
|
1
|
|
|
|
|
1393
|
$cmd = [ Text::ParseWords::shellwords($options{ command }) ]; |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
} elsif( $options{ command_curl }) { |
226
|
0
|
|
|
|
|
0
|
require Text::ParseWords; |
227
|
0
|
|
|
|
|
0
|
$cmd = [ Text::ParseWords::shellwords($options{ command_curl }) ]; |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
# remove the implicit curl command: |
230
|
0
|
|
|
|
|
0
|
shift @$cmd; |
231
|
|
|
|
|
|
|
}; |
232
|
|
|
|
|
|
|
|
233
|
5
|
|
|
|
|
417
|
for (@$cmd) { |
234
|
28
|
50
|
|
|
|
79
|
$_ = '--next' |
235
|
|
|
|
|
|
|
if $_ eq '-:'; # GetOptions does not like "next|:" as specification |
236
|
|
|
|
|
|
|
}; |
237
|
|
|
|
|
|
|
|
238
|
5
|
|
|
|
|
34
|
my $p = Getopt::Long::Parser->new( |
239
|
|
|
|
|
|
|
config => [ 'bundling', 'no_auto_abbrev', 'no_ignore_case_always' ], |
240
|
|
|
|
|
|
|
); |
241
|
5
|
50
|
|
|
|
528
|
$p->getoptionsfromarray( $cmd, |
242
|
|
|
|
|
|
|
\my %curl_options, |
243
|
|
|
|
|
|
|
@option_spec, |
244
|
|
|
|
|
|
|
) or return; |
245
|
5
|
50
|
|
|
|
16086
|
my @urls = (@$cmd, @{ $curl_options{ url } || [] }); |
|
5
|
|
|
|
|
32
|
|
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
return |
248
|
5
|
100
|
|
|
|
25
|
wantarray ? map { $class->_build_request( $_, \%curl_options, %options ) } @urls |
|
7
|
|
|
|
|
31
|
|
249
|
|
|
|
|
|
|
: ($class->_build_request( $urls[0], \%curl_options, %options ))[0] |
250
|
|
|
|
|
|
|
; |
251
|
|
|
|
|
|
|
} |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
=head1 METHODS |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
=head2 C<< ->squash_uri( $uri ) >> |
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
my $uri = HTTP::Request::FromCurl->squash_uri( |
258
|
|
|
|
|
|
|
URI->new( 'https://example.com/foo/bar/..' ) |
259
|
|
|
|
|
|
|
); |
260
|
|
|
|
|
|
|
# https://example.com/foo/ |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
Helper method to clean up relative path elements from the URI the same way |
263
|
|
|
|
|
|
|
that curl does. |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
=cut |
266
|
|
|
|
|
|
|
|
267
|
19
|
|
|
19
|
1
|
20105
|
sub squash_uri( $class, $uri ) { |
|
19
|
|
|
|
|
36
|
|
|
19
|
|
|
|
|
27
|
|
|
19
|
|
|
|
|
29
|
|
268
|
19
|
|
|
|
|
63
|
my $u = $uri->clone; |
269
|
19
|
|
|
|
|
279
|
my @segments = $u->path_segments; |
270
|
|
|
|
|
|
|
|
271
|
19
|
100
|
100
|
|
|
833
|
if( $segments[-1] and ($segments[-1] eq '..' or $segments[-1] eq '.' ) ) { |
|
|
|
100
|
|
|
|
|
272
|
6
|
|
|
|
|
16
|
push @segments, ''; |
273
|
|
|
|
|
|
|
}; |
274
|
|
|
|
|
|
|
|
275
|
19
|
|
|
|
|
39
|
@segments = grep { $_ ne '.' } @segments; |
|
57
|
|
|
|
|
117
|
|
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
# While we find a pair ( "foo", ".." ) remove that pair |
278
|
19
|
|
|
|
|
42
|
while( grep { $_ eq '..' } @segments ) { |
|
75
|
|
|
|
|
143
|
|
279
|
10
|
|
|
|
|
18
|
my $i = 0; |
280
|
10
|
|
|
|
|
23
|
while( $i < $#segments ) { |
281
|
28
|
100
|
100
|
|
|
94
|
if( $segments[$i] ne '..' and $segments[$i+1] eq '..') { |
282
|
12
|
|
|
|
|
37
|
splice @segments, $i, 2; |
283
|
|
|
|
|
|
|
} else { |
284
|
16
|
|
|
|
|
31
|
$i++ |
285
|
|
|
|
|
|
|
}; |
286
|
|
|
|
|
|
|
}; |
287
|
|
|
|
|
|
|
}; |
288
|
|
|
|
|
|
|
|
289
|
19
|
100
|
|
|
|
52
|
if( @segments < 2 ) { |
290
|
11
|
|
|
|
|
60
|
@segments = ('',''); |
291
|
|
|
|
|
|
|
}; |
292
|
|
|
|
|
|
|
|
293
|
19
|
|
|
|
|
63
|
$u->path_segments( @segments ); |
294
|
19
|
|
|
|
|
1246
|
return $u |
295
|
|
|
|
|
|
|
} |
296
|
|
|
|
|
|
|
|
297
|
30
|
|
|
30
|
|
40
|
sub _add_header( $self, $headers, $h, $value ) { |
|
30
|
|
|
|
|
42
|
|
|
30
|
|
|
|
|
35
|
|
|
30
|
|
|
|
|
46
|
|
|
30
|
|
|
|
|
38
|
|
|
30
|
|
|
|
|
40
|
|
298
|
30
|
50
|
|
|
|
85
|
if( exists $headers->{ $h }) { |
299
|
0
|
0
|
|
|
|
0
|
if (!ref( $headers->{ $h })) { |
300
|
0
|
|
|
|
|
0
|
$headers->{ $h } = [ $headers->{ $h }]; |
301
|
|
|
|
|
|
|
} |
302
|
0
|
|
|
|
|
0
|
push @{ $headers->{ $h } }, $value; |
|
0
|
|
|
|
|
0
|
|
303
|
|
|
|
|
|
|
} else { |
304
|
30
|
|
|
|
|
75
|
$headers->{ $h } = $value; |
305
|
|
|
|
|
|
|
} |
306
|
|
|
|
|
|
|
} |
307
|
|
|
|
|
|
|
|
308
|
1
|
|
|
1
|
|
2
|
sub _maybe_read_data_file( $self, $read_files, $data ) { |
|
1
|
|
|
|
|
35
|
|
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
2
|
|
309
|
1
|
|
|
|
|
2
|
my $res; |
310
|
1
|
50
|
|
|
|
4
|
if( $read_files ) { |
311
|
0
|
0
|
|
|
|
0
|
if( $data =~ /^\@(.*)/ ) { |
312
|
0
|
0
|
|
|
|
0
|
open my $fh, '<', $1 |
313
|
|
|
|
|
|
|
or die "$1: $!"; |
314
|
0
|
|
|
|
|
0
|
local $/; # / for Filter::Simple |
315
|
0
|
|
|
|
|
0
|
binmode $fh; |
316
|
0
|
|
|
|
|
0
|
$res = <$fh> |
317
|
|
|
|
|
|
|
} else { |
318
|
0
|
|
|
|
|
0
|
$res = $data |
319
|
|
|
|
|
|
|
} |
320
|
|
|
|
|
|
|
} else { |
321
|
1
|
50
|
|
|
|
13
|
$res = ($data =~ /^\@(.*)/) |
322
|
|
|
|
|
|
|
? "... contents of $1 ..." |
323
|
|
|
|
|
|
|
: $data |
324
|
|
|
|
|
|
|
} |
325
|
1
|
|
|
|
|
3
|
return $res |
326
|
|
|
|
|
|
|
} |
327
|
|
|
|
|
|
|
|
328
|
0
|
|
|
0
|
|
0
|
sub _maybe_read_upload_file( $self, $read_files, $data ) { |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
329
|
0
|
|
|
|
|
0
|
my $res; |
330
|
0
|
0
|
|
|
|
0
|
if( $read_files ) { |
331
|
0
|
0
|
|
|
|
0
|
if( $data =~ /^<(.*)/ ) { |
|
|
0
|
|
|
|
|
|
332
|
0
|
0
|
|
|
|
0
|
open my $fh, '<', $1 |
333
|
|
|
|
|
|
|
or die "$1: $!"; |
334
|
0
|
|
|
|
|
0
|
local $/; # / for Filter::Simple |
335
|
0
|
|
|
|
|
0
|
binmode $fh; |
336
|
0
|
|
|
|
|
0
|
$res = <$fh> |
337
|
|
|
|
|
|
|
} elsif( $data =~ /^\@(.*)/ ) { |
338
|
|
|
|
|
|
|
# Upload the file |
339
|
0
|
|
|
|
|
0
|
$res = [ $1 => basename($1), Content_Type => 'application/octet-stream' ]; |
340
|
|
|
|
|
|
|
} else { |
341
|
0
|
|
|
|
|
0
|
$res = $data |
342
|
|
|
|
|
|
|
} |
343
|
|
|
|
|
|
|
} else { |
344
|
0
|
0
|
|
|
|
0
|
if( $data =~ /^[<@](.*)/ ) { |
345
|
0
|
|
|
|
|
0
|
$res = [ undef, basename($1), Content_Type => 'application/octet-stream', Content => "... contents of $1 ..." ], |
346
|
|
|
|
|
|
|
} else { |
347
|
0
|
|
|
|
|
0
|
$res = $data |
348
|
|
|
|
|
|
|
} |
349
|
|
|
|
|
|
|
} |
350
|
0
|
|
|
|
|
0
|
return $res |
351
|
|
|
|
|
|
|
} |
352
|
|
|
|
|
|
|
|
353
|
8
|
|
|
8
|
|
14
|
sub _build_request( $self, $uri, $options, %build_options ) { |
|
8
|
|
|
|
|
14
|
|
|
8
|
|
|
|
|
13
|
|
|
8
|
|
|
|
|
12
|
|
|
8
|
|
|
|
|
17
|
|
|
8
|
|
|
|
|
12
|
|
354
|
8
|
|
|
|
|
11
|
my $body; |
355
|
8
|
100
|
|
|
|
13
|
my @headers = @{ $options->{header} || []}; |
|
8
|
|
|
|
|
35
|
|
356
|
8
|
|
|
|
|
22
|
my $method = $options->{request}; |
357
|
|
|
|
|
|
|
# Ideally, we shouldn't sort the data but process it in-order |
358
|
8
|
100
|
|
|
|
29
|
my @post_read_data = (@{ $options->{'data'} || []}, |
359
|
8
|
50
|
|
|
|
13
|
@{ $options->{'data-ascii'} || [] } |
|
8
|
|
|
|
|
32
|
|
360
|
|
|
|
|
|
|
); |
361
|
|
|
|
|
|
|
; |
362
|
8
|
50
|
|
|
|
16
|
my @post_raw_data = @{ $options->{'data-raw'} || [] }, |
|
8
|
|
|
|
|
30
|
|
363
|
|
|
|
|
|
|
; |
364
|
8
|
50
|
|
|
|
13
|
my @post_urlencode_data = @{ $options->{'data-urlencode'} || [] }; |
|
8
|
|
|
|
|
25
|
|
365
|
8
|
50
|
|
|
|
13
|
my @post_binary_data = @{ $options->{'data-binary'} || [] }; |
|
8
|
|
|
|
|
25
|
|
366
|
8
|
50
|
|
|
|
15
|
my @post_json_data = @{ $options->{'json'} || [] }; |
|
8
|
|
|
|
|
24
|
|
367
|
|
|
|
|
|
|
|
368
|
8
|
|
|
|
|
13
|
my @form_args; |
369
|
8
|
50
|
|
|
|
20
|
if( $options->{form}) { |
370
|
|
|
|
|
|
|
# support --form uploaded_file=@myfile |
371
|
|
|
|
|
|
|
# and --form "uploaded_text=<~/texts/content.txt" |
372
|
|
|
|
|
|
|
push @form_args, map { /^([^=]+)=(.*)$/ |
373
|
0
|
0
|
|
|
|
0
|
? ($1 => $self->_maybe_read_upload_file( $build_options{ read_files }, $2 )) |
374
|
0
|
|
|
|
|
0
|
: () } @{$options->{form} |
375
|
0
|
|
|
|
|
0
|
}; |
376
|
|
|
|
|
|
|
}; |
377
|
8
|
50
|
|
|
|
16
|
if( $options->{'form-string'}) { |
378
|
0
|
0
|
|
|
|
0
|
push @form_args, map {; /^([^=]+)=(.*)$/ ? ($1 => $2) : (); } @{ $options->{'form-string'}}; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
379
|
|
|
|
|
|
|
}; |
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
# expand the URI here if wanted |
382
|
8
|
|
|
|
|
17
|
my @uris = ($uri); |
383
|
8
|
100
|
|
|
|
18
|
if( ! $options->{ globoff }) { |
384
|
4
|
|
|
|
|
57
|
@uris = map { $_->{url} } generate_requests( pattern => shift @uris, limit => $build_options{ limit } ); |
|
5
|
|
|
|
|
20942
|
|
385
|
|
|
|
|
|
|
} |
386
|
|
|
|
|
|
|
|
387
|
8
|
50
|
33
|
|
|
43
|
if( $options->{'max-filesize'} |
388
|
|
|
|
|
|
|
and $options->{'max-filesize'} =~ m/^(\d+)([kmg])$/i ) { |
389
|
|
|
|
|
|
|
my $mult = { |
390
|
|
|
|
|
|
|
'k' => 1024, |
391
|
|
|
|
|
|
|
'g' => 1024*1024*1024, |
392
|
|
|
|
|
|
|
'm' => 1024*1024, |
393
|
0
|
|
|
|
|
0
|
}->{ $2 }; |
394
|
0
|
|
|
|
|
0
|
$options->{'max-filesize'} = $1 * $mult; |
395
|
|
|
|
|
|
|
} |
396
|
|
|
|
|
|
|
|
397
|
8
|
|
|
|
|
12
|
my @res; |
398
|
8
|
|
|
|
|
22
|
for my $uri (@uris) { |
399
|
9
|
|
|
|
|
41
|
$uri = URI->new( $uri ); |
400
|
9
|
|
|
|
|
643
|
$uri = $self->squash_uri( $uri ); |
401
|
|
|
|
|
|
|
|
402
|
9
|
100
|
|
|
|
84
|
my $host = $uri->can( 'host_port' ) ? $uri->host_port : "$uri"; |
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
# Stuff we use unless nothing else hits |
405
|
9
|
|
|
|
|
281
|
my %request_default_headers = %default_headers; |
406
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
# Sluuuurp |
408
|
|
|
|
|
|
|
# Thous should be hoisted out of the loop |
409
|
|
|
|
|
|
|
@post_binary_data = map { |
410
|
9
|
|
|
|
|
22
|
$self->_maybe_read_data_file( $build_options{ read_files }, $_ ); |
|
0
|
|
|
|
|
0
|
|
411
|
|
|
|
|
|
|
} @post_binary_data; |
412
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
@post_json_data = map { |
414
|
9
|
|
|
|
|
18
|
$self->_maybe_read_data_file( $build_options{ read_files }, $_ ); |
|
0
|
|
|
|
|
0
|
|
415
|
|
|
|
|
|
|
} @post_json_data; |
416
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
@post_read_data = map { |
418
|
9
|
|
|
|
|
15
|
my $v = $self->_maybe_read_data_file( $build_options{ read_files }, $_ ); |
|
1
|
|
|
|
|
6
|
|
419
|
1
|
|
|
|
|
5
|
$v =~ s![\r\n]!!g; |
420
|
1
|
|
|
|
|
4
|
$v |
421
|
|
|
|
|
|
|
} @post_read_data; |
422
|
|
|
|
|
|
|
|
423
|
|
|
|
|
|
|
@post_urlencode_data = map { |
424
|
9
|
0
|
|
|
|
16
|
m/\A([^@=]*)([=@])?(.*)\z/sm |
|
0
|
|
|
|
|
0
|
|
425
|
|
|
|
|
|
|
or die "This should never happen"; |
426
|
0
|
|
|
|
|
0
|
my ($name, $op, $content) = ($1,$2,$3); |
427
|
0
|
0
|
|
|
|
0
|
if(! $op) { |
|
|
0
|
|
|
|
|
|
428
|
0
|
|
|
|
|
0
|
$content = $name; |
429
|
|
|
|
|
|
|
} elsif( $op eq '@' ) { |
430
|
0
|
|
|
|
|
0
|
$content = "$op$content"; |
431
|
|
|
|
|
|
|
}; |
432
|
0
|
0
|
0
|
|
|
0
|
if( defined $name and length $name ) { |
433
|
0
|
|
|
|
|
0
|
$name .= '='; |
434
|
|
|
|
|
|
|
} else { |
435
|
0
|
|
|
|
|
0
|
$name = ''; |
436
|
|
|
|
|
|
|
}; |
437
|
0
|
|
|
|
|
0
|
my $v = $self->_maybe_read_data_file( $build_options{ read_files }, $content ); |
438
|
0
|
|
|
|
|
0
|
$name . uri_escape( $v ) |
439
|
|
|
|
|
|
|
} @post_urlencode_data; |
440
|
|
|
|
|
|
|
|
441
|
9
|
|
|
|
|
15
|
my $data; |
442
|
9
|
100
|
66
|
|
|
73
|
if( @post_read_data |
|
|
50
|
66
|
|
|
|
|
|
|
|
33
|
|
|
|
|
443
|
|
|
|
|
|
|
or @post_binary_data |
444
|
|
|
|
|
|
|
or @post_raw_data |
445
|
|
|
|
|
|
|
or @post_urlencode_data |
446
|
|
|
|
|
|
|
) { |
447
|
1
|
|
|
|
|
4
|
$data = join "&", |
448
|
|
|
|
|
|
|
@post_read_data, |
449
|
|
|
|
|
|
|
@post_binary_data, |
450
|
|
|
|
|
|
|
@post_raw_data, |
451
|
|
|
|
|
|
|
@post_urlencode_data |
452
|
|
|
|
|
|
|
; |
453
|
|
|
|
|
|
|
} elsif( @post_json_data ) { |
454
|
0
|
|
|
|
|
0
|
$data = join '', @post_json_data; |
455
|
|
|
|
|
|
|
} |
456
|
|
|
|
|
|
|
|
457
|
9
|
50
|
|
|
|
53
|
if( @form_args) { |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
458
|
0
|
|
0
|
|
|
0
|
$method //= 'POST'; |
459
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
#my $req = HTTP::Request::Common::POST( |
461
|
|
|
|
|
|
|
# 'https://example.com', |
462
|
|
|
|
|
|
|
# Content_Type => 'form-data', |
463
|
|
|
|
|
|
|
# Content => \@form_args, |
464
|
|
|
|
|
|
|
#); |
465
|
|
|
|
|
|
|
#$body = $req->content; |
466
|
|
|
|
|
|
|
#$request_default_headers{ 'Content-Type' } = join "; ", $req->headers->content_type; |
467
|
|
|
|
|
|
|
|
468
|
|
|
|
|
|
|
} elsif( $options->{ get }) { |
469
|
0
|
|
|
|
|
0
|
$method = 'GET'; |
470
|
|
|
|
|
|
|
# Also, append the POST data to the URL |
471
|
0
|
0
|
|
|
|
0
|
if( $data ) { |
472
|
0
|
|
|
|
|
0
|
my $q = $uri->query; |
473
|
0
|
0
|
0
|
|
|
0
|
if( defined $q and length $q ) { |
474
|
0
|
|
|
|
|
0
|
$q .= "&"; |
475
|
|
|
|
|
|
|
} else { |
476
|
0
|
|
|
|
|
0
|
$q = ""; |
477
|
|
|
|
|
|
|
}; |
478
|
0
|
|
|
|
|
0
|
$q .= $data; |
479
|
0
|
|
|
|
|
0
|
$uri->query( $q ); |
480
|
|
|
|
|
|
|
}; |
481
|
|
|
|
|
|
|
|
482
|
|
|
|
|
|
|
} elsif( $options->{ head }) { |
483
|
0
|
|
|
|
|
0
|
$method = 'HEAD'; |
484
|
|
|
|
|
|
|
|
485
|
|
|
|
|
|
|
} elsif( defined $data ) { |
486
|
1
|
|
50
|
|
|
4
|
$method //= 'POST'; |
487
|
1
|
|
|
|
|
2
|
$body = $data; |
488
|
|
|
|
|
|
|
|
489
|
1
|
50
|
|
|
|
3
|
if( @post_json_data ) { |
490
|
0
|
|
|
|
|
0
|
$request_default_headers{ 'Content-Type' } = "application/json"; |
491
|
0
|
|
|
|
|
0
|
$request_default_headers{ 'Accept' } = "application/json"; |
492
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
} else { |
494
|
1
|
|
|
|
|
3
|
$request_default_headers{ 'Content-Type' } = 'application/x-www-form-urlencoded'; |
495
|
|
|
|
|
|
|
}; |
496
|
|
|
|
|
|
|
|
497
|
|
|
|
|
|
|
} else { |
498
|
8
|
|
100
|
|
|
21
|
$method ||= 'GET'; |
499
|
|
|
|
|
|
|
}; |
500
|
|
|
|
|
|
|
|
501
|
9
|
100
|
|
|
|
23
|
if( defined $body ) { |
502
|
1
|
|
|
|
|
2
|
$request_default_headers{ 'Content-Length' } = length $body; |
503
|
|
|
|
|
|
|
}; |
504
|
|
|
|
|
|
|
|
505
|
9
|
50
|
|
|
|
23
|
if( $options->{ 'oauth2-bearer' } ) { |
506
|
0
|
|
|
|
|
0
|
push @headers, sprintf 'Authorization: Bearer %s', $options->{'oauth2-bearer'}; |
507
|
|
|
|
|
|
|
}; |
508
|
|
|
|
|
|
|
|
509
|
9
|
100
|
|
|
|
27
|
if( $options->{ 'user' } ) { |
510
|
1
|
50
|
33
|
|
|
14
|
if( $options->{anyauth} |
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
511
|
|
|
|
|
|
|
|| $options->{digest} |
512
|
|
|
|
|
|
|
|| $options->{ntlm} |
513
|
|
|
|
|
|
|
|| $options->{negotiate} |
514
|
|
|
|
|
|
|
) { |
515
|
|
|
|
|
|
|
# Nothing to do here, just let LWP::UserAgent do its thing |
516
|
|
|
|
|
|
|
# This means one additional request to fetch the appropriate |
517
|
|
|
|
|
|
|
# 401 response asking for credentials, but ... |
518
|
|
|
|
|
|
|
} else { |
519
|
|
|
|
|
|
|
# $options->{basic} or none at all |
520
|
1
|
|
|
|
|
4
|
my $info = delete $options->{'user'}; |
521
|
|
|
|
|
|
|
# We need to bake this into the header here?! |
522
|
1
|
|
|
|
|
11
|
push @headers, sprintf 'Authorization: Basic %s', encode_base64( $info ); |
523
|
|
|
|
|
|
|
} |
524
|
|
|
|
|
|
|
}; |
525
|
|
|
|
|
|
|
|
526
|
9
|
|
|
|
|
18
|
my %headers; |
527
|
9
|
|
|
|
|
23
|
for my $kv ( |
528
|
2
|
50
|
|
|
|
17
|
(map { /^\s*([^:\s]+)\s*:\s*(.*)$/ ? [$1 => $2] : () } @headers),) { |
529
|
2
|
|
|
|
|
7
|
$self->_add_header( \%headers, @$kv ); |
530
|
|
|
|
|
|
|
}; |
531
|
|
|
|
|
|
|
|
532
|
9
|
50
|
|
|
|
23
|
if( defined $options->{ 'user-agent' }) { |
533
|
0
|
|
|
|
|
0
|
$self->_add_header( \%headers, "User-Agent", $options->{ 'user-agent' } ); |
534
|
|
|
|
|
|
|
}; |
535
|
|
|
|
|
|
|
|
536
|
9
|
50
|
|
|
|
40
|
if( defined $options->{ referrer }) { |
537
|
0
|
|
|
|
|
0
|
$self->_add_header( \%headers, "Referer" => $options->{ 'referrer' } ); |
538
|
|
|
|
|
|
|
}; |
539
|
|
|
|
|
|
|
|
540
|
9
|
50
|
|
|
|
23
|
if( defined $options->{ range }) { |
541
|
0
|
|
|
|
|
0
|
$self->_add_header( \%headers, "Range" => $options->{ 'range' } ); |
542
|
|
|
|
|
|
|
}; |
543
|
|
|
|
|
|
|
|
544
|
|
|
|
|
|
|
# We want to compare the headers case-insensitively |
545
|
9
|
|
|
|
|
27
|
my %headers_lc = map { lc $_ => 1 } keys %headers; |
|
2
|
|
|
|
|
9
|
|
546
|
|
|
|
|
|
|
|
547
|
9
|
|
|
|
|
21
|
for my $k (keys %request_default_headers) { |
548
|
20
|
100
|
|
|
|
52
|
if( ! $headers_lc{ lc $k }) { |
549
|
19
|
|
|
|
|
43
|
$self->_add_header( \%headers, $k, $request_default_headers{ $k }); |
550
|
|
|
|
|
|
|
}; |
551
|
|
|
|
|
|
|
}; |
552
|
9
|
50
|
|
|
|
34
|
if( ! $headers{ 'Host' }) { |
553
|
9
|
|
|
|
|
25
|
$self->_add_header( \%headers, 'Host' => $host ); |
554
|
|
|
|
|
|
|
}; |
555
|
|
|
|
|
|
|
|
556
|
9
|
50
|
|
|
|
22
|
if( defined $options->{ 'cookie-jar' }) { |
557
|
0
|
|
|
|
|
0
|
$options->{'cookie-jar-options'}->{ 'write' } = 1; |
558
|
|
|
|
|
|
|
}; |
559
|
|
|
|
|
|
|
|
560
|
9
|
50
|
|
|
|
31
|
if( defined( my $c = $options->{ cookie })) { |
561
|
0
|
0
|
|
|
|
0
|
if( $c =~ /=/ ) { |
562
|
0
|
|
|
|
|
0
|
$headers{ Cookie } = $options->{ 'cookie' }; |
563
|
|
|
|
|
|
|
} else { |
564
|
0
|
|
|
|
|
0
|
$options->{'cookie-jar'} = $c; |
565
|
0
|
|
|
|
|
0
|
$options->{'cookie-jar-options'}->{ 'read' } = 1; |
566
|
|
|
|
|
|
|
}; |
567
|
|
|
|
|
|
|
}; |
568
|
|
|
|
|
|
|
|
569
|
|
|
|
|
|
|
# Curl 7.61.0 ignores these: |
570
|
|
|
|
|
|
|
#if( $options->{ keepalive }) { |
571
|
|
|
|
|
|
|
# $headers{ 'Keep-Alive' } = 1; |
572
|
|
|
|
|
|
|
#} elsif( exists $options->{ keepalive }) { |
573
|
|
|
|
|
|
|
# $headers{ 'Keep-Alive' } = 0; |
574
|
|
|
|
|
|
|
#}; |
575
|
|
|
|
|
|
|
|
576
|
9
|
50
|
|
|
|
20
|
if( $options->{ compressed }) { |
577
|
0
|
|
|
|
|
0
|
my $compressions = HTTP::Message::decodable(); |
578
|
0
|
|
|
|
|
0
|
$self->_add_header( \%headers, 'Accept-Encoding' => $compressions ); |
579
|
|
|
|
|
|
|
}; |
580
|
|
|
|
|
|
|
|
581
|
9
|
|
|
|
|
14
|
my $auth; |
582
|
9
|
|
|
|
|
20
|
for my $kind (qw(basic ntlm negotiate)) { |
583
|
27
|
50
|
|
|
|
57
|
if( $options->{$kind}) { |
584
|
0
|
|
|
|
|
0
|
$auth = $kind; |
585
|
|
|
|
|
|
|
} |
586
|
|
|
|
|
|
|
}; |
587
|
|
|
|
|
|
|
|
588
|
|
|
|
|
|
|
push @res, HTTP::Request::CurlParameters->new({ |
589
|
|
|
|
|
|
|
method => $method, |
590
|
|
|
|
|
|
|
uri => $uri, |
591
|
|
|
|
|
|
|
headers => \%headers, |
592
|
|
|
|
|
|
|
body => $body, |
593
|
|
|
|
|
|
|
maybe auth => $auth, |
594
|
|
|
|
|
|
|
maybe cert => $options->{cert}, |
595
|
|
|
|
|
|
|
maybe capath => $options->{capath}, |
596
|
|
|
|
|
|
|
maybe credentials => $options->{ user }, |
597
|
|
|
|
|
|
|
maybe output => $options->{ output }, |
598
|
|
|
|
|
|
|
maybe timeout => $options->{ 'max-time' }, |
599
|
|
|
|
|
|
|
maybe cookie_jar => $options->{'cookie-jar'}, |
600
|
|
|
|
|
|
|
maybe cookie_jar_options => $options->{'cookie-jar-options'}, |
601
|
|
|
|
|
|
|
maybe insecure => $options->{'insecure'}, |
602
|
|
|
|
|
|
|
maybe max_filesize => $options->{'max-filesize'}, |
603
|
|
|
|
|
|
|
maybe show_error => $options->{'show-error'}, |
604
|
|
|
|
|
|
|
maybe fail => $options->{'fail'}, |
605
|
|
|
|
|
|
|
maybe unix_socket => $options->{'unix-socket'}, |
606
|
9
|
50
|
|
|
|
328
|
maybe local_address => $options->{'interface'}, |
607
|
|
|
|
|
|
|
maybe form_args => scalar @form_args ? \@form_args : undef, |
608
|
|
|
|
|
|
|
}); |
609
|
|
|
|
|
|
|
} |
610
|
|
|
|
|
|
|
|
611
|
|
|
|
|
|
|
return @res |
612
|
8
|
|
|
|
|
151
|
}; |
613
|
|
|
|
|
|
|
|
614
|
|
|
|
|
|
|
1; |
615
|
|
|
|
|
|
|
|
616
|
|
|
|
|
|
|
=head1 LIVE DEMO |
617
|
|
|
|
|
|
|
|
618
|
|
|
|
|
|
|
L |
619
|
|
|
|
|
|
|
|
620
|
|
|
|
|
|
|
=head1 KNOWN DIFFERENCES |
621
|
|
|
|
|
|
|
|
622
|
|
|
|
|
|
|
=head2 Incompatible cookie jar formats |
623
|
|
|
|
|
|
|
|
624
|
|
|
|
|
|
|
Until somebody writes a robust Netscape cookie file parser and proper loading |
625
|
|
|
|
|
|
|
and storage for L, this module will not be able to load and |
626
|
|
|
|
|
|
|
save files in the format that Curl uses. |
627
|
|
|
|
|
|
|
|
628
|
|
|
|
|
|
|
=head2 Loading/saving cookie jars is the job of the UA |
629
|
|
|
|
|
|
|
|
630
|
|
|
|
|
|
|
You're expected to instruct your UA to load/save cookie jars: |
631
|
|
|
|
|
|
|
|
632
|
|
|
|
|
|
|
use Path::Tiny; |
633
|
|
|
|
|
|
|
use HTTP::CookieJar::LWP; |
634
|
|
|
|
|
|
|
|
635
|
|
|
|
|
|
|
if( my $cookies = $r->cookie_jar ) { |
636
|
|
|
|
|
|
|
$ua->cookie_jar( HTTP::CookieJar::LWP->new()->load_cookies( |
637
|
|
|
|
|
|
|
path($cookies)->lines |
638
|
|
|
|
|
|
|
)); |
639
|
|
|
|
|
|
|
}; |
640
|
|
|
|
|
|
|
|
641
|
|
|
|
|
|
|
=head2 Different Content-Length for POST requests |
642
|
|
|
|
|
|
|
|
643
|
|
|
|
|
|
|
=head2 Different delimiter for form data |
644
|
|
|
|
|
|
|
|
645
|
|
|
|
|
|
|
The delimiter is built by L, and C uses a different |
646
|
|
|
|
|
|
|
mechanism to come up with a unique data delimiter. This results in differences |
647
|
|
|
|
|
|
|
in the raw body content and the C header. |
648
|
|
|
|
|
|
|
|
649
|
|
|
|
|
|
|
=head1 MISSING FUNCTIONALITY |
650
|
|
|
|
|
|
|
|
651
|
|
|
|
|
|
|
=over 4 |
652
|
|
|
|
|
|
|
|
653
|
|
|
|
|
|
|
=item * |
654
|
|
|
|
|
|
|
|
655
|
|
|
|
|
|
|
File uploads / content from files |
656
|
|
|
|
|
|
|
|
657
|
|
|
|
|
|
|
While file uploads and reading POST data from files are supported, the content |
658
|
|
|
|
|
|
|
is slurped into memory completely. This can be problematic for large files |
659
|
|
|
|
|
|
|
and little available memory. |
660
|
|
|
|
|
|
|
|
661
|
|
|
|
|
|
|
=item * |
662
|
|
|
|
|
|
|
|
663
|
|
|
|
|
|
|
Mixed data instances |
664
|
|
|
|
|
|
|
|
665
|
|
|
|
|
|
|
Multiple mixed instances of C<--data>, C<--data-ascii>, C<--data-raw>, |
666
|
|
|
|
|
|
|
C<--data-binary> or C<--data-raw> are sorted by type first instead of getting |
667
|
|
|
|
|
|
|
concatenated in the order they appear on the command line. |
668
|
|
|
|
|
|
|
If the order is important to you, use one type only. |
669
|
|
|
|
|
|
|
|
670
|
|
|
|
|
|
|
=item * |
671
|
|
|
|
|
|
|
|
672
|
|
|
|
|
|
|
Multiple sets of parameters from the command line |
673
|
|
|
|
|
|
|
|
674
|
|
|
|
|
|
|
Curl supports the C<< --next >> command line switch which resets |
675
|
|
|
|
|
|
|
parameters for the next URL. |
676
|
|
|
|
|
|
|
|
677
|
|
|
|
|
|
|
This is not (yet) supported. |
678
|
|
|
|
|
|
|
|
679
|
|
|
|
|
|
|
=back |
680
|
|
|
|
|
|
|
|
681
|
|
|
|
|
|
|
=head1 SEE ALSO |
682
|
|
|
|
|
|
|
|
683
|
|
|
|
|
|
|
L |
684
|
|
|
|
|
|
|
|
685
|
|
|
|
|
|
|
L |
686
|
|
|
|
|
|
|
|
687
|
|
|
|
|
|
|
L |
688
|
|
|
|
|
|
|
|
689
|
|
|
|
|
|
|
L - for the inverse function |
690
|
|
|
|
|
|
|
|
691
|
|
|
|
|
|
|
The module HTTP::Request::AsCurl likely also implements a much better version |
692
|
|
|
|
|
|
|
of C<< ->as_curl >> than this module. |
693
|
|
|
|
|
|
|
|
694
|
|
|
|
|
|
|
L - a converter for multiple |
695
|
|
|
|
|
|
|
target languages |
696
|
|
|
|
|
|
|
|
697
|
|
|
|
|
|
|
L |
698
|
|
|
|
|
|
|
|
699
|
|
|
|
|
|
|
=head1 REPOSITORY |
700
|
|
|
|
|
|
|
|
701
|
|
|
|
|
|
|
The public repository of this module is |
702
|
|
|
|
|
|
|
L. |
703
|
|
|
|
|
|
|
|
704
|
|
|
|
|
|
|
=head1 SUPPORT |
705
|
|
|
|
|
|
|
|
706
|
|
|
|
|
|
|
The public support forum of this module is |
707
|
|
|
|
|
|
|
L. |
708
|
|
|
|
|
|
|
|
709
|
|
|
|
|
|
|
=head1 BUG TRACKER |
710
|
|
|
|
|
|
|
|
711
|
|
|
|
|
|
|
Please report bugs in this module via the Github bug queue at |
712
|
|
|
|
|
|
|
L |
713
|
|
|
|
|
|
|
|
714
|
|
|
|
|
|
|
=head1 AUTHOR |
715
|
|
|
|
|
|
|
|
716
|
|
|
|
|
|
|
Max Maischein C |
717
|
|
|
|
|
|
|
|
718
|
|
|
|
|
|
|
=head1 COPYRIGHT (c) |
719
|
|
|
|
|
|
|
|
720
|
|
|
|
|
|
|
Copyright 2018-2023 by Max Maischein C. |
721
|
|
|
|
|
|
|
|
722
|
|
|
|
|
|
|
=head1 LICENSE |
723
|
|
|
|
|
|
|
|
724
|
|
|
|
|
|
|
This module is released under the same terms as Perl itself. |
725
|
|
|
|
|
|
|
|
726
|
|
|
|
|
|
|
=cut |