File Coverage

blib/lib/HTTP/Size.pm
Criterion Covered Total %
statement 24 73 32.8
branch 0 20 0.0
condition 0 13 0.0
subroutine 8 12 66.6
pod 1 1 100.0
total 33 119 27.7


line stmt bran cond sub pod time code
1             package HTTP::Size;
2 1     1   502 use strict;
  1         1  
  1         25  
3 1     1   3 use warnings;
  1         1  
  1         25  
4 1     1   10 no warnings;
  1         1  
  1         42  
5              
6             =encoding utf8
7              
8             =head1 NAME
9              
10             HTTP::Size - Get the byte size of an internet resource
11              
12             =head1 SYNOPSIS
13              
14             use HTTP::Size
15              
16             my $size = HTTP::Size::get_size( $url );
17              
18             if( defined $size ) {
19             print "$url size was $size";
20             }
21             elsif( $HTTP::Size::ERROR == $HTTP::Size::INVALID_URL ) {
22             print "$url is not a valid absolute URL";
23             }
24             elsif( $HTTP::Size::ERROR == $HTTP::Size::COULD_NOT_FETCH ) {
25             print "Could not fetch $url\nHTTP status is $HTTP::Size::HTTP_STATUS";
26             }
27             elsif( $HTTP::Size::ERROR == $HTTP::Size::BAD_CONTENT_LENGTH ) {
28             print "Could not determine content length of $url";
29             }
30              
31             =head1 DESCRIPTION
32              
33             =head1 VARIABLES
34              
35             The following global variables describes conditions from the last
36             function call:
37              
38             $ERROR
39             $HTTP_STATUS
40              
41             The C<$ERROR> variable may be set to any of these values:
42              
43             $INVALID_URL - the URL is not a valid absolute URL
44             $COULD_NOT_FETCH - the function encountered an HTTP error
45             $BAD_CONTENT_LENGTH - could not determine a content type
46              
47             The module does not export these variables, so you need to use
48             the full package specification outside of the HTTP::Size
49             package.
50              
51             =cut
52              
53 1     1   533 use subs qw( get_size _request );
  1         22  
  1         4  
54 1         72 use vars qw(
55             $ERROR $HTTP_STATUS $VERSION
56             $INVALID_URL $COULD_NOT_FETCH $BAD_CONTENT_LENGTH
57             $CONTENT $CONTENT_TYPE
58 1     1   45 );
  1         1  
59              
60 1     1   975 use LWP::UserAgent;
  1         71030  
  1         72  
61 1     1   8 use URI;
  1         1  
  1         22  
62 1     1   4 use HTTP::Request;
  1         29  
  1         512  
