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.05';
3             # ABSTRACT: Add support for file:// protocol to HTTP::Tiny
4              
5 5     5   503016 use strict;
  5         65  
  5         180  
6 5     5   32 use warnings;
  5         11  
  5         174  
7              
8 5     5   31 use HTTP::Tiny;
  5         14  
  5         121  
9 5     5   33 use File::Basename;
  5         12  
  5         381  
10 5     5   1858 use LWP::MediaTypes;
  5         110513  
  5         576  
11 5     5   71 use Carp;
  5         18  
  5         379  
12              
13 5     5   42 no warnings 'redefine';
  5         13  
  5         4718  
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   3229 my ($self, $url, $args) = @_;
20              
21 4 50 33     31 @_ == 2 || (@_ == 3 && ref $args eq 'HASH')
      66        
22             or croak(q/Usage: $http->get(URL, [HASHREF])/ . "\n");
23              
24 4 50       30 if ( $url !~ m{\Afile://} ) {
25 0   0     0 return $self->$orig( $url, $args || {});
26             }
27              
28 4         12 my $success;
29 4         11 my $status = 599;
30 4         11 my $reason = 'Internal Exception';
31 4         12 my $content = '';
32 4         71 my $content_type = 'text/plain';
33              
34 4         25 (my $path = $url) =~ s{\Afile://}{};
35              
36 4 100       103 if ( !-e $path ) {
    50          
37 1         3 $status = 404;
38 1         3 $reason = 'File Not Found';
39 1         5 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         32 my($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$filesize,
48             $atime,$mtime,$ctime,$blksize,$blocks)
49             = stat($path);
50              
51 3         10 $status = 200;
52 3         9 $success = 1;
53              
54             {
55 3 50       8 if ( open my $fh, '<', $path ) {
  3         82  
56 3         17 local $/;
57 3         13 binmode $fh;
58              
59 3         58 $content = <$fh>;
60 3         19 close $fh;
61              
62 3         21 $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         299 return _build_response( $url, $success, $status, $reason, $content, $content_type );
72             };
73              
74             *HTTP::Tiny::mirror = sub {
75 1     1   1869 my ($self, $url, $file, $args) = @_;
76              
77 1 0 0     6 @_ == 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         7 my $tempfile = $file . int(rand(2**31));
85              
86 1         8 require Fcntl;
87 1 50       61 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         30 binmode $fh;
90              
91 1   50     17 my $response = $self->get( $url, $args || {} );
92              
93 1 50       6 if ( $response->{success} ) {
94 1         2 print {$fh} $response->{content};
  1         13  
95              
96 1 50       39 rename $tempfile, $file
97             or croak(qq/Error replacing $file with $tempfile: $!\n/);
98             }
99              
100 1 50       31 close $fh
101             or croak(qq/Error: Caught error closing temporary file $tempfile: $!\n/);
102              
103 1         12 unlink $tempfile;
104 1         7 return $response;
105             };
106              
107             sub _build_response {
108 4     4   20 my ($url, $success, $status, $reason, $content, $content_type) = @_;
109              
110 4         10 my $bytes;
111             {
112 5     5   46 use bytes;
  5         16  
  5         41  
  4         9  
113 4         9 $bytes = length $content;
114             }
115              
116 4 100 50     60 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         20 return $response;
129             }
130              
131             1;
132              
133             __END__