1 package LWP::Protocol::file;
4 @ISA = qw(LWP::Protocol);
8 require LWP::MediaTypes;
10 require HTTP::Response;
17 my($self, $request, $proxy, $arg, $size) = @_;
19 $size = 4096 unless defined $size and $size > 0;
24 return new HTTP::Response &HTTP::Status::RC_BAD_REQUEST,
25 'You can not proxy through the filesystem';
29 my $method = $request->method;
30 unless ($method eq 'GET' || $method eq 'HEAD') {
31 return new HTTP::Response &HTTP::Status::RC_BAD_REQUEST,
32 'Library does not allow method ' .
33 "$method for 'file:' URLs";
37 my $url = $request->uri;
39 my $scheme = $url->scheme;
40 if ($scheme ne 'file') {
41 return new HTTP::Response &HTTP::Status::RC_INTERNAL_SERVER_ERROR,
42 "LWP::Protocol::file::request called for '$scheme'";
45 # URL OK, look at file
46 my $path = $url->file;
48 # test file exists and is readable
50 return new HTTP::Response &HTTP::Status::RC_NOT_FOUND,
51 "File `$path' does not exist";
54 return new HTTP::Response &HTTP::Status::RC_FORBIDDEN,
55 'User does not have read permission';
58 # looks like file exists
59 my($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$filesize,
60 $atime,$mtime,$ctime,$blksize,$blocks)
63 # XXX should check Accept headers?
65 # check if-modified-since
66 my $ims = $request->header('If-Modified-Since');
68 my $time = HTTP::Date::str2time($ims);
69 if (defined $time and $time >= $mtime) {
70 return new HTTP::Response &HTTP::Status::RC_NOT_MODIFIED,
75 # Ok, should be an OK response by now...
76 my $response = new HTTP::Response &HTTP::Status::RC_OK;
78 # fill in response headers
79 $response->header('Last-Modified', HTTP::Date::time2str($mtime));
81 if (-d _) { # If the path is a directory, process it
82 # generate the HTML for directory
84 return new HTTP::Response &HTTP::Status::RC_INTERNAL_SERVER_ERROR,
85 "Cannot read directory '$path': $!";
86 my(@files) = sort readdir(D);
89 # Make directory listing
91 require HTML::Entities;
92 my $pathe = $path . ( $^O eq 'MacOS' ? ':' : '/');
94 my $furl = URI::Escape::uri_escape($_);
95 if ( -d "$pathe$_" ) {
99 my $desc = HTML::Entities::encode($_);
100 $_ = qq{<LI><A HREF="$furl">$desc</A>};
102 # Ensure that the base URL is "/" terminated
103 my $base = $url->clone;
104 unless ($base->path =~ m|/$|) {
105 $base->path($base->path . "/");
107 my $html = join("\n",
109 "<TITLE>Directory $path</TITLE>",
110 "<BASE HREF=\"$base\">",
112 "<H1>Directory listing of $path</H1>",
113 "<UL>", @files, "</UL>",
114 "</BODY>\n</HTML>\n");
116 $response->header('Content-Type', 'text/html');
117 $response->header('Content-Length', length $html);
118 $html = "" if $method eq "HEAD";
120 return $self->collect_once($arg, $response, $html);
124 # path is a regular file
125 $response->header('Content-Length', $filesize);
126 LWP::MediaTypes::guess_media_type($path, $response);
129 if ($method ne "HEAD") {
130 open(F, $path) or return new
131 HTTP::Response(&HTTP::Status::RC_INTERNAL_SERVER_ERROR,
132 "Cannot read file '$path': $!");
134 $response = $self->collect($arg, $response, sub {
136 my $bytes = sysread(F, $content, $size);
137 return \$content if $bytes > 0;