63              
64             $VERSION = '1.15';
65              
66             my $User_agent = LWP::UserAgent->new();
67              
68             $INVALID_URL = -1;
69             $COULD_NOT_FETCH = -2;
70             $BAD_CONTENT_LENGTH = -3;
71              
72             =head1 FUNCTIONS
73              
74             =over 4
75              
76             =item get_size( URL )
77              
78             Fetch the specified absolute URL and return its content length.
79             The URL can be a string or an URI object. The function tries
80             the HEAD HTTP method first, and on failure, tries the GET method.
81             In either case it sets $HTTP_STATUS to the HTTP response code.
82             If the response does not contain a Content-Length header, the
83             function takes the size of the message body. If the HEAD method
84             returned a good status, but no Content-Length header, it retries
85             with the GET method.
86              
87             On error, the function set $ERROR to one of these values:
88              
89             $INVALID_URL - the URL is not a valid absolute URL
90             $COULD_NOT_FETCH - the function encountered an HTTP error
91             $BAD_CONTENT_LENGTH - could not determine a content type
92              
93             =cut
94              
95             sub get_size {
96 0     0     my $url = shift;
97 0   0       my $method = shift || 0;
98 0           _init();
99              
100 0 0         unless( ref $url eq 'URI' ) {
101 0           $url = URI->new( $url );
102             }
103              
104 0 0         unless( $url->scheme ) {
105 0           $ERROR = $INVALID_URL;
106 0           return;
107             };
108              
109 0           my $response = '';
110 0           my $size = 0;
111              
112 0 0         unless( $method ) {
113 0           my $request = HTTP::Request->new( HEAD => $url->as_string );
114              
115 0           $response = _request( $request );
116 0           $HTTP_STATUS = $response->code;
117 0           $size = $response->content_length;
118             }
119              
120 0 0 0       unless( not $method and $response->is_success and $size ) {
      0        
121 0           my $request = HTTP::Request->new( GET => $url->as_string );
122 0           $response = _request( $request );
123 0           $HTTP_STATUS = $response->code;
124 0           $CONTENT = $response->content;
125              
126 0 0         unless( $response->is_success ) {
    0          
    0          
127 0           $ERROR = $COULD_NOT_FETCH;
128 0           return;
129             }
130             elsif( not $response->content_length ) {
131 0           $size = length $CONTENT;
132             }
133             elsif( $response->content_length ) {
134 0           $size = $response->content_length;
135             }
136              
137             }
138              
139 0           $CONTENT_TYPE = lc $response->content_type;
140              
141 0           return $size;
142             }
143              
144             =item get_sizes( URL, BASE_URL )
145              
146             The get_sizes function is like get_size, although for HTML pages
147             it also fetches all of the images then sums the sizes of the
148             original page and image sizes. It returns a total download size.
149             In list context it returns the total download size and a hash
150             reference whose keys are the URLs that a browser should download
151             automatically (images):
152              
153             size
154             ERROR
155             HTTP_STATUS
156              
157             The ERROR and HTTP_STATUS correspond to the values of $ERROR and
158             $HTTP_STATUS for that URL.
159              
160             my ( $total, $hash ) = HTTP::Size::get_sizes( $url );
161              
162             foreach my $key ( keys %$hash )
163             {
164             print "$key had an error" unless defined $size;
165             }
166              
167             The hash is always returned in list context (a change from
168             version 0.4).
169              
170             Relative image links resolve accroding to BASE_URL, or by
171             a found BASE tag. See L.
172              
173             Javascript and style sheet links are unimplemented right now.
174              
175             =cut
176              
177             sub get_sizes {
178 0     0 1   my $url = shift;
179 0           my $base = shift;
180              
181 0           my %hash;
182              
183 0           my $size = get_size( $url, 'GET' );
184              
185 0           @{$hash{$url}}{ qw(size ERROR HTTP_STATUS) }
  0            
186             = ($size, $ERROR, $HTTP_STATUS);
187              
188 0 0 0       unless( $size and $CONTENT_TYPE eq 'text/html' ) {
189 0 0         return wantarray ? ( $size, \%hash ) : $size;
190             }
191              
192 0           require HTML::SimpleLinkExtor;
193              
194 0           my $total = $size;
195              
196 0           my $extor = HTML::SimpleLinkExtor->new( $url );
197              
198 0           $extor->parse( $CONTENT );
199              
200 0           foreach my $img ( $extor->img ) {
201 0   0       my $size = get_size( $img ) || 0;
202              
203 0           @{$hash{$img}}{ qw(size ERROR HTTP_STATUS) }
  0            
204             = ( $size, $ERROR, $HTTP_STATUS );
205              
206 0           $total += $size;
207             }
208              
209 0 0         return wantarray ? ( $total, \%hash ) : $total;
210             }
211              
212             sub _init {
213 0     0     $ERROR = $CONTENT_TYPE = $CONTENT = $HTTP_STATUS = '';
214             }
215              
216             sub _request {
217 0     0     my $response = $User_agent->request( shift );
218              
219 0           $HTTP_STATUS = $response->code;
220              
221 0           return $response;
222             }
223              
224             =back
225              
226             =head1 TO DO
227              
228             * if i have to use GET, i should use Byte-Ranges to avoid
229             downloading the whole thing
230              
231             * add a way to specify Basic Auth credentials
232              
233             * download javascript and style sheets too.
234              
235             =head1 SEE ALSO
236              
237             L
238              
239             =head1 SOURCE AVAILABILITY
240              
241             This source is part of a GitHub project:
242              
243             https://github.com/briandfoy/http-size
244              
245             =head1 AUTHOR
246              
247             brian d foy, C<< >>
248              
249             =head1 COPYRIGHT AND LICENSE
250              
251             Copyright © 2000-2015, brian d foy . All rights reserved.
252              
253             This program is free software; you can redistribute it and/or modify
254             it under the same terms as Perl itself.
255              
256             =cut
257              
258             1;