File Coverage

lib/App/Perlbrew/HTTP.pm
Criterion Covered Total %
statement 47 64 73.4
branch 17 28 60.7
condition 2 3 66.6
subroutine 7 9 77.7
pod 0 4 0.0
total 73 108 67.5


line stmt bran cond sub pod time code
1             package App::Perlbrew::HTTP;
2 65     65   114941 use strict;
  65         152  
  65         1822  
3 65     65   324 use warnings;
  65         136  
  65         1462  
4 65     65   1175 use 5.008;
  65         230  
5              
6 65     65   416 use Exporter 'import';
  65         149  
  65         62421  
7             our @EXPORT_OK = qw(http_user_agent_program http_user_agent_command http_get http_download);
8              
9             our $HTTP_VERBOSE = 0;
10             our $HTTP_USER_AGENT_PROGRAM;
11              
12             my %commands = (
13             curl => {
14             test => '--version >/dev/null 2>&1',
15             get => '--silent --location --fail -o - {url}',
16             download => '--silent --location --fail -o {output} {url}',
17             order => 1,
18              
19             # Exit code is 22 on 404s etc
20             die_on_error => sub { die 'Page not retrieved; HTTP error code 400 or above.' if ($_[ 0 ] >> 8 == 22); },
21             },
22             wget => {
23             test => '--version >/dev/null 2>&1',
24             get => '--quiet -O - {url}',
25             download => '--quiet -O {output} {url}',
26             order => 2,
27              
28             # Exit code is not 0 on error
29             die_on_error => sub { die 'Page not retrieved: fetch failed.' if ($_[ 0 ]); },
30             },
31             fetch => {
32             test => '--version >/dev/null 2>&1',
33             get => '-o - {url}',
34             download => '-o {output} {url}',
35             order => 3,
36              
37             # Exit code is 8 on 404s etc
38             die_on_error => sub { die 'Server issued an error response.' if ($_[ 0 ] >> 8 == 8); },
39             }
40             );
41              
42             sub http_user_agent_program {
43 10   66 10 0 3357 $HTTP_USER_AGENT_PROGRAM ||= do {
44 4         7 my $program;
45              
46 4         30 for my $p (sort {$commands{$a}{order}<=>$commands{$b}{order}} keys %commands) {
  11         46  
47 6         25592 my $code = system("$p $commands{$p}->{test}") >> 8;
48 6 100       210 if ($code != 127) {
49 4         82 $program = $p;
50 4         48 last;
51             }
52             }
53              
54 4 50       110 unless ($program) {
55 0         0 die "[ERROR] Cannot find a proper http user agent program. Please install curl or wget.\n";
56             }
57              
58 4         96 $program;
59             };
60              
61 10 50       52 die "[ERROR] Unrecognized http user agent program: $HTTP_USER_AGENT_PROGRAM. It can only be one of: ".join(",", keys %commands)."\n" unless $commands{$HTTP_USER_AGENT_PROGRAM};
62              
63 10         84 return $HTTP_USER_AGENT_PROGRAM;
64             }
65              
66             sub http_user_agent_command {
67 8     8 0 16958 my ($purpose, $params) = @_;
68 8         20 my $ua = http_user_agent_program;
69 8         27 my $cmd = $commands{ $ua }->{ $purpose };
70 8         24 for (keys %$params) {
71 10         235 $cmd =~ s!{$_}!$params->{$_}!g;
72             }
73              
74 8 100       30 if ($HTTP_VERBOSE) {
75 3 100       7 unless ($ua eq "fetch") {
76 2         33 $cmd =~ s/(silent|quiet)/verbose/;
77             }
78             }
79              
80 8         25 $cmd = $ua . " " . $cmd;
81 8 100       35 return ($ua, $cmd) if wantarray;
82 2         6 return $cmd;
83             }
84              
85             sub http_download {
86 3     3 0 14568 my ($url, $path) = @_;
87              
88 3 100       33 if (-e $path) {
89 1         15 die "ERROR: The download target < $path > already exists.\n";
90             }
91              
92 2         6 my $partial = 0;
93 2     0   125 local $SIG{TERM} = local $SIG{INT} = sub { $partial++ };
  0         0  
94              
95 2         14 my $download_command = http_user_agent_command(download => { url => $url, output => $path });
96              
97 2         9 my $status = system($download_command);
98 2 50       24 if ($partial) {
99 0         0 $path->unlink;
100 0         0 return "ERROR: Interrupted.";
101             }
102 2 50       7 unless ($status == 0) {
103 2         19 $path->unlink;
104 2 100       13 if ($? == -1) {
    50          
105 1         35 return "ERROR: Failed to execute the command\n\n\t$download_command\n\nReason:\n\n\t$!";
106             }
107             elsif ($? & 127) {
108 0         0 return "ERROR: The command died with signal " . ($? & 127) . "\n\n\t$download_command\n\n";
109             }
110             else {
111 1         25 return "ERROR: The command finished with error\n\n\t$download_command\n\nExit code:\n\n\t" . ($? >> 8);
112             }
113             }
114 0           return 0;
115             }
116              
117             sub http_get {
118 0     0 0   my ($url, $header, $cb) = @_;
119              
120 0 0         if (ref($header) eq 'CODE') {
121 0           $cb = $header;
122 0           $header = undef;
123             }
124              
125 0           my ($program, $command) = http_user_agent_command(get => { url => $url });
126              
127 0 0         open my $fh, '-|', $command
128             or die "open() pipe for '$command': $!";
129              
130 0           local $/;
131 0           my $body = <$fh>;
132 0           close $fh;
133              
134             # check if the download has failed and die automatically
135 0           $commands{ $program }{ die_on_error }->($?);
136              
137 0 0         return $cb ? $cb->($body) : $body;
138             }
139              
140             1;