File Coverage

blib/lib/Net/HTTPS/Any.pm
Criterion Covered Total %
statement 67 119 56.3
branch 19 56 33.9
condition 12 36 33.3
subroutine 11 11 100.0
pod 2 2 100.0
total 111 224 49.5


line stmt bran cond sub pod time code
1             package Net::HTTPS::Any;
2              
3 3     3   79856 use warnings;
  3         7  
  3         109  
4 3     3   20 use strict;
  3         7  
  3         127  
5 3     3   74 use base qw( Exporter );
  3         10  
  3         336  
6 3     3   14 use vars qw(@EXPORT_OK $ssl_module $skip_NetSSLeay);
  3         5  
  3         212  
7 3     3   2729 use URI::Escape;
  3         9972  
  3         257  
8 3     3   2689 use Tie::IxHash;
  3         18626  
  3         3286  
9              
10             @EXPORT_OK = qw( https_get https_post );
11              
12             BEGIN {
13              
14 3     3   9 $ssl_module = '';
15              
16 3         6 eval {
17 3 0 33     16 die if defined($skip_NetSSLeay) && $skip_NetSSLeay;
18 3         3599 require Net::SSLeay;
19 3         66737 Net::SSLeay->VERSION(1.30);
20              
21             #import Net::SSLeay
22             # qw(get_https post_https make_form make_headers);
23 3         19 $ssl_module = 'Net::SSLeay';
24             };
25              
26 3 50       277 if ($@) {
27 0         0 eval {
28 0         0 require LWP::UserAgent;
29 0         0 require HTTP::Request::Common;
30 0         0 require Crypt::SSLeay;
31              
32             #import HTTP::Request::Common qw(GET POST);
33 0         0 $ssl_module = 'Crypt::SSLeay';
34             };
35             }
36              
37 3 50       1086 unless ($ssl_module) {
38 0         0 die "One of Net::SSLeay (v1.30 or later)"
39             . " or Crypt::SSLeay (+LWP) is required";
40             }
41              
42             }
43              
44             =head1 NAME
45              
46             Net::HTTPS::Any - Simple HTTPS client using whichever underlying SSL module is available
47              
48             =cut
49              
50             our $VERSION = '0.11';
51              
52             =head1 SYNOPSIS
53              
54             use Net::HTTPS::Any qw(https_get https_post);
55            
56             ( $page, $response, %reply_headers )
57             = https_get(
58             { 'host' => 'www.fortify.net',
59             'port' => 443,
60             'path' => '/sslcheck.html',
61             'args' => { 'field' => 'value' },
62             #'args' => [ 'field'=>'value' ], #order preserved
63             },
64             );
65              
66             ( $page, $response, %reply_headers )
67             = https_post(
68             'host' => 'www.google.com',
69             'port' => 443,
70             'path' => '/accounts/ServiceLoginAuth',
71             'args' => { 'field' => 'value' },
72             #'args' => [ 'field'=>'value' ], #order preserved
73             );
74            
75             #...
76              
77             =head1 DESCRIPTION
78              
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.
82              
83             It depends on Net::SSLeay _or_ ( Crypt::SSLeay and LWP::UserAgent ).
84              
85             =head1 WHY THIS MODULE
86              
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.
89             Don't worry about it.
90              
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.
95              
96             =head1 FUTURE
97              
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";
103              
104             Therefore this module will likely eventually become a wrapper around a single
105             codepath, driven by the conservative needs of Business::OnlinePayment::HTTPS.
106              
107             =head1 FUNCTIONS
108              
109             =head2 https_get HASHREF | FIELD => VALUE, ...
110              
111             Accepts parameters as either a hashref or a list of fields and values.
112              
113             Parameters are:
114              
115             =over 4
116              
117             =item host
118              
119             =item port
120              
121             =item path
122              
123             =item headers (hashref)
124              
125             For example: { 'X-Header1' => 'value', ... }
126              
127             =cut
128              
129             # =item Content-Type
130             #
131             # Defaults to "application/x-www-form-urlencoded" if not specified.
132              
133             =item args
134              
135             CGI arguments, either as a hashref or a listref. In the latter case, ordering
136             is preserved (see L to do so when passing a hashref).
137              
138             =item debug
139              
140             Set true to enable debugging.
141              
142             =back
143              
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.
147              
148             =cut
149              
150             sub https_get {
151 2 50   2 1 993 my $opts = ref($_[0]) ? shift : { @_ }; #hashref or list
152              
153             # accept a hashref or a list (keep it ordered)
154 2         6 my $post_data = {}; # technically get_data, pedant
155 2 50 33     28 if ( exists($opts->{'args'}) && ref($opts->{'args'}) eq 'HASH' ) {
    50 33        
156 0         0 $post_data = $opts->{'args'};
157             } elsif ( exists($opts->{'args'}) && ref($opts->{'args'}) eq 'ARRAY' ) {
158 0         0 tie my %hash, 'Tie::IxHash', @{ $opts->{'args'} };
  0         0  
159 0         0 $post_data = \%hash;
160             }
161              
162 2   50     9 $opts->{'port'} ||= 443;
163             #$opts->{"Content-Type"} ||= "application/x-www-form-urlencoded";
164              
165             ### XXX referer!!!
166 2         7 my %headers = ();
167 2 50       8 if ( ref( $opts->{headers} ) eq "HASH" ) {
168 0         0 %headers = %{ $opts->{headers} };
  0         0  
169             }
170 2   33     17 $headers{'Host'} ||= $opts->{'host'};
171              
172 2         5 my $path = $opts->{'path'};
173 2 50       10 if ( keys %$post_data ) {
174 0         0 $path .= '?'
175             . join( ';',
176 0         0 map { uri_escape($_) . '=' . uri_escape( $post_data->{$_} ) }
177             keys %$post_data );
178             }
179              
180 2 50       9 if ( $ssl_module eq 'Net::SSLeay' ) {
    0          
181              
182 3     3   36 no warnings 'uninitialized';
  3         30  
  3         2213  
183              
184 2         1220 import Net::SSLeay qw(get_https make_headers);
185 2         46 my $headers = make_headers(%headers);
186              
187 2 50 33     1055 $Net::SSLeay::trace = $opts->{'debug'}
188             if exists $opts->{'debug'} && $opts->{'debug'};
189              
190 2         37 my( $res_page, $res_code, @res_headers ) =
191             get_https( $opts->{'host'},
192             $opts->{'port'},
193             $path,
194             $headers,
195             #"",
196             #$opts->{"Content-Type"},
197             );
198              
199 2 50       1211612 $res_code =~ /^(HTTP\S+ )?(.*)/ and $res_code = $2;
200              
201 2         45 return ( $res_page, $res_code, @res_headers );
202              
203             } elsif ( $ssl_module eq 'Crypt::SSLeay' ) {
204              
205 0         0 import HTTP::Request::Common qw(GET);
206              
207 0         0 my $url = 'https://' . $opts->{'host'};
208 0 0       0 $url .= ':' . $opts->{'port'}
209             unless $opts->{'port'} == 443;
210 0         0 $url .= "/$path";
211              
212 0         0 my $ua = new LWP::UserAgent;
213 0         0 foreach my $hdr ( keys %headers ) {
214 0         0 $ua->default_header( $hdr => $headers{$hdr} );
215             }
216 0 0       0 $ENV{HTTPS_DEBUG} = $opts->{'debug'} if exists $opts->{'debug'};
217 0         0 my $res = $ua->request( GET($url) );
218              
219 0         0 my @res_headers = map { $_ => $res->header($_) }
  0         0  
220             $res->header_field_names;
221              
222 0         0 return ( $res->content, $res->code. ' '. $res->message, @res_headers );
223              
224             } else {
225 0         0 die "unknown SSL module $ssl_module";
226             }
227              
228             }
229              
230             =head2 https_post HASHREF | FIELD => VALUE, ...
231              
232             Accepts parameters as either a hashref or a list of fields and values.
233              
234             Parameters are:
235              
236             =over 4
237              
238             =item host
239              
240             =item port
241              
242             =item path
243              
244             =item headers (hashref)
245              
246             For example: { 'X-Header1' => 'value', ... }
247              
248             =item Content-Type
249              
250             Defaults to "application/x-www-form-urlencoded" if not specified.
251              
252             =item args
253              
254             CGI arguments, either as a hashref or a listref. In the latter case, ordering
255             is preserved (see L to do so when passing a hashref).
256              
257             =item content
258              
259             Raw content (overrides args). A simple scalar containing the raw content.
260              
261             =item debug
262              
263             Set true to enable debugging in the underlying SSL module.
264              
265             =back
266              
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.
270              
271             =cut
272              
273             sub https_post {
274 2 50   2 1 1409 my $opts = ref($_[0]) ? shift : { @_ }; #hashref or list
275              
276             # accept a hashref or a list (keep it ordered). or a scalar of content.
277 2         5 my $post_data = '';
278 2 50 33     19 if ( exists($opts->{'args'}) && ref($opts->{'args'}) eq 'HASH' ) {
    0 0        
279 2         5 $post_data = $opts->{'args'};
280             } elsif ( exists($opts->{'args'}) && ref($opts->{'args'}) eq 'ARRAY' ) {
281 0         0 tie my %hash, 'Tie::IxHash', @{ $opts->{'args'} };
  0         0  
282 0         0 $post_data = \%hash;
283             }
284 2 50       9 if ( exists $opts->{'content'} ) {
285 0         0 $post_data = $opts->{'content'};
286             }
287              
288 2   50     6 $opts->{'port'} ||= 443;
289 2   50     12 $opts->{"Content-Type"} ||= "application/x-www-form-urlencoded";
290              
291             ### XXX referer!!!
292 2         4 my %headers;
293 2 50       8 if ( ref( $opts->{headers} ) eq "HASH" ) {
294 0         0 %headers = %{ $opts->{headers} };
  0         0  
295             }
296 2   33     11 $headers{'Host'} ||= $opts->{'host'};
297              
298 2 50       6 if ( $ssl_module eq 'Net::SSLeay' ) {
    0          
299            
300 3     3   27 no warnings 'uninitialized';
  3         6  
  3         11450  
301              
302 2         615 import Net::SSLeay qw(post_https make_headers make_form);
303 2         41 my $headers = make_headers(%headers);
304              
305 2 50 33     690 $Net::SSLeay::trace = $opts->{'debug'}
306             if exists $opts->{'debug'} && $opts->{'debug'};
307              
308 2 50       35 my $raw_data = ref($post_data) ? make_form(%$post_data) : $post_data;
309              
310 2 50 33     463 $Net::SSLeay::trace = $opts->{'debug'}
311             if exists $opts->{'debug'} && $opts->{'debug'};
312              
313 2         35 my( $res_page, $res_code, @res_headers ) =
314             post_https( $opts->{'host'},
315             $opts->{'port'},
316             $opts->{'path'},
317             $headers,
318             $raw_data,
319             $opts->{"Content-Type"},
320             );
321              
322 2 50       274926 $res_code =~ /^(HTTP\S+ )?(.*)/ and $res_code = $2;
323              
324 2         99 return ( $res_page, $res_code, @res_headers );
325              
326             } elsif ( $ssl_module eq 'Crypt::SSLeay' ) {
327              
328 0           import HTTP::Request::Common qw(POST);
329              
330 0           my $url = 'https://' . $opts->{'host'};
331 0 0         $url .= ':' . $opts->{'port'}
332             unless $opts->{'port'} == 443;
333 0           $url .= $opts->{'path'};
334              
335 0           my $ua = new LWP::UserAgent;
336 0           foreach my $hdr ( keys %headers ) {
337 0           $ua->default_header( $hdr => $headers{$hdr} );
338             }
339              
340 0 0         $ENV{HTTPS_DEBUG} = $opts->{'debug'} if exists $opts->{'debug'};
341              
342 0           my $res;
343 0 0         if ( ref($post_data) ) {
344 0           $res = $ua->request( POST( $url, [%$post_data] ) );
345             }
346             else {
347 0           my $req = new HTTP::Request( 'POST' => $url );
348 0           $req->content_type( $opts->{"Content-Type"} );
349 0           $req->content($post_data);
350 0           $res = $ua->request($req);
351             }
352              
353 0           my @res_headers = map { $_ => $res->header($_) }
  0            
354             $res->header_field_names;
355              
356 0           return ( $res->content, $res->code. ' '. $res->message, @res_headers );
357              
358             } else {
359 0           die "unknown SSL module $ssl_module";
360             }
361              
362             }
363              
364             =head1 AUTHOR
365              
366             Ivan Kohler, C<< >>
367              
368             =head1 BUGS
369              
370             Please report any bugs or feature requests to C, or through
371             the web interface at L. I will be notified, and then you'll
372             automatically be notified of progress on your bug as I make changes.
373              
374             =head1 SUPPORT
375              
376             You can find documentation for this module with the perldoc command.
377              
378             perldoc Net::HTTPS::Any
379              
380             You can also look for information at:
381              
382             =over 4
383              
384             =item * RT: CPAN's request tracker
385              
386             L
387              
388             =item * AnnoCPAN: Annotated CPAN documentation
389              
390             L
391              
392             =item * CPAN Ratings
393              
394             L
395              
396             =item * Search CPAN
397              
398             L
399              
400             =back
401              
402             =head1 COPYRIGHT & LICENSE
403              
404             Copyright 2008-2014 Freeside Internet Services, Inc. (http://freeside.biz/)
405             All rights reserved.
406              
407             This program is free software; you can redistribute it and/or modify it
408             under the same terms as Perl itself.
409              
410             =cut
411              
412             1;