Pod-Webserver-3.05/0000755000175000017500000000000010741123727014015 5ustar allisonallisonPod-Webserver-3.05/t/0000755000175000017500000000000010741123727014260 5ustar allisonallisonPod-Webserver-3.05/t/03_daemon.t0000644000175000017500000000343110741123526016210 0ustar allisonallisonBEGIN { chdir "t" if -e "t"; if($ENV{PERL_CORE}) { @INC = '../lib'; } else { push @INC, '../lib'; } } require 5; use strict; use warnings; use IO::Socket; # When run with the single argument 'client', the test script should run # a dummy client and exit. my $mode = shift || ''; if ($mode eq 'client') { my $port = $ENV{'PODWEBSERVERPORT'} || 8020; my $sock = IO::Socket::INET->new("localhost:$port") or die "Couldn't connect to localhost:$port: $!"; send ($sock,"GET Pod/Simple HTTP/1.0\15\12", 0x4); exit; } use Test; BEGIN {plan tests => 8}; use Pod::Webserver; ok 1; my $ws = Pod::Webserver->new(); ok ($ws); $ws->verbose(0); $ws->httpd_timeout(10); $ws->httpd_port($ENV{'PODWEBSERVERPORT'}) if ($ENV{'PODWEBSERVERPORT'}); $ws->prep_for_daemon; my $daemon; eval { $daemon = $ws->new_daemon; }; if ($@) { die $@ . "Try setting the PODWEBSERVERPORT environment variable to another port"; } ok ($daemon); my $sock = $daemon->{__sock}; #shutdown ($sock, 2); # Create a dummy client in another process. use Config; my $perl = $Config{'perlpath'}; open(CLIENT, "$perl 03_daemon.t client |") or die "Can't exec client: $!"; # Accept a request from the dummy client. my $conn = $daemon->accept; ok ($conn); my $req = $conn->get_request; ok ($req); ok ($req->url, 'Pod/Simple'); ok ($req->method, 'GET'); $conn->close; close CLIENT; # Test the response from the daemon. my $testfile = 'dummysocket.txt'; open(DUMMY, ">$testfile"); $conn = Pod::Webserver::Connection->new(*DUMMY); $ws->_serve_thing($conn, $req); $conn->close; my $captured_response; { open(COMP, $testfile); local $/ = ''; $captured_response = ; close COMP; unlink $testfile; } ok ($captured_response, qr/Pod::Simple/); shutdown ($sock, 2); exit; Pod-Webserver-3.05/t/01_about_verbose.t0000644000175000017500000000425710741123526017611 0ustar allisonallison require 5; # Time-stamp: "2004-05-25 17:46:37 ADT" # Summary of, well, things. use Test; BEGIN {plan tests => 2}; ok 1; use Pod::Webserver; #chdir "t" if -e "t"; { my @out; push @out, "\n\nPerl v", defined($^V) ? sprintf('%vd', $^V) : $], " under $^O ", (defined(&Win32::BuildNumber) and defined &Win32::BuildNumber()) ? ("(Win32::BuildNumber ", &Win32::BuildNumber(), ")") : (), (defined $MacPerl::Version) ? ("(MacPerl version $MacPerl::Version)") : (), "\n" ; # Ugly code to walk the symbol tables: my %v; my @stack = (''); # start out in %:: my $this; my $count = 0; my $pref; while(@stack) { $this = shift @stack; die "Too many packages?" if ++$count > 1000; next if exists $v{$this}; next if $this eq 'main'; # %main:: is %:: #print "Peeking at $this => ${$this . '::VERSION'}\n"; if(defined ${$this . '::VERSION'} ) { $v{$this} = ${$this . '::VERSION'} } elsif( defined *{$this . '::ISA'} or defined &{$this . '::import'} or ($this ne '' and grep defined *{$_}{'CODE'}, values %{$this . "::"}) # If it has an ISA, an import, or any subs... ) { # It's a class/module with no version. $v{$this} = undef; } else { # It's probably an unpopulated package. ## $v{$this} = '...'; } $pref = length($this) ? "$this\::" : ''; push @stack, map m/^(.+)::$/ ? "$pref$1" : (), keys %{$this . '::'}; #print "Stack: @stack\n"; } push @out, " Modules in memory:\n"; delete @v{'', '[none]'}; foreach my $p (sort {lc($a) cmp lc($b)} keys %v) { $indent = ' ' x (2 + ($p =~ tr/:/:/)); push @out, ' ', $indent, $p, defined($v{$p}) ? " v$v{$p};\n" : ";\n"; } push @out, sprintf "[at %s (local) / %s (GMT)]\n", scalar(gmtime), scalar(localtime); my $x = join '', @out; $x =~ s/^/#/mg; print $x; } print "# Running", (chr(65) eq 'A') ? " in an ASCII world.\n" : " in a non-ASCII world.\n", "#\n", ; print "# \@INC:\n", map("# [$_]\n", @INC), "#\n#\n"; print "# \%INC:\n"; foreach my $x (sort {lc($a) cmp lc($b)} keys %INC) { print "# [$x] = [", $INC{$x} || '', "]\n"; } print "#\n# Bye from ", __FILE__, "\n"; ok 1; Pod-Webserver-3.05/t/02_pod_webserver.t0000644000175000017500000000466410741123526017623 0ustar allisonallisonBEGIN { chdir "t" if -e "t"; } require 5; use strict; use Test; BEGIN {plan tests => 14}; use Pod::Webserver; ok 1; # Test inlined time2str routine. require Time::Local if $^O eq "MacOS"; my $offset = ($^O eq "MacOS") ? Time::Local::timegm(0,0,0,1,0,70) : 0; my $time = (760233600 + $offset); # assume broken POSIX counting of seconds ok (Pod::Webserver::time2str($time), 'Thu, 03 Feb 1994 00:00:00 GMT'); # Test mock request object. my $req = Pod::Webserver::Request->new(method=>'GET', url=>'http://www.cpan.org'); ok ($req); ok ($req->method, 'GET'); ok ($req->url, 'http://www.cpan.org'); # Test mock response object. $time = (1139520862 + $offset); my $resp = Pod::Webserver::Response->new(200); ok ($resp); $resp->content('Dummy content.'); $resp->content_type( 'text/html' ); $resp->header( 'Last-Modified' => Pod::Webserver::time2str($time) ); $resp->header( 'Expires' => Pod::Webserver::time2str($time) ); # Test mock connection object response. my $testfile = 'dummysocket.txt'; open(DUMMY, ">$testfile"); my $conn = Pod::Webserver::Connection->new(*DUMMY); ok ($conn); $conn->send_response($resp); $conn->close; my $captured_response; { open(COMP, $testfile); local $/ = ''; $captured_response = ; close COMP; unlink $testfile; } my $compare = "HTTP\/1.0 200 OK Date: .* GMT Content-Type: text\/html Last-Modified: Thu, 09 Feb 2006 21:34:22 GMT Expires: Thu, 09 Feb 2006 21:34:22 GMT Dummy content."; $compare =~ s/\n/\15\12/gs; ok ($captured_response, qr/$compare/); # Test mock connection object sending errors. open(DUMMY, ">$testfile"); $conn = Pod::Webserver::Connection->new(*DUMMY); ok ($conn); $conn->send_error('404'); $conn->close; my $captured_error; { open(COMP, $testfile); local $/ = ''; $captured_error = ; close COMP; unlink $testfile; } $compare = "HTTP\/1.0 404 HTTP error code 404 Date: .* GMT Content-Type: text\/plain Something went wrong, generating code 404."; $compare =~ s/\n/\15\12/gs; ok ($captured_error, qr/$compare/); # Test mock connection object retrieving requests. open(DUMMY, "+>$testfile"); print DUMMY "GET http://www.cpan.org/index.html HTTP/1.0\15\12"; close DUMMY; open(DUMMY, "$testfile"); $conn = Pod::Webserver::Connection->new(*DUMMY); ok ($conn); $req = $conn->get_request; ok ($req); if ($req) { ok ($req->method, 'GET'); ok ($req->url, 'http://www.cpan.org/index.html'); } else { ok 0; ok 0; } $conn->close; unlink $testfile; exit; Pod-Webserver-3.05/podwebserver0000755000175000017500000000011510741123526016444 0ustar allisonallison#!/usr/bin/perl #-T require 5; use Pod::Webserver; Pod::Webserver::httpd(); Pod-Webserver-3.05/lib/0000755000175000017500000000000010741123727014563 5ustar allisonallisonPod-Webserver-3.05/lib/Pod/0000755000175000017500000000000010741123727015305 5ustar allisonallisonPod-Webserver-3.05/lib/Pod/Webserver.pm0000644000175000017500000004516010741123624017611 0ustar allisonallison require 5; package Pod::Webserver; use strict; use vars qw( $VERSION @ISA ); $VERSION = '3.05'; BEGIN { if(defined &DEBUG) { } # no-op elsif( defined &Pod::Simple::DEBUG ) { *DEBUG = \&Pod::Simple::DEBUG } elsif( ($ENV{'PODWEBSERVERDEBUG'} || '') =~ m/^(\d+)$/ ) { my $x = $1; *DEBUG = sub(){$x} } else { *DEBUG = sub () {0}; } } #sub Pod::Simple::HTMLBatch::DEBUG () {5} use Pod::Simple::HTMLBatch; use Pod::Simple::TiedOutFH; use Pod::Simple; use Carp (); use IO::Socket; use File::Spec::Unix (); @ISA = ('Pod::Simple::HTMLBatch'); __PACKAGE__->Pod::Simple::_accessorize( 'httpd_port', 'httpd_host', 'httpd_timeout', 'skip_indexing', ); httpd() unless caller; # Run me as: perl -MPod::HTTP -e Pod::Webserver::httpd # or (assuming you have it installed), just run "podwebserver" #========================================================================== sub httpd { my $self = @_ ? shift(@_) : __PACKAGE__; $self = $self->new unless ref $self; $self->{'_batch_start_time'} = time(); $self->_get_options; $self->contents_file('/'); $self->prep_for_daemon; my $daemon = $self->new_daemon || return; my $url = $daemon->url; $url =~ s{//default\b}{//localhost} if $^O =~ m/Win32/; # lame hack DEBUG > -1 and print "You can now open your browser to $url\n"; return $self->run_daemon($daemon); } #========================================================================== sub _get_options { my($self) = shift; $self->verbose(0); return unless @ARGV; require Getopt::Std; my %o; die "Aborting" unless Getopt::Std::getopts( "p: H: q v h V" => \%o ) || die "Aborting\n"; # The three switches that shortcut the run: $o{'h'} and exit( $self->_arg_h || 0); $o{'V'} and exit( $self->_arg_V || 0); $self->verbose(4) if $o{'v'}; $self->skip_indexing(1) if $o{'q'}; $self->httpd_host( $o{'H'} ) if $o{'H'}; $self->httpd_port( $o{'p'} ) if $o{'p'}; return; } sub _arg_h { my $class = ref($_[0]) || $_[0]; $_[0]->_arg_V; print join "\n", "Usage:", " podwebserver = start podwebserver on localhost:8020", " podwebserver -p 1234 = start podwebserver on localhost:1234", " podwebserver -p 1234 -H blorp = start podwebserver on blorp:1234", " podwebserver -q = quick startup (but no Table of Contents)", " podwebserver -v = run with verbose output to STDOUT", " podwebserver -h = see this message", " podwebserver -V = show version information", "\nRun 'perldoc $class' for more information.", ""; return; } sub _arg_V { my $class = ref($_[0]) || $_[0]; # # Anything else particularly useful to report here? # print '', __PACKAGE__, " version $VERSION", # and report if we're running a subclass: (__PACKAGE__ eq $class) ? () : (" ($class)"), "\n", ; print " Running under perl version $] for $^O", (chr(65) eq 'A') ? "\n" : " in a non-ASCII world\n"; print " Win32::BuildNumber ", &Win32::BuildNumber(), "\n" if defined(&Win32::BuildNumber) and defined &Win32::BuildNumber(); print " MacPerl verison $MacPerl::Version\n" if defined $MacPerl::Version; return; } #========================================================================== sub _serve_pod { my($self, $modname, $filename, $resp) = @_; unless( -e $filename and -r _ and -s _ ) { # sanity $self->muse( "But filename $filename is no good!" ); return; } my $modtime = (stat(_))[9]; # use my own modtime whynot! $resp->content(''); my $contr = $resp->content_ref; $Pod::Simple::HTMLBatch::HTML_EXTENSION = $Pod::Simple::HTML::HTML_EXTENSION = ''; $resp->header('Last-Modified' => time2str($modtime) ); my $retval; if( # This is totally gross and hacky. So unless your name rhymes # with "Pawn Lurk", you have to cover your eyes right now. $retval = $self->_do_one_batch_conversion( $modname, { $modname => $filename }, '/', Pod::Simple::TiedOutFH->handle_on($contr), ) ) { $self->muse( "$modname < $filename" ); } else { $self->muse( "Ugh, couldn't convert $modname" ); } return $retval; } #========================================================================== sub new_daemon { my $self = shift; my @opts = ( defined($self->httpd_host) ? (LocalHost => $self->httpd_host) : (), LocalPort => $self->httpd_port || 8020, Timeout => defined($self->httpd_timeout) ? $self->httpd_timeout : (5*3600), # exit after 5H idle ); $self->muse( "Starting daemon with options {@opts}" ); Pod::Webserver::Daemon->new(@opts) || die "Can't start a daemon: $!\nAborting"; } #========================================================================== sub prep_for_daemon { my($self) = shift; DEBUG > -1 and print "I am process $$ = perl ", __PACKAGE__, " v$VERSION\n"; $self->{'__daemon_fs'} = {}; # That's where we keep the bodies!!!! $self->{'__expires_as_http_date'} = time2str(24*3600+time); $self->{ '__start_as_http_date'} = time2str( time); $self->add_to_fs( 'robots.txt', 'text/plain', join "\cm\cj", "User-agent: *", "Disallow: /", "", "", "# I am " . __PACKAGE__ . " v$VERSION", "", "", ); $self->add_to_fs( '/', 'text/html', # We get this only when we start up in -q mode: "* Perl Pod server *\n

