HTTP-Server-Simple-Static-0.14000755001750001750 013175106166 16442 5ustar00stephenstephen000000000000HTTP-Server-Simple-Static-0.14/Build.PL000555001750001750 140413175106166 20075 0ustar00stephenstephen000000000000#!/usr/bin/perl use strict; use warnings; use Module::Build; Module::Build->new ( module_name => 'HTTP::Server::Simple::Static', dist_author => 'Stephen Quinney ', license => 'perl', create_makefile_pl => 'traditional', requires => { 'Cwd' => 0, 'CGI' => '3.46', 'Exporter' => 0, 'File::LibMagic' => 0, 'File::Spec::Functions' => 0, 'HTTP::Date' => 0, 'HTTP::Server::Simple' => 0.01 , 'IO::File' => 0, 'URI::Escape' => 0, }, configure_requires => { 'Module::Build' => '0.40' }, )->create_build_script; HTTP-Server-Simple-Static-0.14/Changes000444001750001750 751013175106166 20075 0ustar00stephenstephen000000000000Revision history for Perl extension HTTP::Server::Simple::Static 0.14 Sat, 28 Oct 2017 14:53:00 +0100 - Further improvements to the path handling to fix a bug with specifying the base directory using a relative path. Closes: https://rt.cpan.org/Public/Bug/Display.html?id=123428 0.13 Sun, 08 Oct 2017 09:38:00 +0100 - Reworked file path handling to prevent attacker traversing out of the base directory. Closes: https://rt.cpan.org/Ticket/Display.html?id=123178 0.12 Thu, 28 Apr 2016 06:30:00 +0100 - Moved POD tests to xt/ directory so they are not run for normal user installs. 0.11 Wed, 27 Apr 2016 16:01:00 +0100 - Added a mapping for *.js files to a Content-Type of application/javascript 0.10 Wed, 27 Apr 2016 14:45:00 +0100 - Reworked how the value for the Content-Type header is selected. Simple regexp matching on the path suffix is used for *.html?, *.css and *.txt files. Any other files are checked using File::LibMagic as before. Closes: https://rt.cpan.org/Ticket/Display.html?id=113980 and https://rt.cpan.org/Ticket/Display.html?id=91321 0.09 Thu, 15 Aug 2013 09:08:00 +0100 - Added support for clients which send an If-Modified-Since HTTP header in the request. We return a 304 if the file has not been changed. 0.08 Wed, 14 Aug 2013 17:00:00 +0100 - Replaced File::MMagic and MIME::Types with File::LibMagic which should be more reliable. Closes: http://rt.cpan.org/Public/Bug/Display.html?id=39598 - Improved docs and code example. Closes: http://rt.cpan.org/Public/Bug/Display.html?id=37701 - Added support for the Last-Modified and Date HTTP headers, this consequently adds a new dependency on HTTP::Date. - Added support for not sending the content when the request method is HEAD. 0.07 Wed, 19 Mar 2008 18:41:56 +0000 - Only serve files not directories, thanks to Bradley Bailey for the report. Closes http://rt.cpan.org/Public/Bug/Display.html?id=34068 - Fixed url handling for requests from IE/ Closes http://rt.cpan.org/Public/Bug/Display.html?id=27650 0.06 Mon, 23 Jul 2007 10:42:37 +0100 - Fixed problem with handling empty files where they have no file extension or it is not recognised by MIME::Types. Thanks to Mark Stosberg for the report 0.05 Mon, 6 Nov 2006 09:29:42 +0000 - Applied patch from Max Maischein to use the binmode function rather than the binmode method of IO::File, which only exists in newer versions of that module which we were not requiring. 0.04 Thu, 20 Jul 2006 12:03:21 +0100 - Applied patch from Tom Hukins to make HTTP::Server::Simple::Static RFC compliant. Section 4.1 of RFC 2616, "Message Types", states that header fields should be separated by CRLF. This is done in the manner recommended in perlport(1). - Also applied patch from Tom Hukins to add the "use bytes" pragma to ensure Content-Length contains the number of bytes in the response body, not the number of characters. 0.03 Tue, 13 Jun 2006 11:00:58 +0100 - Fixed documentation to show that HTTP::Server::Simple::CGI should be used as the base class. Closes: http://rt.cpan.org/Public/Bug/Display.html?id=18682 - Switched to using IO::File for the file handling, also turned on binmode to help those on Windows serve images, etc. 0.02 Wed Mar 29 12:00:00 2005 - close fh after reading content. (Max Maischein) - fixed content-type header (Kang-min Liu & Max) 0.01 Thu Jan 06 21:40:02 2005 - forked from patch to HTTP::Server::Simple HTTP-Server-Simple-Static-0.14/MANIFEST000444001750001750 24413175106166 17710 0ustar00stephenstephen000000000000Build.PL Changes example.pl lib/HTTP/Server/Simple/Static.pm Makefile.PL MANIFEST This list of files META.yml t/01basic.t xt/02pod.t xt/03podcoverage.t META.json HTTP-Server-Simple-Static-0.14/META.json000444001750001750 236013175106166 20221 0ustar00stephenstephen000000000000{ "abstract" : "Serve static files with HTTP::Server::Simple", "author" : [ "Stephen Quinney " ], "dynamic_config" : 1, "generated_by" : "Module::Build version 0.4224", "license" : [ "perl_5" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : "2" }, "name" : "HTTP-Server-Simple-Static", "prereqs" : { "configure" : { "requires" : { "Module::Build" : "0.40" } }, "runtime" : { "requires" : { "CGI" : "3.46", "Cwd" : "0", "Exporter" : "0", "File::LibMagic" : "0", "File::Spec::Functions" : "0", "HTTP::Date" : "0", "HTTP::Server::Simple" : "0.01", "IO::File" : "0", "URI::Escape" : "0" } } }, "provides" : { "HTTP::Server::Simple::Static" : { "file" : "lib/HTTP/Server/Simple/Static.pm", "version" : "0.14" } }, "release_status" : "stable", "resources" : { "license" : [ "http://dev.perl.org/licenses/" ] }, "version" : "0.14", "x_serialization_backend" : "JSON::PP version 2.27400_02" } HTTP-Server-Simple-Static-0.14/META.yml000444001750001750 150613175106166 20052 0ustar00stephenstephen000000000000--- abstract: 'Serve static files with HTTP::Server::Simple' author: - 'Stephen Quinney ' build_requires: {} configure_requires: Module::Build: '0.40' dynamic_config: 1 generated_by: 'Module::Build version 0.4224, CPAN::Meta::Converter version 2.150010' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: HTTP-Server-Simple-Static provides: HTTP::Server::Simple::Static: file: lib/HTTP/Server/Simple/Static.pm version: '0.14' requires: CGI: '3.46' Cwd: '0' Exporter: '0' File::LibMagic: '0' File::Spec::Functions: '0' HTTP::Date: '0' HTTP::Server::Simple: '0.01' IO::File: '0' URI::Escape: '0' resources: license: http://dev.perl.org/licenses/ version: '0.14' x_serialization_backend: 'CPAN::Meta::YAML version 0.018' HTTP-Server-Simple-Static-0.14/Makefile.PL000444001750001750 125713175106166 20556 0ustar00stephenstephen000000000000# Note: this file was auto-generated by Module::Build::Compat version 0.4224 use ExtUtils::MakeMaker; WriteMakefile ( 'NAME' => 'HTTP::Server::Simple::Static', 'VERSION_FROM' => 'lib/HTTP/Server/Simple/Static.pm', 'PREREQ_PM' => { 'CGI' => '3.46', 'Cwd' => 0, 'Exporter' => 0, 'File::LibMagic' => 0, 'File::Spec::Functions' => 0, 'HTTP::Date' => 0, 'HTTP::Server::Simple' => '0.01', 'IO::File' => 0, 'URI::Escape' => 0 }, 'INSTALLDIRS' => 'site', 'EXE_FILES' => [], 'PL_FILES' => {} ) ; HTTP-Server-Simple-Static-0.14/example.pl000555001750001750 100713175106166 20570 0ustar00stephenstephen000000000000#!/usr/bin/perl use strict; use warnings; package MyServer; use lib qw(./lib); use base 'HTTP::Server::Simple::CGI'; use HTTP::Server::Simple::Static; my $webroot = '/tmp'; sub handle_request { my ( $self, $cgi ) = @_; if ( !$self->serve_static( $cgi, $webroot ) ) { print "HTTP/1.0 404 Not found\r\n"; print $cgi->header, $cgi->start_html('Not found'), $cgi->h1('Not found'), $cgi->end_html; } } package main; my $server = MyServer->new(); $server->run(); HTTP-Server-Simple-Static-0.14/lib000755001750001750 013175106166 17210 5ustar00stephenstephen000000000000HTTP-Server-Simple-Static-0.14/lib/HTTP000755001750001750 013175106166 17767 5ustar00stephenstephen000000000000HTTP-Server-Simple-Static-0.14/lib/HTTP/Server000755001750001750 013175106166 21235 5ustar00stephenstephen000000000000HTTP-Server-Simple-Static-0.14/lib/HTTP/Server/Simple000755001750001750 013175106166 22466 5ustar00stephenstephen000000000000HTTP-Server-Simple-Static-0.14/lib/HTTP/Server/Simple/Static.pm000444001750001750 1371713175106166 24441 0ustar00stephenstephen000000000000package HTTP::Server::Simple::Static; use strict; use warnings; use v5.10; use Cwd (); use File::Spec::Functions qw(catfile); use HTTP::Date (); use IO::File (); use URI::Escape (); use base qw(Exporter); our @EXPORT = qw(serve_static); our $VERSION = '0.14'; my $line_end = "\015\012"; my $magic; my @mime_types = ( [ qr/\.htm(l)?$/ => 'text/html' ], [ qr/\.txt$/ => 'text/plain' ], [ qr/\.css$/ => 'text/css' ], [ qr/\.js$/ => 'application/javascript' ], ); sub get_mimetype { my ($path) = @_; for my $type (@mime_types) { if ( $path =~ $type->[0] ) { return $type->[1]; } } if ( !defined $magic ) { require File::LibMagic; $magic = File::LibMagic->new(); } return $magic->checktype_filename($path); } sub serve_static { my ( $self, $cgi, $base ) = @_; $base //= q{.}; my $realbase = Cwd::realpath($base); my $path = $cgi->url( -absolute => 1, -path_info => 1 ); # Internet Explorer provides the full URI in the GET section # of the request header, so remove the protocol, domain name, # and port if they exist. $path =~ s{^https?://([^/:]+)(:\d+)?/}{/}; $path = URI::Escape::uri_unescape($path); # The splitting of the URL path and then concatenating with the # base ensures the correct directory separators are used for the # file path. my @parts = split q{/+}, $path; my $fullpath = catfile( $realbase, @parts ); # Sanitize the path and try it. my $realpath = Cwd::realpath($fullpath); if ( !$realpath || $realpath !~ m/^\Q$realbase\E/ ) { # directory traversal attack! return 0; } my $fh = IO::File->new(); if ( -f $realpath && $fh->open($realpath) ) { my $mtime = ( stat $realpath )[9]; my $now = time; # RFC-2616 Section 14.25 "If-Modified-Since": my $if_modified_since = $cgi->http('If-Modified-Since'); if ($if_modified_since) { $if_modified_since = HTTP::Date::str2time($if_modified_since); if ( defined $if_modified_since && # parsed ok $if_modified_since <= $now && # not in future $mtime <= $if_modified_since ) { # not changed print 'HTTP/1.1 304 Not Modified' . $line_end; print $line_end; return 1; } } # Read the file contents and get the length in bytes binmode $fh; binmode $self->stdout_handle; my $content; { local $/; $content = <$fh>; } $fh->close; my $content_length; if ( defined $content ) { use bytes; # Content-Length in bytes, not characters $content_length = length $content; } else { $content_length = 0; $content = q{}; } # Find MIME type my $mimetype = get_mimetype($realpath); # RFC-2616 Section 14.29 "Last-Modified": # # An origin server MUST NOT send a Last-Modified date which is # later than the server's time of message origination. In such # cases, where the resource's last modification would indicate # some time in the future, the server MUST replace that date # with the message origination date. if ( $mtime > $now ) { $mtime = $now; } my $last_modified = HTTP::Date::time2str($mtime); my $date = HTTP::Date::time2str($now); print 'HTTP/1.1 200 OK' . $line_end; print 'Date: ' . $date . $line_end; print 'Last-Modified: ' . $last_modified . $line_end; print 'Content-Type: ' . $mimetype . $line_end; print 'Content-Length: ' . $content_length . $line_end; print $line_end; if ( $cgi->request_method() ne 'HEAD' ) { print $content; } return 1; } return 0; } 1; __END__ =head1 NAME HTTP::Server::Simple::Static - Serve static files with HTTP::Server::Simple =head1 VERSION This documentation refers to HTTP::Server::Simple::Static version 0.13 =head1 SYNOPSIS package MyServer; use base qw(HTTP::Server::Simple::CGI); use HTTP::Server::Simple::Static; my $webroot = '/var/www'; sub handle_request { my ( $self, $cgi ) = @_; if ( !$self->serve_static( $cgi, $webroot ) ) { print "HTTP/1.0 404 Not found\r\n"; print $cgi->header, $cgi->start_html('Not found'), $cgi->h1('Not found'), $cgi->end_html; } } package main; my $server = MyServer->new(); $server->run(); =head1 DESCRIPTION this mixin adds a method to serve static files from your HTTP::Server::Simple subclass. =head1 SUBROUTINES/METHODS =over 4 =item serve_static( $cgi, $base ) Takes a reference to the CGI object and a document root path, and tries to serve a static file. Returns 0 if the file does not exist, returns 1 on success. This method sets the C and C HTTP headers when sending a response for a valid file. Further to this, the method supports clients which send an C HTTP header in the request, it will return a 304 C response if the file is unchanged. See RFC-2616 for full details. If the client makes a C request then no message body will be returned in the response. =back =head1 BUGS AND LIMITATIONS Bugs or wishlist requests should be submitted via http://rt.cpan.org/ =head1 DEPENDENCIES The L module is used to detect the MIME-type of a file. The L module is used for URI handling. The L module is used to format the timestamp in the Last-Modified HTTP header. =head1 SEE ALSO L, L =head1 AUTHOR Stephen Quinney C Thanks to Marcus Ramberg C and Simon Cozens for initial implementation. =head1 LICENSE AND COPYRIGHT Copyright 2006 - 2017. Stephen Quinney C You may distribute this code under the same terms as Perl itself. =cut HTTP-Server-Simple-Static-0.14/t000755001750001750 013175106166 16705 5ustar00stephenstephen000000000000HTTP-Server-Simple-Static-0.14/t/01basic.t000444001750001750 16713175106166 20435 0ustar00stephenstephen000000000000use Test::More tests=>2; use_ok ("HTTP::Server::Simple::Static"); ok (HTTP::Server::Simple::Static->isa("Exporter")); HTTP-Server-Simple-Static-0.14/xt000755001750001750 013175106166 17075 5ustar00stephenstephen000000000000HTTP-Server-Simple-Static-0.14/xt/02pod.t000444001750001750 24313175106166 20322 0ustar00stephenstephen000000000000#!/usr/bin/perl -w use strict; use Test::More; eval "use Test::Pod 1.14"; plan skip_all => "Test::Pod 1.14 required for testing POD" if $@; all_pod_files_ok(); HTTP-Server-Simple-Static-0.14/xt/03podcoverage.t000444001750001750 35213175106166 22040 0ustar00stephenstephen000000000000#!/usr/bin/perl -w use strict; use Test::More; eval "use Test::Pod::Coverage 1.04"; plan skip_all => "Test::Pod::Coverage 1.04 required for testing POD coverage" if $@; all_pod_coverage_ok({ also_private => [ qr/^[A-Z_]+$/ ], });