This file is indexed.

/usr/share/perl5/Pod/Webserver.pm is in libpod-webserver-perl 3.11-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
package Pod::Webserver;

use parent 'Pod::Simple::HTMLBatch';
use strict;
use vars qw( $VERSION @ISA );

use Pod::Webserver::Daemon;
use Pod::Webserver::Response;

use Pod::Simple::HTMLBatch;
use Pod::Simple::TiedOutFH;
use Pod::Simple;
use IO::Socket;
use File::Spec;
use File::Spec::Unix ();

our $VERSION = '3.11';

# ------------------------------------------------

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}; }

} # End of BEGIN.

# ------------------------------------------------

#sub Pod::Simple::HTMLBatch::DEBUG () {5}

# ------------------------------------------------

sub add_to_fs {  # add an item to my virtual in-memory filesystem
  my($self,$file,$type,$content) = @_;

  die "Missing filespec\n" 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 );

} # End of add_to_fs.

# ------------------------------------------------

sub _arg_h {
  my $class = ref($_[0]) || $_[0];
  $_[0]->_arg_V;
  print join "\n",
    "Usage:",
    "  podwebserver                   = Start podwebserver on localhost:8020. Search \@INC",
    "  podwebserver -p 1234           = Start podwebserver on localhost:1234",
    "  podwebserver -p 1234 -H blorp  = Start podwebserver on blorp:1234",
    "  podwebserver -t 3600           = Auto-exit in 1 hour. Default => 18000 (5 hours). 0 => No timeout",
	"  podwebserver -d /path/to/lib   = Ignore \@INC, and only search within /path/to/lib",
	"  podwebserver -e /path/to/skip  = Exclude /path/to/skip files",
    "  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;

} # End of _arg_h.

# ------------------------------------------------

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;

} # End of _arg_V.

# ------------------------------------------------

sub _contents_filespec { return '/' } # overriding the superclass's

# ------------------------------------------------

sub filespecsys { $_[0]{'_filespecsys'} || 'File::Spec::Unix' }

# ------------------------------------------------

sub _get_options {
  my($self) = shift;
  $self->verbose(0);
  return unless @ARGV;
  require Getopt::Std;
  my %o;

  Getopt::Std::getopts( "d:e:H:hp:qt:Vv" => \%o ) || die "Failed to parse options\n";

  # The 2 switches that shortcut the run:
  $o{'h'} and exit( $self->_arg_h || 0);
  $o{'V'} and exit( $self->_arg_V || 0);

  $self->_arg_h, exit(0) if ($o{p} and ($o{p} !~ /^\d+$/) );
  $self->_arg_h, exit(0) if ($o{t} and ($o{t} !~ /^\d+$/) );

  $self->dir_exclude( [ map File::Spec->canonpath($_), split(/:|;/, $o{'e'}) ] ) if ($o{'e'});
  $self->dir_include( [ map File::Spec->canonpath($_), split(/:|;/, $o{'d'}) ] ) if ($o{'d'});

  $self->httpd_host( $o{'H'} )		if $o{'H'};
  $self->httpd_port( $o{'p'} )		if $o{'p'};
  $self->httpd_timeout( $o{'t'} )	if $o{'t'};

  $self->skip_indexing(1)			if $o{'q'};
  $self->verbose(4)					if $o{'v'};

  return;

} # End of _get_options.

# ------------------------------------------------

# 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->_init_options;
  $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);

} # End of httpd.

# ------------------------------------------------

sub _init_options
{
  my($self) = shift;

  $self->dir_exclude([]);
  $self->dir_include([@INC]);

} # End of _init_options.

# ------------------------------------------------

sub makepath { return }               # overriding the superclass's

# ------------------------------------------------

#sub muse { return 1 }

# ------------------------------------------------

sub new_daemon {
  my $self = shift;

  my @opts;

  push @opts, LocalHost => $self->httpd_host if (defined $self->httpd_host);
  push @opts, LocalPort => $self->httpd_port || 8020;

  if (defined $self->httpd_timeout)
  {
	if ($self->httpd_timeout > 0)
	{
	  push @opts, Timeout => $self->httpd_timeout;
	}
  }
  else
  {
	push @opts, Timeout => 24 * 3600; # Default to exit after 24 hours of idle time.
  }

  $self->muse( "Starting daemon with options {@opts}" );
  Pod::Webserver::Daemon->new(@opts) || die "Can't start a daemon: $!\n";

} # End of _new_daemon.

