Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

153 lines
3.9 KiB

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