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 64     64   123703 use strict;
  64         159  
  64         1834  
3 64     64   323 use warnings;
  64         123  
  64         1461  
4 64     64   1196 use 5.008;
  64         260  
5              
6 64     64   394 use Exporter 'import';
  64         156  
  64         63018  
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 2630 $HTTP_USER_AGENT_PROGRAM ||= do {
44 4         8 my $program;
45              
46 4         30 for my $p (sort {$commands{$a}{order}<=>$commands{$b}{order}} keys %commands) {
  10         39  
47 6         23712 my $code = system("$p $commands{$p}->{test}") >> 8;
48 6 100       194 if ($code != 127) {
49 4         66 $program = $p;
50 4         64 last;
51             }
52             }
53              
54 4 50       69 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         73 $program;
59             };
60              
61 10 50       67 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         76 return $HTTP_USER_AGENT_PROGRAM;
64             }
65              
66             sub http_user_agent_command {
67 8     8 0 16125 my ($purpose, $params) = @_;
68 8         22 my $ua = http_user_agent_program;
69 8         22 my $cmd = $commands{ $ua }->{ $purpose };
70 8         24 for (keys %$params) {
71 10         151 $cmd =~ s!{$_}!\Q$params->{$_}\E!g;
72             }
73              
74 8 100       27 if ($HTTP_VERBOSE) {
75 3 100       10 unless ($ua eq "fetch") {
76 2         19 $cmd =~ s/(silent|quiet)/verbose/;
77             }
78             }
79              
80 8         29 $cmd = $ua . " " . $cmd;
81 8 100       31 return ($ua, $cmd) if wantarray;
82 2         10 return $cmd;
83             }
84              
85             sub http_download {
86 3     3 0 13867 my ($url, $path) = @_;
87              
88 3 100       60 if (-e $path) {
89 1         18 die "ERROR: The download target < $path > already exists.\n";
90             }
91              
92 2         8 my $partial = 0;
93 2     0   101 local $SIG{TERM} = local $SIG{INT} = sub { $partial++ };
  0         0  
94              
95 2         24 my $download_command = http_user_agent_command(download => { url => $url, output => $path });
96              
97 2         25 my $status = system($download_command);
98 2 50       23 if ($partial) {
99 0         0 $path->unlink;
100 0         0 return "ERROR: Interrupted.";
101             }
102 2 50       8 unless ($status == 0) {
103 2         11 $path->unlink;
104 2 100       18 if ($? == -1) {
    50          
105 1         50 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         29 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;