HTTP-Request-FromCurl
view release on metacpan or search on metacpan
lib/HTTP/Request/FromCurl.pm view on Meta::CPAN
=item C< --junk-session-cookies >
If you want to keep session cookies between subsequent requests, you need to
provide a cookie jar in your user agent.
=item C<--next>
Resetting the UA between requests is something you need to handle yourself
=item C<--parallel>
=item C<--parallel-immediate>
=item C<--parallel-max>
Parallel requests is something you need to handle in the UA
=back
=cut
our @option_spec = (
'user-agent|A=s',
'verbose|v', # ignored
'show-error|S', # ignored
'fail|f', # ignored
'silent|s', # ignored
'anyauth', # ignored
'basic',
'buffer!',
'capath=s',
# 'cacert=s', # to be added
'cert|E=s', # this is the client certificate
'compressed',
'cookie|b=s',
'cookie-jar|c=s',
'data|d=s@',
'data-ascii=s@',
'data-binary=s@',
'data-raw=s@',
'data-urlencode=s@',
'digest',
'disable|q!', # ignored
'dump-header|D=s', # ignored
'referrer|e=s',
'form|F=s@',
'form-string=s@',
'get|G',
'globoff|g',
'head|I',
'header|H=s@',
'include|i', # ignored
'interface=s',
'insecure|k',
'json=s@',
'location|L', # ignored, we always follow redirects
'max-filesize=s',
'max-time|m=s',
'ntlm',
'keepalive!',
'range=s',
'request|X=s',
'oauth2-bearer=s',
'output|o=s',
'progress-bar|#', # ignored
'user|u=s',
'next', # ignored
'parallel|Z', # ignored
'parallel-immediate', # ignored
'parallel-max', # ignored
'junk-session-cookies|j', # ignored, must be set in code using the HTTP request
'unix-socket=s',
'url=s@',
);
sub new( $class, %options ) {
my $cmd = $options{ argv };
if( $options{ command }) {
require Text::ParseWords;
$cmd = [ Text::ParseWords::shellwords($options{ command }) ];
} elsif( $options{ command_curl }) {
require Text::ParseWords;
$cmd = [ Text::ParseWords::shellwords($options{ command_curl }) ];
# remove the implicit curl command:
shift @$cmd;
};
for (@$cmd) {
$_ = '--next'
if $_ eq '-:'; # GetOptions does not like "next|:" as specification
};
my $p = Getopt::Long::Parser->new(
config => [ 'bundling', 'no_auto_abbrev', 'no_ignore_case_always' ],
);
$p->getoptionsfromarray( $cmd,
\my %curl_options,
@option_spec,
) or return;
my @urls = (@$cmd, @{ $curl_options{ url } || [] });
return
wantarray ? map { $class->_build_request( $_, \%curl_options, %options ) } @urls
: ($class->_build_request( $urls[0], \%curl_options, %options ))[0]
;
}
=head1 METHODS
=head2 C<< ->squash_uri( $uri ) >>
my $uri = HTTP::Request::FromCurl->squash_uri(
URI->new( 'https://example.com/foo/bar/..' )
);
# https://example.com/foo/
Helper method to clean up relative path elements from the URI the same way
lib/HTTP/Request/FromCurl.pm view on Meta::CPAN
if( $options->{anyauth}
|| $options->{digest}
|| $options->{ntlm}
|| $options->{negotiate}
) {
# Nothing to do here, just let LWP::UserAgent do its thing
# This means one additional request to fetch the appropriate
# 401 response asking for credentials, but ...
} else {
# $options->{basic} or none at all
my $info = delete $options->{'user'};
# We need to bake this into the header here?!
push @headers, sprintf 'Authorization: Basic %s', encode_base64( $info );
}
};
my %headers;
for my $kv (
(map { /^\s*([^:\s]+)\s*:\s*(.*)$/ ? [$1 => $2] : () } @headers),) {
$self->_add_header( \%headers, @$kv );
};
if( defined $options->{ 'user-agent' }) {
$self->_add_header( \%headers, "User-Agent", $options->{ 'user-agent' } );
};
if( defined $options->{ referrer }) {
$self->_add_header( \%headers, "Referer" => $options->{ 'referrer' } );
};
if( defined $options->{ range }) {
$self->_add_header( \%headers, "Range" => $options->{ 'range' } );
};
# We want to compare the headers case-insensitively
my %headers_lc = map { lc $_ => 1 } keys %headers;
for my $k (keys %request_default_headers) {
if( ! $headers_lc{ lc $k }) {
$self->_add_header( \%headers, $k, $request_default_headers{ $k });
};
};
if( ! $headers{ 'Host' }) {
$self->_add_header( \%headers, 'Host' => $host );
};
if( defined $options->{ 'cookie-jar' }) {
$options->{'cookie-jar-options'}->{ 'write' } = 1;
};
if( defined( my $c = $options->{ cookie })) {
if( $c =~ /=/ ) {
$headers{ Cookie } = $options->{ 'cookie' };
} else {
$options->{'cookie-jar'} = $c;
$options->{'cookie-jar-options'}->{ 'read' } = 1;
};
};
# Curl 7.61.0 ignores these:
#if( $options->{ keepalive }) {
# $headers{ 'Keep-Alive' } = 1;
#} elsif( exists $options->{ keepalive }) {
# $headers{ 'Keep-Alive' } = 0;
#};
if( $options->{ compressed }) {
my $compressions = HTTP::Message::decodable();
$self->_add_header( \%headers, 'Accept-Encoding' => $compressions );
};
my $auth;
for my $kind (qw(basic ntlm negotiate)) {
if( $options->{$kind}) {
$auth = $kind;
}
};
push @res, HTTP::Request::CurlParameters->new({
method => $method,
uri => $uri,
headers => \%headers,
body => $body,
maybe auth => $auth,
maybe cert => $options->{cert},
maybe capath => $options->{capath},
maybe credentials => $options->{ user },
maybe output => $options->{ output },
maybe timeout => $options->{ 'max-time' },
maybe cookie_jar => $options->{'cookie-jar'},
maybe cookie_jar_options => $options->{'cookie-jar-options'},
maybe insecure => $options->{'insecure'},
maybe max_filesize => $options->{'max-filesize'},
maybe show_error => $options->{'show-error'},
maybe fail => $options->{'fail'},
maybe unix_socket => $options->{'unix-socket'},
maybe local_address => $options->{'interface'},
maybe form_args => scalar @form_args ? \@form_args : undef,
});
}
return @res
};
1;
=head1 LIVE DEMO
L<https://corion.net/curl2lwp.psgi>
=head1 KNOWN DIFFERENCES
=head2 Incompatible cookie jar formats
Until somebody writes a robust Netscape cookie file parser and proper loading
and storage for L<HTTP::CookieJar>, this module will not be able to load and
save files in the format that Curl uses.
=head2 Loading/saving cookie jars is the job of the UA
You're expected to instruct your UA to load/save cookie jars:
use Path::Tiny;
( run in 0.516 second using v1.01-cache-2.11-cpan-71847e10f99 )