File Coverage

blib/lib/Cikl/Smrt/Fetchers/Http.pm
Criterion Covered Total %
statement 36 93 38.7
branch 0 36 0.0
condition 0 9 0.0
subroutine 13 15 86.6
pod 0 3 0.0
total 49 156 31.4


line stmt bran cond sub pod time code
1             package Cikl::Smrt::Fetchers::Http;
2              
3 1     1   1813 use strict;
  1         3  
  1         39  
4 1     1   6 use warnings;
  1         2  
  1         27  
5 1     1   1514 use Mouse;
  1         33617  
  1         6  
6 1     1   1043 use Cikl::Smrt::Fetcher;
  1         4  
  1         34  
7 1     1   1017 use IO::File;
  1         11908  
  1         199  
8 1     1   1011 use LWP::Authen::Basic;
  1         2478  
  1         46  
9 1     1   1400 use File::Temp qw/tmpnam/;
  1         12688  
  1         81  
10 1     1   519 use Cikl::Logging;
  1         5  
  1         130  
11 1     1   1585 use Cikl;
  1         3  
  1         62  
12             extends 'Cikl::Smrt::Fetcher';
13              
14             my $logger = get_logger();
15              
16 1     1   2553 use namespace::autoclean;
  1         40596  
  1         9  
17             my @__tempfiles;
18             END {
19 1     1   11930 unlink($_) for(@__tempfiles);
20 1         40 @__tempfiles = ();
21             }
22              
23             our $AGENT = 'cikl-smrt/'.$Cikl::VERSION.' (cikl.org)';
24              
25 1     1   150 use constant SCHEMES => qw/http https/;
  1         2  
  1         1110  
26              
27             has 'timeout' => (
28             is => 'ro',
29             isa => 'Num',
30             default => 300,
31             required => 1
32             );
33              
34             has 'proxy' => (
35             is => 'ro',
36             #isa => 'Str',
37             required => 0
38             );
39              
40             has 'verify_tls' => (
41             is => 'ro',
42             isa => 'Num',
43             default => 1,
44             required => 0
45             );
46              
47             has 'feed_user' => (
48             is => 'ro',
49             isa => 'Str',
50             required => 0
51             );
52              
53             has 'feed_password' => (
54             is => 'ro',
55             isa => 'Str',
56             required => 0
57             );
58              
59             has 'mirror' => (
60             is => 'ro',
61             isa => 'Str',
62             required => 0
63             );
64              
65             sub schemes {
66 4     4 0 175 return SCHEMES;
67             }
68              
69             sub fetch {
70 0     0 0   my $self = shift;
71 0           my $feedurl = $self->feedurl();
72            
73 0 0         unless($feedurl->scheme =~ /^http/) {
74 0           die("Incorrect scheme: " . $feedurl->scheme());
75             }
76            
77             # If a proxy server is set in the configuration use LWP::UserAgent
78             # since LWPx::ParanoidAgent does not allow the use of proxies
79             # We'll assume that the proxy is sane and handles timeouts and redirects and such appropriately.
80             # LWPx::ParanoidAgent doesn't work well with Net-HTTP/TLS timeouts just yet
81 0           my $ua;
82 0 0 0       if (env_proxy() || $self->proxy() || $feedurl->scheme() eq 'https') {
      0        
83             # setup the initial agent
84 0           require LWP::UserAgent;
85 0           $ua = LWP::UserAgent->new(agent => $AGENT);
86            
87             # pull from env_
88 0           $ua->env_proxy();
89            
90             # if we override, specify
91 0           my $proxy = $self->proxy();
92 0 0         $ua->proxy(['http','https','ftp'], $proxy) if($proxy);
93             } else {
94             # we use this instead of ::UserAgent, it does better
95             # overall timeout checking
96 0           require LWPx::ParanoidAgent;
97 0           $ua = LWPx::ParanoidAgent->new(agent => $AGENT);
98             }
99            
100 0           $ua->timeout($self->timeout());
101            
102             # work-around for what appears to be a threading / race condition
103 0 0         $ua->max_redirect(0) if($feedurl->scheme() eq 'https');
104              
105 0 0         if(defined($self->verify_tls == 0)) {
106 0           $ua->ssl_opts(SSL_verify_mode => 'SSL_VERIFY_NONE');
107             } else {
108 0           $ua->ssl_opts(SSL_verify_mode => 'SSL_VERIFY_PEER');
109             }
110              
111 0 0         if(defined($self->feed_user)){
112 0           my $auth = LWP::Authen::Basic->auth_header($self->feed_user, $self->feed_password);
113 0           $ua->default_header("Authentication" => $auth);
114             }
115            
116             # work-around for a bug in LWP::UserAgent
117 0           delete($ua->{'ssl_opts'}->{'verify_hostname'});
118              
119 0           my $filename;
120              
121 0           my $is_tempfile = 0;
122 0 0         if(my $mirror = $self->mirror){
123 0           $feedurl->path() =~ m/\/([a-zA-Z0-9._-]+)$/;
124 0           $filename = $mirror.'/'.$1;
125             } else {
126 0           $filename = tmpnam();
127             # Try to ensure that it gets unlinked when the process exits.
128 0           push(@__tempfiles, $filename);
129 0           $is_tempfile = 1;
130             }
131              
132 0           $logger->debug("Saving response to $filename");
133              
134 0 0 0       die($filename.' isn\'t writeable by our user') if(-e $filename && !-w $filename);
135              
136 0           my $response = $ua->mirror($feedurl->as_string(), $filename);
137              
138 0 0         if( $response->is_error()){
139 0           die('failed to get feed: '.$feedurl->as_string()."\n".$response->status_line());
140             }
141 0           $ua = undef;
142 0 0         my $fh = IO::File->new($filename, 'r') or die($!);
143 0 0         if ($is_tempfile == 1) {
144             # This looks strange, but since we still have the filehandle open, it
145             # won't really disappear until the handle is closed.
146 0           unlink($filename);
147             }
148 0           return($fh);
149             }
150              
151             sub env_proxy {
152 0     0 0   my ($self) = @_;
153 0           require Encode;
154 0           require Encode::Locale;
155 0           my($k,$v);
156 0           my $found = 0;
157 0           while(($k, $v) = each %ENV) {
158 0 0         if ($ENV{REQUEST_METHOD}) {
159             # Need to be careful when called in the CGI environment, as
160             # the HTTP_PROXY variable is under control of that other guy.
161 0 0         next if $k =~ /^HTTP_/;
162 0 0         $k = "HTTP_PROXY" if $k eq "CGI_HTTP_PROXY";
163             }
164 0           $k = lc($k);
165 0 0         next unless $k =~ /^(.*)_proxy$/;
166 0           $k = $1;
167 0 0         unless($k eq 'no') {
168             # Ignore random _proxy variables, allow only valid schemes
169 0 0         next unless $k =~ /^$URI::scheme_re\z/;
170             # Ignore xxx_proxy variables if xxx isn't a supported protocol
171 0 0         next unless LWP::Protocol::implementor($k);
172 0           $found = 1;
173             }
174             }
175 0           return $found;
176             }
177              
178             __PACKAGE__->meta->make_immutable;
179              
180             1;