<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">package LWP::Protocol::file;

use parent qw(LWP::Protocol);

use strict;

our $VERSION = '6.77';

require LWP::MediaTypes;
require HTTP::Request;
require HTTP::Response;
require HTTP::Status;
require HTTP::Date;


sub request
{
    my($self, $request, $proxy, $arg, $size) = @_;

    $size = 4096 unless defined $size and $size &gt; 0;

    # check proxy
    if (defined $proxy)
    {
	return HTTP::Response-&gt;new( HTTP::Status::RC_BAD_REQUEST,
				  'You can not proxy through the filesystem');
    }

    # check method
    my $method = $request-&gt;method;
    unless ($method eq 'GET' || $method eq 'HEAD') {
	return HTTP::Response-&gt;new( HTTP::Status::RC_BAD_REQUEST,
				  'Library does not allow method ' .
				  "$method for 'file:' URLs");
    }

    # check url
    my $url = $request-&gt;uri;

    my $scheme = $url-&gt;scheme;
    if ($scheme ne 'file') {
	return HTTP::Response-&gt;new( HTTP::Status::RC_INTERNAL_SERVER_ERROR,
			   "LWP::Protocol::file::request called for '$scheme'");
    }

    # URL OK, look at file
    my $path  = $url-&gt;file;

    # test file exists and is readable
    unless (-e $path) {
	return HTTP::Response-&gt;new( HTTP::Status::RC_NOT_FOUND,
				  "File `$path' does not exist");
    }
    unless (-r _) {
	return HTTP::Response-&gt;new( HTTP::Status::RC_FORBIDDEN,
				  'User does not have read permission');
    }

    # looks like file exists
    my($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$filesize,
       $atime,$mtime,$ctime,$blksize,$blocks)
	    = stat(_);

    # XXX should check Accept headers?

    # check if-modified-since
    my $ims = $request-&gt;header('If-Modified-Since');
    if (defined $ims) {
	my $time = HTTP::Date::str2time($ims);
	if (defined $time and $time &gt;= $mtime) {
	    return HTTP::Response-&gt;new( HTTP::Status::RC_NOT_MODIFIED,
				      "$method $path");
	}
    }

    # Ok, should be an OK response by now...
    my $response = HTTP::Response-&gt;new( HTTP::Status::RC_OK );

    # fill in response headers
    $response-&gt;header('Last-Modified', HTTP::Date::time2str($mtime));

    if (-d _) {         # If the path is a directory, process it
	# generate the HTML for directory
	opendir(D, $path) or
	   return HTTP::Response-&gt;new( HTTP::Status::RC_INTERNAL_SERVER_ERROR,
				     "Cannot read directory '$path': $!");
	my(@files) = sort readdir(D);
	closedir(D);

	# Make directory listing
	require URI::Escape;
	require HTML::Entities;
        my $pathe = $path . ( $^O eq 'MacOS' ? ':' : '/');
	for (@files) {
	    my $furl = URI::Escape::uri_escape($_);
            if ( -d "$pathe$_" ) {
                $furl .= '/';
                $_ .= '/';
            }
	    my $desc = HTML::Entities::encode($_);
	    $_ = qq{&lt;LI&gt;&lt;A HREF="$furl"&gt;$desc&lt;/A&gt;};
	}
	# Ensure that the base URL is "/" terminated
	my $base = $url-&gt;clone;
	unless ($base-&gt;path =~ m|/$|) {
	    $base-&gt;path($base-&gt;path . "/");
	}
	my $html = join("\n",
			"&lt;HTML&gt;\n&lt;HEAD&gt;",
			"&lt;TITLE&gt;Directory $path&lt;/TITLE&gt;",
			"&lt;BASE HREF=\"$base\"&gt;",
			"&lt;/HEAD&gt;\n&lt;BODY&gt;",
			"&lt;H1&gt;Directory listing of $path&lt;/H1&gt;",
			"&lt;UL&gt;", @files, "&lt;/UL&gt;",
			"&lt;/BODY&gt;\n&lt;/HTML&gt;\n");

	$response-&gt;header('Content-Type',   'text/html');
	$response-&gt;header('Content-Length', length $html);
	$html = "" if $method eq "HEAD";

	return $self-&gt;collect_once($arg, $response, $html);

    }

    # path is a regular file
    $response-&gt;header('Content-Length', $filesize);
    LWP::MediaTypes::guess_media_type($path, $response);

    # read the file
    if ($method ne "HEAD") {
	open(my $fh, '&lt;', $path) or return new
	    HTTP::Response(HTTP::Status::RC_INTERNAL_SERVER_ERROR,
			   "Cannot read file '$path': $!");
	binmode($fh);
	$response =  $self-&gt;collect($arg, $response, sub {
	    my $content = "";
	    my $bytes = sysread($fh, $content, $size);
	    return \$content if $bytes &gt; 0;
	    return \ "";
	});
	close($fh);
    }

    $response;
}

1;
</pre></body></html>