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 LWP::Debug::trace('()');
21 $size = 4096 unless defined $size and $size > 0;
26 return new HTTP::Response &HTTP::Status::RC_BAD_REQUEST,
27 'You can not proxy through the filesystem';
31 my $method = $request->method;
32 unless ($method eq 'GET' || $method eq 'HEAD') {
33 return new HTTP::Response &HTTP::Status::RC_BAD_REQUEST,
34 'Library does not allow method ' .
35 "$method for 'file:' URLs";
39 my $url = $request->url;
41 my $scheme = $url->scheme;
42 if ($scheme ne 'file') {
43 return new HTTP::Response &HTTP::Status::RC_INTERNAL_SERVER_ERROR,
44 "LWP::Protocol::file::request called for '$scheme'";
47 # URL OK, look at file
48 my $path = $url->file;
50 # test file exists and is readable
52 return new HTTP::Response &HTTP::Status::RC_NOT_FOUND,
53 "File `$path' does not exist";
56 return new HTTP::Response &HTTP::Status::RC_FORBIDDEN,
57 'User does not have read permission';
60 # looks like file exists
61 my($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$filesize,
62 $atime,$mtime,$ctime,$blksize,$blocks)
65 # XXX should check Accept headers?
67 # check if-modified-since
68 my $ims = $request->header('If-Modified-Since');
70 my $time = HTTP::Date::str2time($ims);
71 if (defined $time and $time >= $mtime) {
72 return new HTTP::Response &HTTP::Status::RC_NOT_MODIFIED,
77 # Ok, should be an OK response by now...
78 my $response = new HTTP::Response &HTTP::Status::RC_OK;
80 # fill in response headers
81 $response->header('Last-Modified', HTTP::Date::time2str($mtime));
83 if (-d _) { # If the path is a directory, process it
84 # generate the HTML for directory
86 return new HTTP::Response &HTTP::Status::RC_INTERNAL_SERVER_ERROR,
87 "Cannot read directory '$path': $!";
88 my(@files) = sort readdir(D);
91 # Make directory listing
93 require HTML::Entities;
94 my $pathe = $path . ( $^O eq 'MacOS' ? ':' : '/');
96 my $furl = URI::Escape::uri_escape($_);
97 if ( -d "$pathe$_" ) {
101 my $desc = HTML::Entities::encode($_);
102 $_ = qq{<LI><A HREF="$furl">$desc</A>};
104 # Ensure that the base URL is "/" terminated
105 my $base = $url->clone;
106 unless ($base->path =~ m|/$|) {
107 $base->path($base->path . "/");
109 my $html = join("\n",
111 "<TITLE>Directory $path</TITLE>",
112 "<BASE HREF=\"$base\">",
114 "<H1>Directory listing of $path</H1>",
115 "<UL>", @files, "</UL>",
116 "</BODY>\n</HTML>\n");
118 $response->header('Content-Type', 'text/html');
119 $response->header('Content-Length', length $html);
120 $html = "" if $method eq "HEAD";
122 return $self->collect_once($arg, $response, $html);
126 # path is a regular file
127 $response->header('Content-Length', $filesize);
128 LWP::MediaTypes::guess_media_type($path, $response);
131 if ($method ne "HEAD") {
132 open(F, $path) or return new
133 HTTP::Response(&HTTP::Status::RC_INTERNAL_SERVER_ERROR,
134 "Cannot read file '$path': $!");
136 $response = $self->collect($arg, $response, sub {
138 my $bytes = sysread(F, $content, $size);
139 return \$content if $bytes > 0;