File Coverage

blib/lib/WebSource/Fetcher.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package WebSource::Fetcher;
2              
3 1     1   2639 use strict;
  1         3  
  1         40  
4 1     1   6 use LWP::UserAgent;
  1         2  
  1         24  
5 1     1   4 use HTTP::Cookies;
  1         2  
  1         22  
6 1     1   43 use WebSource::Module;
  0            
  0            
7             use Carp;
8             eval "use Net::INET6Glue::INET_is_INET6"; # use Net::INET6Glue::INET_is_INET6 when available
9              
10             our @ISA = ('WebSource::Module');
11              
12             =head1 NAME
13              
14             WebSource::Fetcher : fetching module
15             When run downloads given urls and returns the corresponding http response
16            
17             =head1 DESCRIPTION
18              
19             A fetch operator is declared with the following format :
20              
21            
22              
23              
24             =head1 SYNOPSIS
25              
26             $fetcher = WebSource::Fetcher->new(wsnode => $node);
27              
28             # for the rest it works as a WebSource::Module
29              
30             =head1 METHODS
31              
32             =over 2
33              
34             =item B<< $source = WebSource->new(desc => $node); >>
35              
36             Create a new Fetcher;
37              
38             =cut
39              
40             sub _init_ {
41             my $self = shift;
42             $self->{method} or $self->{method} = 'GET';
43             $self->log(6,"Default method set to '",$self->{method},"'");
44             $self->SUPER::_init_;
45             $self->{useragent} or $self->{useragent} =
46             LWP::UserAgent->new(
47             agent => "WebSource/1.0",
48             keep_alive => 1,
49             timeout => 20,
50             env_proxy => 0,
51             );
52             if($self->{cookies}) {
53             $self->log(5,"Got cookie jar : ",$self->{cookies});
54             } else {
55             $self->log(5,"Creating new cookie jar");
56             $self->{cookies} = HTTP::Cookies->new;
57             }
58             $self->{maxreqinterval} or $self->{maxreqinterval} = 3;
59             $self->{maxtries} or $self->{maxtries} = 3;
60             }
61              
62             sub makeRequest {
63             my $self = shift;
64             my $env = shift;
65             if($env->type eq "object/http-request") {
66             return $env->data;
67             }
68             my $str = $env->dataString;
69             my $uri = $env->{baseuri} ?
70             URI->new_abs($str,$env->{baseuri}) :
71             URI->new($str);
72             if($uri) {
73             $self->log(6,"Generating HTTP::Request for $uri with method '",$self->{method},"'");
74             return HTTP::Request->new($self->{method},$uri);
75             }
76             return undef;
77             }
78              
79             =item B<< $fetcher->handle($env); >>
80              
81             Builds an HTTP::Request from the data in enveloppe, fetches
82             the URI (eventually stores it in a file) and builds
83             the corresponding DOM object
84              
85             =cut
86              
87             sub handle {
88             my $self = shift;
89             my $data = shift;
90             # my $request = $self->makeRequest($data);
91             my $request = $data->dataAsHttpRequest;
92             if(!$request) {
93             $self->log(1,"Couldn't convert to HTTP::Request");
94             return ();
95             }
96             my $scheme = $request->uri->scheme;
97             if(!($scheme eq "http" || $scheme eq "ftp" || $scheme eq "https" || $scheme eq "file")) {
98             $self->log(1,"Can't fetch scheme ",$scheme);
99             return ();
100             }
101             $self->log(5,"Handling request \n",$request->as_string);
102             # $self->{cookies}->add_cookie_header($request);
103             $self->log(3, "Posting request\n",
104             "-------------------\n",
105             $request->as_string,
106             "-------------------");
107             my $tries = $self->{maxtries};
108             $tries > 0 or $tries = 1;
109             my $response;
110             while($tries > 0) {
111             $self->temporize();
112             $self->log(5, "Try ", $self->{maxtries} - $tries + 1, " / ", $self->{maxtries});
113             $response = $self->{useragent}->request($request);;
114             $tries = $response->is_success ? 0 : $tries - 1;
115             ($response->code eq "500" && $response->message =~ m/SIGINT/)
116             and die($response->message);
117             $self->log(5, "Response status : ",$response->status_line);
118             }
119             if($response->is_success) {
120             $self->log(1, "success");
121             # $self->{cookies}->extract_cookies($response);
122              
123             my $base = $response->request->uri;
124             my %meta = %$data;
125             $self->log(6,"Meta data is as follows :\n",
126             map{ $_ . " => " . $meta{$_} ."\n" } keys(%meta)
127             );
128             $self->log(3,$response->headers->as_string());
129             $response->headers->scan(sub { my ($h,$v) = @_; $meta{$h} = $v; });
130             if($meta{'Content-Type'}) {
131             $self->log(2,"Parsing Content-Type: ".$meta{'Content-Type'});
132            
133             if($meta{'Content-Type'} =~ m/([A-Za-z0-9\/\-]+)(?:;\s+charset=([a-zA-Z0-9\-]+))?/) {
134             $meta{type} = $1;
135             $meta{encoding} = $2;
136             }
137             }
138             # $meta{encoding} = $response->content_encoding;
139             # $meta{type} = $response->content_type;
140             $meta{baseuri} = $base;
141             $meta{data} = $response->content;
142             $self->log(2,"Content-Encoding: ".$meta{encoding});
143             return WebSource::Envelope->new(%meta);
144             } else {
145             if ($response->{request}) {
146             $self->log(1, "WebSource : couldn't fetch ",
147             $request->uri, " received ",
148             $response->{request}->status_line);
149             } else {
150             $self->log(1, $response->message);
151             }
152             }
153             return ();
154             }
155              
156             sub temporize {
157             my $self = shift;
158             my $sleep = 0;
159              
160             if($self->{lastrequest}) {
161             my $dist = time() - $self->{lastrequest};
162             $sleep = $self->{minreqinterval} - $dist;
163             }
164             if ($sleep > 0) {
165             $self->log(3, "WebSource : temporizing : waiting ", $sleep, " seconds");
166             sleep($sleep);
167             }
168             $self->{lastrequest} = time();
169             }
170              
171             =back
172              
173             =head1 SEE ALSO
174              
175             WebSource::Module
176              
177             =cut
178              
179             1;