1 package Net::HTTPS::Any;
5 use base qw( Exporter );
6 use vars qw(@EXPORT_OK $ssl_module $skip_NetSSLeay);
10 @EXPORT_OK = qw( https_get https_post );
17 die if defined($skip_NetSSLeay) && $skip_NetSSLeay;
19 Net::SSLeay->VERSION(1.30);
22 # qw(get_https post_https make_form make_headers);
23 $ssl_module = 'Net::SSLeay';
28 require LWP::UserAgent;
29 require HTTP::Request::Common;
30 require Crypt::SSLeay;
32 #import HTTP::Request::Common qw(GET POST);
33 $ssl_module = 'Crypt::SSLeay';
37 unless ($ssl_module) {
38 die "One of Net::SSLeay (v1.30 or later)"
39 . " or Crypt::SSLeay (+LWP) is required";
46 Net::HTTPS::Any - Simple HTTPS client using whichever underlying SSL module is available
50 our $VERSION = '0.11';
54 use Net::HTTPS::Any qw(https_get https_post);
56 ( $page, $response, %reply_headers )
58 { 'host' => 'www.fortify.net',
60 'path' => '/sslcheck.html',
61 'args' => { 'field' => 'value' },
62 #'args' => [ 'field'=>'value' ], #order preserved
66 ( $page, $response, %reply_headers )
68 'host' => 'www.google.com',
70 'path' => '/accounts/ServiceLoginAuth',
71 'args' => { 'field' => 'value' },
72 #'args' => [ 'field'=>'value' ], #order preserved
79 This is a simple wrapper around either of the two available SSL
80 modules. It offers a unified API for sending GET and POST requests over HTTPS
81 and receiving responses.
83 It depends on Net::SSLeay _or_ ( Crypt::SSLeay and LWP::UserAgent ).
85 =head1 WHY THIS MODULE
87 If you just want to write something that speaks HTTPS, you don't need this
88 module. Just go ahead and use whichever of the two modules is good for you.
91 On the other hand, if you are a CPAN author or distribute a Perl application,
92 especially if you aim to support multiple OSes/disributions, using this module
93 for speaking HTTPS may make things easier on your users. It allows your code
94 to be used with either SSL implementation.
98 Using LWP::Protocol::https 6.02 or later, the LWP path actually uses
99 Net::SSLeay also instead of Crypt::SSLeay. Going forward that makes this
100 module more of historical interest, especially so since modern LWP has its own
101 mechanism to force use of Crypt::SSLeay:
102 $Net::HTTPS::SSL_SOCKET_CLASS = "Net::SSL";
104 Therefore this module will likely eventually become a wrapper around a single
105 codepath, driven by the conservative needs of Business::OnlinePayment::HTTPS.
109 =head2 https_get HASHREF | FIELD => VALUE, ...
111 Accepts parameters as either a hashref or a list of fields and values.
123 =item headers (hashref)
125 For example: { 'X-Header1' => 'value', ... }
131 # Defaults to "application/x-www-form-urlencoded" if not specified.
135 CGI arguments, either as a hashref or a listref. In the latter case, ordering
136 is preserved (see L<Tie::IxHash> to do so when passing a hashref).
140 Set true to enable debugging.
144 Returns a list consisting of the page content as a string, the HTTP
145 response code and message (i.e. "200 OK" or "404 Not Found"), and a list of
146 key/value pairs representing the HTTP response headers.
151 my $opts = ref($_[0]) ? shift : { @_ }; #hashref or list
153 # accept a hashref or a list (keep it ordered)
154 my $post_data = {}; # technically get_data, pedant
155 if ( exists($opts->{'args'}) && ref($opts->{'args'}) eq 'HASH' ) {
156 $post_data = $opts->{'args'};
157 } elsif ( exists($opts->{'args'}) && ref($opts->{'args'}) eq 'ARRAY' ) {
158 tie my %hash, 'Tie::IxHash', @{ $opts->{'args'} };
162 $opts->{'port'} ||= 443;
163 #$opts->{"Content-Type"} ||= "application/x-www-form-urlencoded";
167 if ( ref( $opts->{headers} ) eq "HASH" ) {
168 %headers = %{ $opts->{headers} };
170 $headers{'Host'} ||= $opts->{'host'};
172 my $path = $opts->{'path'};
173 if ( keys %$post_data ) {
176 map { uri_escape($_) . '=' . uri_escape( $post_data->{$_} ) }
180 if ( $ssl_module eq 'Net::SSLeay' ) {
182 no warnings 'uninitialized';
184 import Net::SSLeay qw(get_https make_headers);
185 my $headers = make_headers(%headers);
187 $Net::SSLeay::trace = $opts->{'debug'}
188 if exists $opts->{'debug'} && $opts->{'debug'};
190 my( $res_page, $res_code, @res_headers ) =
191 get_https( $opts->{'host'},
196 #$opts->{"Content-Type"},
199 $res_code =~ /^(HTTP\S+ )?(.*)/ and $res_code = $2;
201 return ( $res_page, $res_code, @res_headers );
203 } elsif ( $ssl_module eq 'Crypt::SSLeay' ) {
205 import HTTP::Request::Common qw(GET);
207 my $url = 'https://' . $opts->{'host'};
208 $url .= ':' . $opts->{'port'}
209 unless $opts->{'port'} == 443;
212 my $ua = new LWP::UserAgent;
213 foreach my $hdr ( keys %headers ) {
214 $ua->default_header( $hdr => $headers{$hdr} );
216 $ENV{HTTPS_DEBUG} = $opts->{'debug'} if exists $opts->{'debug'};
217 my $res = $ua->request( GET($url) );
219 my @res_headers = map { $_ => $res->header($_) }
220 $res->header_field_names;
222 return ( $res->content, $res->code. ' '. $res->message, @res_headers );
225 die "unknown SSL module $ssl_module";
230 =head2 https_post HASHREF | FIELD => VALUE, ...
232 Accepts parameters as either a hashref or a list of fields and values.
244 =item headers (hashref)
246 For example: { 'X-Header1' => 'value', ... }
250 Defaults to "application/x-www-form-urlencoded" if not specified.
254 CGI arguments, either as a hashref or a listref. In the latter case, ordering
255 is preserved (see L<Tie::IxHash> to do so when passing a hashref).
259 Raw content (overrides args). A simple scalar containing the raw content.
263 Set true to enable debugging in the underlying SSL module.
267 Returns a list consisting of the page content as a string, the HTTP
268 response code and message (i.e. "200 OK" or "404 Not Found"), and a list of
269 key/value pairs representing the HTTP response headers.
274 my $opts = ref($_[0]) ? shift : { @_ }; #hashref or list
276 # accept a hashref or a list (keep it ordered). or a scalar of content.
278 if ( exists($opts->{'args'}) && ref($opts->{'args'}) eq 'HASH' ) {
279 $post_data = $opts->{'args'};
280 } elsif ( exists($opts->{'args'}) && ref($opts->{'args'}) eq 'ARRAY' ) {
281 tie my %hash, 'Tie::IxHash', @{ $opts->{'args'} };
284 if ( exists $opts->{'content'} ) {
285 $post_data = $opts->{'content'};
288 $opts->{'port'} ||= 443;
289 $opts->{"Content-Type"} ||= "application/x-www-form-urlencoded";
293 if ( ref( $opts->{headers} ) eq "HASH" ) {
294 %headers = %{ $opts->{headers} };
296 $headers{'Host'} ||= $opts->{'host'};
298 if ( $ssl_module eq 'Net::SSLeay' ) {
300 no warnings 'uninitialized';
302 import Net::SSLeay qw(post_https make_headers make_form);
303 my $headers = make_headers(%headers);
305 $Net::SSLeay::trace = $opts->{'debug'}
306 if exists $opts->{'debug'} && $opts->{'debug'};
308 my $raw_data = ref($post_data) ? make_form(%$post_data) : $post_data;
310 $Net::SSLeay::trace = $opts->{'debug'}
311 if exists $opts->{'debug'} && $opts->{'debug'};
313 my( $res_page, $res_code, @res_headers ) =
314 post_https( $opts->{'host'},
319 $opts->{"Content-Type"},
322 $res_code =~ /^(HTTP\S+ )?(.*)/ and $res_code = $2;
324 return ( $res_page, $res_code, @res_headers );
326 } elsif ( $ssl_module eq 'Crypt::SSLeay' ) {
328 import HTTP::Request::Common qw(POST);
330 my $url = 'https://' . $opts->{'host'};
331 $url .= ':' . $opts->{'port'}
332 unless $opts->{'port'} == 443;
333 $url .= $opts->{'path'};
335 my $ua = new LWP::UserAgent;
336 foreach my $hdr ( keys %headers ) {
337 $ua->default_header( $hdr => $headers{$hdr} );
340 $ENV{HTTPS_DEBUG} = $opts->{'debug'} if exists $opts->{'debug'};
343 if ( ref($post_data) ) {
344 $res = $ua->request( POST( $url, [%$post_data] ) );
347 my $req = new HTTP::Request( 'POST' => $url );
348 $req->content_type( $opts->{"Content-Type"} );
349 $req->content($post_data);
350 $res = $ua->request($req);
353 my @res_headers = map { $_ => $res->header($_) }
354 $res->header_field_names;
356 return ( $res->content, $res->code. ' '. $res->message, @res_headers );
359 die "unknown SSL module $ssl_module";
366 Ivan Kohler, C<< <ivan-net-https-any at freeside.biz> >>
370 Please report any bugs or feature requests to C<bug-net-https-any at rt.cpan.org>, or through
371 the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Net-HTTPS-Any>. I will be notified, and then you'll
372 automatically be notified of progress on your bug as I make changes.
376 You can find documentation for this module with the perldoc command.
378 perldoc Net::HTTPS::Any
380 You can also look for information at:
384 =item * RT: CPAN's request tracker
386 L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Net-HTTPS-Any>
388 =item * AnnoCPAN: Annotated CPAN documentation
390 L<http://annocpan.org/dist/Net-HTTPS-Any>
394 L<http://cpanratings.perl.org/d/Net-HTTPS-Any>
398 L<http://search.cpan.org/dist/Net-HTTPS-Any>
402 =head1 COPYRIGHT & LICENSE
404 Copyright 2008-2014 Freeside Internet Services, Inc. (http://freeside.biz/)
407 This program is free software; you can redistribute it and/or modify it
408 under the same terms as Perl itself.