line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package LWP::Protocol::file; |
2
|
|
|
|
|
|
|
|
3
|
3
|
|
|
3
|
|
467
|
use base qw(LWP::Protocol); |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
281
|
|
4
|
|
|
|
|
|
|
|
5
|
3
|
|
|
3
|
|
15
|
use strict; |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
2063
|
|
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
our $VERSION = '6.34'; |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
require LWP::MediaTypes; |
10
|
|
|
|
|
|
|
require HTTP::Request; |
11
|
|
|
|
|
|
|
require HTTP::Response; |
12
|
|
|
|
|
|
|
require HTTP::Status; |
13
|
|
|
|
|
|
|
require HTTP::Date; |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
sub request |
17
|
|
|
|
|
|
|
{ |
18
|
7
|
|
|
7
|
1
|
16
|
my($self, $request, $proxy, $arg, $size) = @_; |
19
|
|
|
|
|
|
|
|
20
|
7
|
50
|
33
|
|
|
18
|
$size = 4096 unless defined $size and $size > 0; |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
# check proxy |
23
|
7
|
50
|
|
|
|
14
|
if (defined $proxy) |
24
|
|
|
|
|
|
|
{ |
25
|
0
|
|
|
|
|
0
|
return HTTP::Response->new( HTTP::Status::RC_BAD_REQUEST, |
26
|
|
|
|
|
|
|
'You can not proxy through the filesystem'); |
27
|
|
|
|
|
|
|
} |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
# check method |
30
|
7
|
|
|
|
|
18
|
my $method = $request->method; |
31
|
7
|
50
|
66
|
|
|
94
|
unless ($method eq 'GET' || $method eq 'HEAD') { |
32
|
0
|
|
|
|
|
0
|
return HTTP::Response->new( HTTP::Status::RC_BAD_REQUEST, |
33
|
|
|
|
|
|
|
'Library does not allow method ' . |
34
|
|
|
|
|
|
|
"$method for 'file:' URLs"); |
35
|
|
|
|
|
|
|
} |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
# check url |
38
|
7
|
|
|
|
|
18
|
my $url = $request->uri; |
39
|
|
|
|
|
|
|
|
40
|
7
|
|
|
|
|
54
|
my $scheme = $url->scheme; |
41
|
7
|
50
|
|
|
|
974
|
if ($scheme ne 'file') { |
42
|
0
|
|
|
|
|
0
|
return HTTP::Response->new( HTTP::Status::RC_INTERNAL_SERVER_ERROR, |
43
|
|
|
|
|
|
|
"LWP::Protocol::file::request called for '$scheme'"); |
44
|
|
|
|
|
|
|
} |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
# URL OK, look at file |
47
|
7
|
|
|
|
|
22
|
my $path = $url->file; |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
# test file exists and is readable |
50
|
7
|
50
|
|
|
|
2585
|
unless (-e $path) { |
51
|
0
|
|
|
|
|
0
|
return HTTP::Response->new( HTTP::Status::RC_NOT_FOUND, |
52
|
|
|
|
|
|
|
"File `$path' does not exist"); |
53
|
|
|
|
|
|
|
} |
54
|
7
|
50
|
|
|
|
58
|
unless (-r _) { |
55
|
0
|
|
|
|
|
0
|
return HTTP::Response->new( HTTP::Status::RC_FORBIDDEN, |
56
|
|
|
|
|
|
|
'User does not have read permission'); |
57
|
|
|
|
|
|
|
} |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
# looks like file exists |
60
|
7
|
|
|
|
|
29
|
my($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$filesize, |
61
|
|
|
|
|
|
|
$atime,$mtime,$ctime,$blksize,$blocks) |
62
|
|
|
|
|
|
|
= stat(_); |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
# XXX should check Accept headers? |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
# check if-modified-since |
67
|
7
|
|
|
|
|
67
|
my $ims = $request->header('If-Modified-Since'); |
68
|
7
|
50
|
|
|
|
409
|
if (defined $ims) { |
69
|
0
|
|
|
|
|
0
|
my $time = HTTP::Date::str2time($ims); |
70
|
0
|
0
|
0
|
|
|
0
|
if (defined $time and $time >= $mtime) { |
71
|
0
|
|
|
|
|
0
|
return HTTP::Response->new( HTTP::Status::RC_NOT_MODIFIED, |
72
|
|
|
|
|
|
|
"$method $path"); |
73
|
|
|
|
|
|
|
} |
74
|
|
|
|
|
|
|
} |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
# Ok, should be an OK response by now... |
77
|
7
|
|
|
|
|
28
|
my $response = HTTP::Response->new( HTTP::Status::RC_OK ); |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
# fill in response headers |
80
|
7
|
|
|
|
|
366
|
$response->header('Last-Modified', HTTP::Date::time2str($mtime)); |
81
|
|
|
|
|
|
|
|
82
|
7
|
100
|
|
|
|
500
|
if (-d _) { # If the path is a directory, process it |
83
|
|
|
|
|
|
|
# generate the HTML for directory |
84
|
2
|
50
|
|
|
|
79
|
opendir(D, $path) or |
85
|
|
|
|
|
|
|
return HTTP::Response->new( HTTP::Status::RC_INTERNAL_SERVER_ERROR, |
86
|
|
|
|
|
|
|
"Cannot read directory '$path': $!"); |
87
|
2
|
|
|
|
|
136
|
my(@files) = sort readdir(D); |
88
|
2
|
|
|
|
|
49
|
closedir(D); |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
# Make directory listing |
91
|
2
|
|
|
|
|
14
|
require URI::Escape; |
92
|
2
|
|
|
|
|
929
|
require HTML::Entities; |
93
|
2
|
50
|
|
|
|
9534
|
my $pathe = $path . ( $^O eq 'MacOS' ? ':' : '/'); |
94
|
2
|
|
|
|
|
5
|
for (@files) { |
95
|
52
|
|
|
|
|
98
|
my $furl = URI::Escape::uri_escape($_); |
96
|
52
|
100
|
|
|
|
962
|
if ( -d "$pathe$_" ) { |
97
|
16
|
|
|
|
|
33
|
$furl .= '/'; |
98
|
16
|
|
|
|
|
18
|
$_ .= '/'; |
99
|
|
|
|
|
|
|
} |
100
|
52
|
|
|
|
|
133
|
my $desc = HTML::Entities::encode($_); |
101
|
52
|
|
|
|
|
643
|
$_ = qq{$desc}; |
102
|
|
|
|
|
|
|
} |
103
|
|
|
|
|
|
|
# Ensure that the base URL is "/" terminated |
104
|
2
|
|
|
|
|
26
|
my $base = $url->clone; |
105
|
2
|
50
|
|
|
|
23
|
unless ($base->path =~ m|/$|) { |
106
|
2
|
|
|
|
|
71
|
$base->path($base->path . "/"); |
107
|
|
|
|
|
|
|
} |
108
|
2
|
|
|
|
|
132
|
my $html = join("\n", |
109
|
|
|
|
|
|
|
"\n", |
110
|
|
|
|
|
|
|
"Directory $path", |
111
|
|
|
|
|
|
|
"", |
112
|
|
|
|
|
|
|
"\n", |
113
|
|
|
|
|
|
|
"Directory listing of $path", |
114
|
|
|
|
|
|
|
"", |
115
|
|
|
|
|
|
|
"\n\n"); |
116
|
|
|
|
|
|
|
|
117
|
2
|
|
|
|
|
40
|
$response->header('Content-Type', 'text/html'); |
118
|
2
|
|
|
|
|
119
|
$response->header('Content-Length', length $html); |
119
|
2
|
50
|
|
|
|
81
|
$html = "" if $method eq "HEAD"; |
120
|
|
|
|
|
|
|
|
121
|
2
|
|
|
|
|
20
|
return $self->collect_once($arg, $response, $html); |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
} |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
# path is a regular file |
126
|
5
|
|
|
|
|
12
|
$response->header('Content-Length', $filesize); |
127
|
5
|
|
|
|
|
192
|
LWP::MediaTypes::guess_media_type($path, $response); |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
# read the file |
130
|
5
|
100
|
|
|
|
757
|
if ($method ne "HEAD") { |
131
|
3
|
50
|
|
|
|
115
|
open(my $fh, '<', $path) or return new |
132
|
|
|
|
|
|
|
HTTP::Response(HTTP::Status::RC_INTERNAL_SERVER_ERROR, |
133
|
|
|
|
|
|
|
"Cannot read file '$path': $!"); |
134
|
3
|
|
|
|
|
10
|
binmode($fh); |
135
|
|
|
|
|
|
|
$response = $self->collect($arg, $response, sub { |
136
|
6
|
|
|
6
|
|
6
|
my $content = ""; |
137
|
6
|
|
|
|
|
66
|
my $bytes = sysread($fh, $content, $size); |
138
|
6
|
100
|
|
|
|
28
|
return \$content if $bytes > 0; |
139
|
3
|
|
|
|
|
19
|
return \ ""; |
140
|
3
|
|
|
|
|
26
|
}); |
141
|
3
|
|
|
|
|
32
|
close($fh); |
142
|
|
|
|
|
|
|
} |
143
|
|
|
|
|
|
|
|
144
|
5
|
|
|
|
|
25
|
$response; |
145
|
|
|
|
|
|
|
} |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
1; |