File Coverage

blib/lib/HTTP/Size.pm
Criterion Covered Total %
statement 70 73 95.8
branch 12 18 66.6
condition 10 16 62.5
subroutine 12 12 100.0
pod 1 1 100.0
total 105 120 87.5


line stmt bran cond sub pod time code
1             package HTTP::Size;
2 2     2   1012 use strict;
  2         3  
  2         40  
3 2     2   6 use warnings;
  2         3  
  2         34  
4 2     2   6 no warnings;
  2         3  
  2         75  
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 2     2   775 use subs qw( get_size _request );
  2         34  
  2         7  
54 2         162 use vars qw(
55             $ERROR $HTTP_STATUS $VERSION
56             $INVALID_URL $COULD_NOT_FETCH $BAD_CONTENT_LENGTH
57             $CONTENT $CONTENT_TYPE
58 2     2   133 );
  2         3  
59              
60 2     2   962 use LWP::UserAgent;
  2         66783  
  2         51  
61 2     2   14 use URI;
  2         3  
  2         33  
62 2     2   8 use HTTP::Request;
  2         2  
  2         737  
63              
64             $VERSION = '1.151';
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 9     9   841598 my $url = shift;
97 9   100     41 my $method = shift || 0;
98 9         30 _init();
99              
100 9 50       28 unless( ref $url eq 'URI' ) {
101 9         36 $url = URI->new( $url );
102             }
103              
104 9 100       3461 unless( $url->scheme ) {
105 2         71 $ERROR = $INVALID_URL;
106 2         7 return;
107             };
108              
109 7         110 my $response = '';
110 7         16 my $size = 0;
111              
112 7 100       21 unless( $method ) {
113 5         38 my $request = HTTP::Request->new( HEAD => $url->as_string );
114              
115 5         413 $response = _request( $request );
116 5         11 $HTTP_STATUS = $response->code;
117 5         45 $size = $response->content_length;
118             }
119              
120 7 100 100     155 unless( not $method and $response->is_success and $size ) {
      66        
121 4         46 my $request = HTTP::Request->new( GET => $url->as_string );
122 4         345 $response = _request( $request );
123 4         42 $HTTP_STATUS = $response->code;
124 4         41 $CONTENT = $response->content;
125              
126 4 50 33     51 unless( $response->is_success ) {
    100          
127 2         23 $ERROR = $COULD_NOT_FETCH;
128 2         21 return;
129             }
130 0         0 elsif( not $response->content_length ) {
131 0         0 $size = length $CONTENT;
132             }
133             elsif( $response->content_length ) {
134             $size = $response->content_length;
135             }
136              
137             }
138              
139 5         101 $CONTENT_TYPE = lc $response->content_type;
140              
141 5         139 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 2     2 1 1682 my $url = shift;
179 2         3 my $base = shift;
180              
181 2         4 my %hash;
182              
183 2         6 my $size = get_size( $url, 'GET' );
184              
185 2         5 @{$hash{$url}}{ qw(size ERROR HTTP_STATUS) }
  2         9  
186             = ($size, $ERROR, $HTTP_STATUS);
187              
188 2 50 33     24 unless( $size and $CONTENT_TYPE eq 'text/html' ) {
189 0 0       0 return wantarray ? ( $size, \%hash ) : $size;
190             }
191              
192 2         379 require HTML::SimpleLinkExtor;
193              
194 2         3955 my $total = $size;
195              
196 2         15 my $extor = HTML::SimpleLinkExtor->new( $url );
197              
198 2         743 $extor->parse( $CONTENT );
199              
200 2         482 foreach my $img ( $extor->img ) {
201 1   50     679 my $size = get_size( $img ) || 0;
202              
203 1         3 @{$hash{$img}}{ qw(size ERROR HTTP_STATUS) }
  1         3  
204             = ( $size, $ERROR, $HTTP_STATUS );
205              
206 1         6 $total += $size;
207             }
208              
209 2 50       5194 return wantarray ? ( $total, \%hash ) : $total;
210             }
211              
212             sub _init {
213 9     9   37 $ERROR = $CONTENT_TYPE = $CONTENT = $HTTP_STATUS = '';
214             }
215              
216             sub _request {
217 9     9   27 my $response = $User_agent->request( shift );
218              
219 9         1536570 $HTTP_STATUS = $response->code;
220              
221 9         74 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-2018, brian d foy . All rights reserved.
252              
253             This program is free software; you can redistribute it and/or modify
254             it under the terms of the Artistic License 2.0.
255              
256             =cut
257              
258             1;