File Coverage

blib/lib/HTTP/Tiny/FileProtocol.pm
Criterion Covered Total %
statement 69 77 89.6
branch 13 24 54.1
condition 7 22 31.8
subroutine 11 11 100.0
pod n/a
total 100 134 74.6


line stmt bran cond sub pod time code
1             package HTTP::Tiny::FileProtocol;
2             $HTTP::Tiny::FileProtocol::VERSION = '0.06';
3             # ABSTRACT: Add support for file:// protocol to HTTP::Tiny
4              
5 5     5   503030 use strict;
  5         48  
  5         151  
6 5     5   31 use warnings;
  5         18  
  5         130  
7              
8 5     5   26 use HTTP::Tiny;
  5         9  
  5         89  
9 5     5   25 use File::Basename;
  5         8  
  5         311  
10 5     5   2526 use LWP::MediaTypes;
  5         80320  
  5         464  
11 5     5   45 use Carp;
  5         11  
  5         285  
12              
13 5     5   29 no warnings 'redefine';
  5         10  
  5         3784  
14              
15             my $orig = *HTTP::Tiny::get{CODE};
16             my $orig_mirror = *HTTP::Tiny::mirror{CODE};
17              
18             *HTTP::Tiny::get = sub {
19 4     4   2774 my ($self, $url, $args) = @_;
20              
21 4 50 33     29 @_ == 2 || (@_ == 3 && ref $args eq 'HASH')
      66        
22             or croak(q/Usage: $http->get(URL, [HASHREF])/ . "\n");
23              
24 4 50       27 if ( $url !~ m{\Afile://} ) {
25 0   0     0 return $self->$orig( $url, $args || {});
26             }
27              
28 4         8 my $success;
29 4         8 my $status = 599;
30 4         9 my $reason = 'Internal Exception';
31 4         9 my $content = '';
32 4         43 my $content_type = 'text/plain';
33              
34 4         19 (my $path = $url) =~ s{\Afile://}{};
35              
36 4 100       141 if ( !-e $path ) {
    50          
37 1         3 $status = 404;
38 1         2 $reason = 'File Not Found';
39 1         4 return _build_response( $url, $success, $status, $reason, $content, $content_type );
40             }
41             elsif ( !-r $path ) {
42 0         0 $status = 403;
43 0         0 $reason = 'Permission Denied';
44 0         0 return _build_response( $url, $success, $status, $reason, $content, $content_type );
45             }
46              
47 3         46 my($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$filesize,
48             $atime,$mtime,$ctime,$blksize,$blocks)
49             = stat($path);
50              
51 3         11 $status = 200;
52 3         9 $success = 1;
53              
54             {
55 3 50       4 if ( open my $fh, '<', $path ) {
  3         100  
56 3         23 local $/;
57 3         16 binmode $fh;
58              
59 3         89 $content = <$fh>;
60 3         402 close $fh;
61              
62 3         24 $content_type = LWP::MediaTypes::guess_media_type( $path );
63             }
64             else {
65 0         0 $status = 500;
66 0         0 $reason = 'Internal Server Error';
67 0         0 return _build_response( $url, $success, $status, $reason, $content, $content_type );
68             }
69             }
70              
71 3         291 return _build_response( $url, $success, $status, $reason, $content, $content_type );
72             };
73              
74             *HTTP::Tiny::mirror = sub {
75 1     1   1900 my ($self, $url, $file, $args) = @_;
76              
77 1 0 0     5 @_ == 3 || (@_ == 4 && ref $args eq 'HASH')
      33        
78             or croak(q/Usage: $http->mirror(URL, FILE, [HASHREF])/ . "\n");
79              
80 1 50       7 if ( $url !~ m{\Afile://} ) {
81 0   0     0 return $self->$orig_mirror( $url, $file, $args || {});
82             }
83              
84 1         6 my $tempfile = $file . int(rand(2**31));
85              
86 1         7 require Fcntl;
87 1 50       88 sysopen my $fh, $tempfile, Fcntl::O_CREAT()|Fcntl::O_EXCL()|Fcntl::O_WRONLY()
88             or croak(qq/Error: Could not create temporary file $tempfile for downloading: $!\n/);
89 1         24 binmode $fh;
90              
91 1   50     17 my $response = $self->get( $url, $args || {} );
92              
93 1 50       5 if ( $response->{success} ) {
94 1         2 print {$fh} $response->{content};
  1         18  
95              
96 1 50       50 rename $tempfile, $file
97             or croak(qq/Error replacing $file with $tempfile: $!\n/);
98             }
99              
100 1 50       46 close $fh
101             or croak(qq/Error: Caught error closing temporary file $tempfile: $!\n/);
102              
103 1         16 unlink $tempfile;
104 1         10 return $response;
105             };
106              
107             sub _build_response {
108 4     4   17 my ($url, $success, $status, $reason, $content, $content_type) = @_;
109              
110 4         19 my $bytes;
111             {
112 5     5   44 use bytes;
  5         10  
  5         33  
  4         7  
113 4         9 $bytes = length $content;
114             }
115              
116 4 100 50     50 my $response = {
      50        
117             url => $url,
118             success => $success,
119             status => $status,
120             ( !$success ? (reason => $reason) : () ),
121             content => $content // '',
122             headers => {
123             'content-type' => $content_type,
124             'content-length' => $bytes // 0,
125             },
126             };
127              
128 4         17 return $response;
129             }
130              
131             1;
132              
133             __END__