File Coverage

blib/lib/WWW/Curl/Simple.pm
Criterion Covered Total %
statement 1 3 33.3
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 2 4 50.0


line stmt bran cond sub pod time code
1             package WWW::Curl::Simple;
2             {
3             $WWW::Curl::Simple::VERSION = '0.100191';
4             }
5             # ABSTRACT: A Simpler interface to WWW::Curl
6 3     3   77835 use Moose;
  0            
  0            
7              
8             use HTTP::Request;
9             use HTTP::Response;
10             use Carp qw/croak carp/;
11             use WWW::Curl::Simple::Request;
12             use WWW::Curl::Multi;
13             use WWW::Curl::Easy;
14             use Time::HiRes 1.9705 qw/nanosleep/;
15              
16             #use base 'LWP::Parallel::UserAgent';
17              
18             use namespace::clean -except => 'meta';
19              
20              
21              
22             sub request {
23             my ($self, $req) = @_;
24              
25             my $curl = WWW::Curl::Simple::Request->new(simple_ua => $self, request => $req);
26              
27             # Starts the actual request
28             return $curl->perform;
29             }
30              
31              
32              
33             sub get {
34             my ($self, $uri) = @_;
35             return $self->request(HTTP::Request->new(GET => $uri));
36             }
37              
38              
39             sub post {
40             my ($self, $uri, $form) = @_;
41              
42             return $self->request(HTTP::Request->new(POST => $uri, undef, $form));
43             }
44              
45              
46              
47             has _requests => (
48             traits => ['Array'],
49             is => 'ro',
50             isa => 'ArrayRef[WWW::Curl::Simple::Request]',
51             handles => {
52             _add_request => 'push',
53             requests => 'elements',
54             _find_request => 'first',
55             _count_requests => 'count',
56             _get_request => 'get',
57             _delete_request => 'delete',
58             },
59             default => sub { [] },
60             );
61              
62             sub add_request {
63             my ($self, $req) = @_;
64             $req = WWW::Curl::Simple::Request->new(simple_ua => $self, request => $req);
65             $self->_add_request($req);
66              
67             return $req;
68             }
69              
70              
71             __PACKAGE__->meta->add_package_symbol('&register',
72             __PACKAGE__->meta->get_package_symbol('&add_request')
73             );
74              
75              
76             sub has_request {
77             my ($self, $req) = @_;
78              
79             $self->_find_request(sub {
80             $_ == $req
81             });
82             }
83              
84              
85             sub delete_request {
86             my ($self, $req) = @_;
87              
88             return unless $self->has_request($req);
89             # need to find the index
90             my $c = $self->_count_requests;
91              
92             while ($c--) {
93             $self->_delete_request($c) if ($self->_get_request($c) == $req);
94             }
95             return 1;
96             }
97              
98              
99              
100             sub perform {
101             my ($self) = @_;
102              
103             my $curlm = WWW::Curl::Multi->new;
104              
105             my %reqs;
106             my $i = 0;
107             foreach my $req ($self->requests) {
108             $i++;
109             my $curl = $req->easy;
110             # we set this so we have the ref later on
111             $curl->setopt(CURLOPT_PRIVATE, $i);
112              
113             # here we also mangle all requests based on options
114             # XXX: Should re-factor this to be a metaclass/trait on the attributes,
115             # and a general method that takes all those and applies the proper setopt
116             # calls
117             if ($self->timeout_ms) {
118             unless ($WWW::Curl::Easy::CURLOPT_TIMEOUT_MS) {
119             croak( "Your trying to use timeout_ms, but your libcurl is apperantly older than 7.16.12.");
120             }
121             $curl->setopt($WWW::Curl::Easy::CURLOPT_TIMEOUT_MS, $self->timeout_ms) if $self->timeout_ms;
122             $curl->setopt($WWW::Curl::Easy::CURLOPT_CONNECTTIMEOUT_MS, $self->connection_timeout_ms) if $self->connection_timeout_ms;
123             } else {
124             $curl->setopt(CURLOPT_TIMEOUT, $self->timeout) if $self->timeout;
125             $curl->setopt(CURLOPT_CONNECTTIMEOUT, $self->connection_timeout) if $self->connection_timeout;
126             }
127              
128             $curlm->add_handle($curl);
129              
130             $reqs{$i} = $req;
131             }
132             my @res;
133             while ($i) {
134             my $active_transfers = $curlm->perform;
135             if ($active_transfers != $i) {
136             while (my ($id,$retcode) = $curlm->info_read) {
137             if ($id) {
138             $i--;
139             my $req = $reqs{$id};
140             unless ($retcode == 0) {
141             my $err = "Error during handling of request: "
142             .$req->easy->strerror($retcode)." ". $req->request->uri;
143              
144             croak($err) if $self->fatal;
145             carp($err) unless $self->fatal;
146             }
147             push(@res, $req);
148             delete($reqs{$id});
149             }
150             }
151             }
152             # To prevent busy-looping
153             nanosleep(1);
154             }
155             return @res;
156             }
157              
158              
159              
160             sub wait {
161             my $self = shift;
162              
163             my @res = $self->perform(@_);
164              
165             # convert to a hash
166             my %res;
167              
168             while (my $r = pop @res) {
169             #warn "adding $r at " . scalar(@res);
170             $res{scalar(@res)} = $r;
171             }
172              
173             return \%res;
174             }
175              
176              
177              
178              
179              
180             has 'timeout' => (is => 'ro', isa => 'Int');
181             has 'timeout_ms' => (is => 'ro', isa => 'Int');
182              
183              
184             has 'max_redirects' => (is => 'ro', isa => 'Int', default => 5);
185              
186              
187             has 'check_ssl_certs' => (is => 'ro', isa => 'Int', default => 1);
188              
189              
190             has 'ssl_cert_bundle' => (is => 'ro', isa => 'Str', predicate => 'has_cacert');
191              
192              
193             has 'connection_timeout' => (is => 'ro', isa => 'Int');
194             has 'connection_timeout_ms' => (is => 'ro', isa => 'Int');
195              
196              
197              
198             has 'fatal' => (is => 'ro', isa => 'Bool', default => 1);
199              
200             __PACKAGE__->meta->make_immutable;
201              
202             1; # End of WWW::Curl::Simple
203              
204             __END__
205              
206             =pod
207              
208             =encoding UTF-8
209              
210             =head1 NAME
211              
212             WWW::Curl::Simple - A Simpler interface to WWW::Curl
213              
214             =head1 VERSION
215              
216             version 0.100191
217              
218             =head1 SYNOPSIS
219              
220             my $curl = WWW::Curl::Simple->new();
221              
222             my $res = $curl->get('http://www.google.com/');
223              
224             =head1 ATTRIBUTES
225              
226             =head2 timeout / timeout_ms
227              
228             Sets the timeout of individual requests, in seconds or milliseconds.
229              
230             =head2 max_redirects
231              
232             Sets the maximum number of redirects that should be transparently followed.
233             Set this to 0 if you don't want to follow redirects. Default: 5.
234              
235             =head2 check_ssl_certs
236              
237             Specifies whether the underlying Curl library should check SSL certificates
238             when making https requests. Defaults to 1 (i.e. do check certs, to err on safe side).
239              
240             =head2 ssl_cert_bundle
241              
242             Specifies the bundle to look for CA certificates in. Leave blank for system
243             default, which should work if your libcurl is properly compiled.
244              
245             =head2 connection_timeout /connection_timeout_ms
246              
247             Sets the timeout of the connect phase of requests, in seconds or milliseconds.
248              
249             =head2 fatal
250              
251             Defaults to true, but if set to false, it will make failure in multi-requests
252             warn instead of die.
253              
254             =head1 METHODS
255              
256             =head2 request($req)
257              
258             C<$req> should be a L<HTTP::Request> object.
259              
260             If you have a URI string or object, look at the C<get> method instead.
261             Returns a L<WWW::Curl::Simple::Request> object.
262              
263             =head2 get($uri || URI)
264              
265             Accepts one parameter, which should be a reference to a URI object or a
266             string representing a URI. Returns a L<HTTP::Response> object.
267              
268             =head2 post($uri || URI, $form)
269              
270             Creates a L<HTTP::Request> of type POST to C<$uri>, which can be a string
271             or a URI object, and sets the form of the request to C<$form>. See
272             L<HTTP::Request> for more information on the format of C<$form>.
273              
274             =head2 add_request($req)
275              
276             Adds C<$req> (a L<HTTP::Request> object) to the list of URLs to fetch. Returns
277             a L<WWW::Curl::Simple::Request> object.
278              
279             =head2 register($req)
280              
281             An alias for C<add_request>.
282              
283             =head2 has_request $request
284              
285             Will return true if C<$request> is one of the object's requests.
286              
287             =head2 delete_request $req
288              
289             Removes C<$req> from the object's list of requests.
290              
291             =head2 perform
292              
293             Does all the requests added with C<add_request> and returns a list of
294             L<WWW::Curl::Simple::Request> objects.
295              
296             =head2 wait
297              
298             This method is here to provide an easier transition from
299             L<LWP::Parallel::UserAgent>. It is by no means a drop in replacement, but using
300             C<wait> instead of C<perform> makes the return value more like that of LWP::UA.
301              
302             =head1 AUTHOR
303              
304             Andreas Marienborg <andremar@cpan.org>
305              
306             =head1 CONTRIBUTORS
307              
308             =over 4
309              
310             =item *
311              
312             Bjørn-Olav Strand <bo@startsiden.no>
313              
314             =item *
315              
316             Graham Knop <haarg@haarg.org>
317              
318             =item *
319              
320             Marcus Ramberg <marcus@nordaaker.com>
321              
322             =item *
323              
324             Neil Bowers <neil@bowers.com>
325              
326             =item *
327              
328             chromatic <chromatic@wgz.org>
329              
330             =back
331              
332             =head1 COPYRIGHT AND LICENSE
333              
334             This software is copyright (c) 2013 by Andreas Marienborg.
335              
336             This is free software; you can redistribute it and/or modify it under
337             the same terms as the Perl 5 programming language system itself.
338              
339             =cut