# ------------------------------------------------

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<p>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;

} # End of prep_for_daemon.

# ------------------------------------------------

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;
	my $dir_include = $self->dir_include;
    if(DEBUG > -1) {
		if ($#{$self->dir_include} >= 0) {
			print " Indexing all of @$dir_include -- this might take a minute.\n";
		}
		else {
			print " Indexing all of \@INC -- this might take a minute.\n";
			DEBUG > 1 and print "\@INC = [ @INC ]\n";
		}
      $self->{'httpd_has_noted_inc_already'} ++;
    }
	$m2p = $self->modnames2paths($dir_include ? $dir_include : undef);
    $self->progress(0);

	# Filter out excluded folders
	while ( my ($key, $value) = each %$m2p ) {
		DEBUG > 1 and print "-e $value, ",  (grep $value =~ /^\Q$_\E/, @{ $self->dir_exclude }), "\n";
		delete $m2p->{$key} if grep $value =~ /^\Q$_\E/, @{ $self->dir_exclude };
	}

    die "Missing path\n" unless $m2p and keys %$m2p;

	DEBUG > -1 and print " Done scanning \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;

} # End of prep_lookup_table.

# ------------------------------------------------

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;

} # End of run_daemon.

# ------------------------------------------------

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;

} # End of _serve_pod.

# ------------------------------------------------

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 in case
    #  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;

} # End of _serve_thing.

# ------------------------------------------------

sub _wopen {             # overriding the superclass's
  my($self, $outpath) = @_;

  return Pod::Simple::TiedOutFH->handle_on( $self->add_to_fs($outpath) );

} # End of _wopen.

# ------------------------------------------------

sub write_contents_file {
  my $self = shift;
  $Pod::Simple::HTMLBatch::HTML_EXTENSION
     = $Pod::Simple::HTML::HTML_EXTENSION = '';

  return $self->SUPER::write_contents_file(@_);

} # End of write_contents_file.

# ------------------------------------------------

sub url_up_to_contents { return '/' } # overriding the superclass's

# ------------------------------------------------

# 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::Simple::_accessorize(
	'dir_include',
	'dir_exclude',
	'httpd_port',
	'httpd_host',
	'httpd_timeout',
	'skip_indexing',
);

httpd() unless caller;

# ------------------------------------------------

1;

__END__

=head1 NAME

Pod::Webserver -- Minimal web server for local Perl documentation

=head1 SYNOPSIS

  % podwebserver
  ...
  You can now open your browser to 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<perldoc> except it works through your browser.

C<podwebserver -h> displays help:

	Pod::Webserver version 3.11
	 Running under perl version 5.020002 for linux
	Usage:
	  podwebserver                   = Start podwebserver on localhost:8020. Search @INC
	  podwebserver -p 1234           = Start podwebserver on localhost:1234
	  podwebserver -p 1234 -H blorp  = Start podwebserver on blorp:1234
	  podwebserver -t 3600           = Auto-exit in 1 hour. Default => 86000 (24 hours)
	                                       0 => No timeout, but does not work for me
	  podwebserver -d /path/to/lib   = Ignore @INC, and only search within /path/to/lib
	  podwebserver -e /path/to/skip  = Exclude /path/to/skip files
	  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

	Run 'perldoc Pod::Webserver' for more information.

=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<whose Pod> 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<perlsec>), 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<perlrun>. 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<Pod::Simple::HTMLBatch> L<Pod::Simple::HTML>
L<Pod::Simple::Search> L<Pod::Simple>

See also L<Pod::Perldoc> and L<http://search.cpan.org/>

=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 Repository

L<https://github.com/ronsavage/Pod-Webserver>

=head1 AUTHOR

Original author: Sean M. Burke C<sburke@cpan.org>.

Maintained by: Allison Randal C<allison@perl.org> and Ron Savage C<ron@savage.net.au>.

=cut