Example URL: http://whatever/Getopt/Std\n\n" ); $self->_spray_css( '/' ); $self->_spray_javascript( '/' ); DEBUG > 5 and print "In FS: ", join(' ', map qq{"$_"}, sort grep !m/^\e/, keys %{ $self->{'__daemon_fs'} }), "\n"; $self->prep_lookup_table(); return; } #========================================================================== sub prep_lookup_table { my $self = shift; my $m2p; if( $self->skip_indexing ) { $self->muse("Skipping \@INC indexing."); } else { if($self->progress) { DEBUG and print "Using existing progress object\n"; } elsif( DEBUG or ($self->verbose() >= 1 and $self->verbose() <= 5) ) { require Pod::Simple::Progress; $self->progress( Pod::Simple::Progress->new(4) ); } my $search = $Pod::Simple::HTMLBatch::SEARCH_CLASS->new; if(DEBUG > -1) { print " Indexing all of \@INC -- this might take a minute.\n", "\@INC = [ @INC ]\n"; $self->{'httpd_has_noted_inc_already'} ++; } $m2p = $self->modnames2paths(); $self->progress(0); die "What, no name2path?!" unless $m2p and keys %$m2p; DEBUG > -1 and print " Done scanning \@INC\n"; foreach my $modname (sort keys %$m2p) { my @namelets = split '::', $modname; $self->note_for_contents_file( \@namelets, 'crunkIn', 'crunkOut' ); } $self->write_contents_file('crunkBase'); } $self->{'__modname2path'} = $m2p || {}; return; } sub write_contents_file { my $self = shift; $Pod::Simple::HTMLBatch::HTML_EXTENSION = $Pod::Simple::HTML::HTML_EXTENSION = ''; return $self->SUPER::write_contents_file(@_); } #========================================================================== sub add_to_fs { # add an item to my virtual in-memory filesystem my($self,$file,$type,$content) = @_; Carp::croak "What filespec?" unless defined $file and length $file; $file = "/$file"; $file =~ s{/+}{/}s; $type ||= $file eq '/' ? 'text/html' # special case : $file =~ m/\.dat?/ ? 'application/octet-stream' : $file =~ m/\.html?/ ? 'text/html' : $file =~ m/\.txt/ ? 'text/plain' : $file =~ m/\.gif/ ? 'image/gif' : $file =~ m/\.jpe?g/ ? 'image/jpeg' : $file =~ m/\.png/ ? 'image/png' : 'text/plain' ; $content = '' unless defined ''; $self->{'__daemon_fs'}{"\e$file"} = $type; \( $self->{'__daemon_fs'}{$file} = $content ); } sub _wopen { # overriding the superclass's my($self, $outpath) = @_; return Pod::Simple::TiedOutFH->handle_on( $self->add_to_fs($outpath) ); } # All of these are hacky to varying degrees sub makepath { return } # overriding the superclass's sub _contents_filespec { return '/' } # overriding the superclass's sub url_up_to_contents { return '/' } # overriding the superclass's #sub muse { return 1 } sub filespecsys { $_[0]{'_filespecsys'} || 'File::Spec::Unix' } #========================================================================== sub run_daemon { my($self, $daemon) = @_; while( my $conn = $daemon->accept ) { if( my $req = $conn->get_request ) { #^^ That used to be a while(... instead of an if( ..., but the # keepalive wasn't working so great, so let's just leave it for now. # It's not like our server here is streaming GIFs or anything. DEBUG and print "Answering connection at ", localtime()."\n"; $self->_serve_thing($conn, $req); } $conn->close; undef($conn); } $self->muse("HTTP Server terminated"); return; } #========================================================================== sub _serve_thing { my($self, $conn, $req) = @_; return $conn->send_error(405) unless $req->method eq 'GET'; # sanity my $path = $req->url; $path .= substr( ($ENV{PATH} ||''), 0, 0); # to force-taint it. my $fs = $self->{'__daemon_fs'}; my $pods = $self->{'__modname2path'}; my $resp = Pod::Webserver::Response->new(200); $resp->content_type( $fs->{"\e$path"} || 'text/html' ); $path =~ s{:+}{/}g; my $modname = $path; $modname =~ s{/+}{::}g; $modname =~ s{^:+}{}; $modname =~ s{:+$}{}; $modname =~ s{:+$}{::}g; if( $modname =~ m{^([a-zA-Z0-9_]+(?:::[a-zA-Z0-9_]+)*)$}s ) { $modname = $1; # thus untainting } else { $modname = ''; } DEBUG > 1 and print "Modname $modname ($path)\n"; if( $fs->{$path} ) { # Is it in our mini-filesystem? $resp->content( $fs->{$path} ); $resp->header( 'Last-Modified' => $self->{ '__start_as_http_date'} ); $resp->header( 'Expires' => $self->{'__expires_as_http_date'} ); $self->muse("Serving pre-cooked $path"); } elsif( $modname eq '' ) { $resp = ''; # After here, it's only untainted module names } elsif( $pods->{$modname} ) { # Is it known pod? #$self->muse("I know $modname as ", $pods->{$modname}); $self->_serve_pod( $modname, $pods->{$modname}, $resp ) or $resp = ''; } else { # If it's not known, look for it. # This is necessary for indexless mode, and also useful just incase # the user has just installed a new module (after the index was generated) my $fspath = $Pod::Simple::HTMLBatch::SEARCH_CLASS->new->find($modname); if( defined($fspath) ) { #$self->muse("Found $modname as $fspath"); $self->_serve_pod( $modname, $fspath, $resp ); } else { $resp = ''; $self->muse("Can't find $modname in \@INC"); unless( $self->{'httpd_has_noted_inc_already'} ++ ) { $self->muse(" \@INC = [ @INC ]"); } } } $resp ? $conn->send_response( $resp ) : $conn->send_error(404); return; } #========================================================================== # Inlined from HTTP::Date to avoid a dependency { my @DoW = qw(Sun Mon Tue Wed Thu Fri Sat); my @MoY = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec); sub time2str (;$) { my $time = shift; my ($sec, $min, $hour, $mday, $mon, $year, $wday) = gmtime($time); sprintf("%s, %02d %s %04d %02d:%02d:%02d GMT", $DoW[$wday], $mday, $MoY[$mon], $year+1900, $hour, $min, $sec); } } #========================================================================== package Pod::Webserver::Response; sub new { my ($class, $status_code) = @_; bless {code=>$status_code}, $class; } sub DESTROY {}; # The real methods are setter/getters. We only need the setters. sub AUTOLOAD { my ($attrib) = $Pod::Webserver::Response::AUTOLOAD =~ /([^:]+)$/; $_[0]->{$attrib} = $_[1]; } sub header { my $self = shift; push @{$self->{header}}, @_; } # The real method is a setter/getter. We only need the getter. sub content_ref { my $self = shift; \$self->{content}; } #========================================================================== package Pod::Webserver::Daemon; use vars qw( $VERSION ); $VERSION = '3.05'; use Socket qw(PF_INET SOCK_STREAM SOMAXCONN inet_aton sockaddr_in); sub new { my $class = shift; my $self = {@_}; $self->{LocalHost} ||= 'localhost'; # Anonymous file handles the 5.004 way: my $sock = do {local *SOCK; \*SOCK}; my $proto = getprotobyname('tcp') or die "getprotobyname: $!"; socket($sock, PF_INET, SOCK_STREAM, $proto) or die "Can't create socket: $!"; my $host = inet_aton($self->{LocalHost}) or die "Can't resolve hostname '$self->{LocalHost}'"; my $sin = sockaddr_in($self->{LocalPort}, $host); bind $sock, $sin or die "Couldn't bind to $self->{LocalHost}:$self->{LocalPort}: $!"; listen $sock, SOMAXCONN or die "Couldn't listen: $!"; $self->{__sock} = $sock; bless $self, $class; } sub url { my $self = shift; "http://$self->{LocalHost}:$self->{LocalPort}/"; } sub accept { my $self = shift; my $sock = $self->{__sock}; my $rin = ''; vec($rin, fileno($sock), 1) = 1; # Sadly getting a valid returned time from select is not portable my $end = $self->{Timeout} + time; do { if (select ($rin, undef, undef, $self->{Timeout})) { # Ready for reading; my $got = do {local *GOT; \*GOT}; #$! = ""; accept $got, $sock or die "accept failed: $!"; return Pod::Webserver::Connection->new($got); } } while (time < $end); return undef; } #========================================================================== package Pod::Webserver::Request; sub new { my $class = shift; bless {@_}, $class } sub url { return $_[0]->{url}; } sub method { return $_[0]->{method}; } #========================================================================== package Pod::Webserver::Connection; sub new { my ($class, $fh) = @_; bless {__fh => $fh}, $class } sub get_request { my $self = shift; my $fh = $self->{__fh}; my $line = <$fh>; if (!defined $line or !($line =~ m!^([A-Z]+)\s+(\S+)\s+HTTP/1\.\d+!)) { $self->send_error(400); return; } return Pod::Webserver::Request->new(method=>$1, url=>$2); } sub send_error { my ($self, $status_code) = @_; my $message = "HTTP/1.0 $status_code HTTP error code $status_code\n" . "Date: " . Pod::Webserver::time2str(time) . "\n" . <<"EOM"; Content-Type: text/plain Something went wrong, generating code $status_code. EOM $message =~ s/\n/\15\12/gs; print {$self->{__fh}} $message; } sub send_response { my ($self, $response) = @_; my $message = "HTTP/1.0 200 OK\n" . "Date: " . Pod::Webserver::time2str(time) . "\n" . "Content-Type: $response->{content_type}\n"; # This is destructive, but for our local purposes it doesn't matter while (my ($name, $value) = splice @{$response->{header}}, 0, 2) { $message .= "$name: $value\n"; } $message .= "\n$response->{content}"; $message =~ s/\n/\15\12/gs; print {$self->{__fh}} $message; } sub close { close $_[0]->{__fh}; } #========================================================================== 1; __END__ =head1 NAME Pod::Webserver -- minimal web server to serve local Perl documentation =head1 SYNOPSIS % podwebserver You can now point your browser at http://localhost:8020/ =head1 DESCRIPTION This module can be run as an application that works as a minimal web server to serve local Perl documentation. It's like L except it works through your browser. Run F for a list of runtime options. =head1 SECURITY (AND @INC) Pod::Webserver is not what you'd call a gaping security hole -- after all, all it does and could possibly do is serve HTML versions of anything you could get by typing "perldoc SomeModuleName". Pod::Webserver won't serve files at arbitrary paths or anything. But do consider whether you're revealing anything by basically showing off what versions of modules you've got installed; and also consider whether you could be revealing any proprietary or in-house module documentation. And also consider that this exposes the documentation of modules (i.e., any Perl files that at all look like modules) in your @INC dirs -- and your @INC probably contains "."! If your current working directory could contain modules I you don't want anyone to see, then you could do two things: The cheap and easy way is to just chdir to an uninteresting directory: mkdir ~/.empty; cd ~/.empty; podwebserver The more careful approach is to run podwebserver under perl in -T (taint) mode (as explained in L), and to explicitly specify what extra directories you want in @INC, like so: perl -T -Isomepath -Imaybesomeotherpath -S podwebserver You can also use the -I trick (that's a capital "igh", not a lowercase "ell") to add dirs to @INC even if you're not using -T. For example: perl -I/that/thar/Module-Stuff-0.12/lib -S podwebserver An alternate approach is to use your shell's environment-setting commands to alter PERL5LIB or PERLLIB before starting podwebserver. These -T and -I switches are explained in L. But I'll note in passing that you'll likely need to do this to get your PERLLIB environment variable to be in @INC... perl -T -I$PERLLIB -S podwebserver (Or replacing that with PERL5LIB, if that's what you use.) =head2 ON INDEXING '.' IN @INC Pod::Webserver uses the module Pod::Simple::Search to build the index page you see at http://yourservername:8020/ (or whatever port you choose instead of 8020). That module's indexer has one notable DWIM feature: it reads over @INC, except that it skips the "." in @INC. But you can work around this by expressing the current directory in some other way than as just the single literal period -- either as some more roundabout way, like so: perl -I./. -S podwebserver Or by just expressing the current directory absolutely: perl -I`pwd` -S podwebserver Note that even when "." isn't indexed, the Pod in files under it are still accessible -- just as if you'd typed "perldoc whatever" and got the Pod in F<./whatever.pl> =head1 SEE ALSO This module is implemented using many CPAN modules, including: L L L L See also L and L =head1 COPYRIGHT AND DISCLAIMERS Copyright (c) 2004-2006 Sean M. Burke. All rights reserved. This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =head1 AUTHOR Original author: Sean M. Burke C Maintained by: Allison Randal C =cut Pod-Webserver-3.05/META.yml0000644000175000017500000000132710741123727015271 0ustar allisonallison--- #YAML:1.0 name: Pod-Webserver version: 3.05 abstract: a miniature web server for reading Pod in web browsers license: ~ author: ~ generated_by: ExtUtils::MakeMaker version 6.42 distribution_type: module requires: Carp: 0 File::Spec::Unix: 0 IO::Socket: 0 Pod::Simple: 3.01 Pod::Simple::HTML: 0 Pod::Simple::HTMLBatch: 0 Pod::Simple::Progress: 0 strict: 0 vars: 0 meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.3.html version: 1.3 Pod-Webserver-3.05/MANIFEST0000644000175000017500000000033510741123526015144 0ustar allisonallisonChangeLog lib/Pod/Webserver.pm Makefile.PL MANIFEST MANIFEST.SKIP podwebserver README t/01_about_verbose.t t/02_pod_webserver.t t/03_daemon.t META.yml Module meta-data (added by MakeMaker) Pod-Webserver-3.05/ChangeLog0000644000175000017500000000142010741123624015560 0ustar allisonallisonRevision history for Perl module Pod::Webserver 2008-01-09 Allison Randal * Release 3.05 Added an explicit VERSION to Pod::Webserver::Daemon, to pass the tests on Perl version 5.10.0. 2006-09-12 Allison Randal * Release 3.04 Applied a patch from Nicholas Clark to eliminate the dependency on LWP, so the module could be incorporated into the Perl core. Mad props to Nick for the networking code! 2004-06-20 Sean M. Burke * Release 3.03 -- no code changes; I merely added some extra docs about -T and security and @INC things. Thanks for all your supportive email! I am surprised by what a hit this module has become! 2004-05-25 Sean M. Burke * Release 3.02 -- first release version Pod-Webserver-3.05/MANIFEST.SKIP0000644000175000017500000000010610741123526015705 0ustar allisonallison^MANIFEST\.bak$ Makefile(\.old)?$ ^Pod-Webserver-\d \.rej$ CVS blib ~ Pod-Webserver-3.05/Makefile.PL0000644000175000017500000000167610741123526015776 0ustar allisonallison# Time-stamp: "2004-05-25 19:06:13 ADT" require 5; use 5.004; # sane minimum, I think use strict; use warnings; use ExtUtils::MakeMaker; # See lib/ExtUtils/MakeMaker.pm for details of how to influence # the contents of the Makefile that is written. WriteMakefile( 'dist' => { COMPRESS => 'gzip -6f', SUFFIX => 'gz', }, 'NAME' => 'Pod::Webserver', 'VERSION_FROM' => 'lib/Pod/Webserver.pm', # finds $VERSION 'ABSTRACT' => 'a miniature web server for reading Pod in web browsers', 'EXE_FILES' => [qw( podwebserver )], 'PREREQ_PM' => { 'Pod::Simple' => 3.01, # And finally, things I don't have any particular version in mind for: map {; $_ => 0 } qw[ strict vars Pod::Simple::Progress Pod::Simple::HTMLBatch Pod::Simple::HTML Carp IO::Socket File::Spec::Unix ] } ); package MY; sub libscan { # Determine things that should *not* be installed my($self, $path) = @_; return '' if $path =~ m/~/; $path; } __END__ Pod-Webserver-3.05/README0000644000175000017500000000243710741123526014700 0ustar allisonallisonREADME for Pod::Webserver Time-stamp: "2004-05-25 18:22:38 ADT" Pod::Webserver Pod::Webserver -- minimal web server to serve local Perl documentation SYNOPSIS (Running from a prompt) % podwebserver You can now point your browser at http://localhost:8020/ DESCRIPTION This module can be run as an application that works as a minimal web server to serve local Perl documentation. It's like L except it works through your browser. Run "podwebserver -h" for a list of runtime options. INSTALLATION You install this module-suite, as you would install any perl module library, by running these commands: perl Makefile.PL make make test make install If you want to install a private copy of this module-suite in your home directory, then you should try to produce the initial Makefile with something like this command: perl Makefile.PL PREFIX=~/perl See perldoc perlmodinstall for more information on installing modules. SUPPORT Questions, bug reports, useful code bits, and suggestions for this module should just be sent to me at sburke@cpan.org AVAILABILITY The latest version of this module is available from the Comprehensive Perl Archive Network (CPAN). Visit to find a CPAN site near you.