Current Path : /usr/local/lib/perl5/site_perl/5.8.9/mach/Apache/ |
FreeBSD hs32.drive.ne.jp 9.1-RELEASE FreeBSD 9.1-RELEASE #1: Wed Jan 14 12:18:08 JST 2015 root@hs32.drive.ne.jp:/sys/amd64/compile/hs32 amd64 |
Current File : //usr/local/lib/perl5/site_perl/5.8.9/mach/Apache/PerlRun.pm |
package Apache::PerlRun; use strict; use vars qw($Debug); use Apache::Constants qw(:common &OPT_EXECCGI); BEGIN { OPT_EXECCGI() if $ENV{MOD_PERL}; #preload, :common are alread pre-loaded } unless (defined $Apache::Registry::NameWithVirtualHost) { $Apache::Registry::NameWithVirtualHost = 1; } unless (defined $Apache::Registry::MarkLine) { $Apache::Registry::MarkLine = 1; } $Debug ||= 0; my $Is_Win32 = $^O eq "MSWin32"; sub new { my($class, $r) = @_; my $filename = $r->filename; $r->warn("Apache::PerlRun->new for $filename in process $$") if $Debug && $Debug & 4; return bless {r=>$r}, $class; } sub xlog_error { my($r, $msg) = @_; $r->log_error($msg); $r->notes('error-notes', $msg); } sub can_compile { my($pr) = @_; my $r = $pr->{r}; my $filename = $r->filename; #XXX reported problems with $r->finfo # if (-r $r->finfo && -s _) { if (-r $filename && -s _) { if (!($r->allow_options & OPT_EXECCGI)) { $r->log_reason("Options ExecCGI is off in this directory", $filename); return FORBIDDEN; } if (-d _) { return DECLINED; } unless (-x _ or $Is_Win32) { $r->log_reason("file permissions deny server execution", $filename); return FORBIDDEN; } $pr->{'mtime'} = -M _; return wantarray ? (OK, $pr->{'mtime'}) : OK; } xlog_error($r, "$filename not found or unable to stat"); return NOT_FOUND; } sub mark_line { my $filename = shift->{r}->filename; return $Apache::Registry::MarkLine ? "\n#line 1 $filename\n" : ""; } sub sub_wrap { my($pr, $code, $package) = @_; $code ||= $pr->{'code'}; $package ||= $pr->{'namespace'}; my $line = $pr->mark_line; my $sub = join( '', 'package ', $package, ';use Apache qw(exit);', 'sub handler {', $line, $$code, "\n}", # last line comment without newline? ); $pr->{'sub'} = \$sub; } sub cached { my($pr) = @_; exists $Apache::Registry->{$pr->namespace}{'mtime'}; } sub should_compile { my($pr, $package, $mtime) = @_; $package ||= $pr->{'namespace'}; $mtime ||= $pr->{'mtime'}; !($pr->cached && $Apache::Registry->{$package}{'mtime'} <= $mtime); } sub set_mtime { my($pr, $mtime, $package) = @_; $mtime ||= $pr->{'mtime'}; $package ||= $pr->{'namespace'}; $Apache::Registry->{$package}{'mtime'} = $mtime; } sub compile { my($pr, $eval) = @_; $eval ||= $pr->{'sub'}; # don't use $r, but something else, so the script won't use # inherited $r by mistake my $_r = $pr->{r}; $_r->clear_rgy_endav; $_r->log_error("Apache::PerlRun->compile") if $Debug && $Debug & 4; Apache->untaint($$eval); { no strict; #so eval'd code doesn't inherit our bits eval $$eval; } $_r->stash_rgy_endav; return $pr->error_check; } sub run { my $pr = shift; my $package = $pr->{'namespace'}; my $r = $pr->{r}; my $rc = OK; my $cv = \&{"$package\::handler"}; my $oldwarn = $^W; eval { $rc = &{$cv}($r, @_) } if $r->seqno; $pr->{status} = $rc; $^W = $oldwarn; my $errsv = ""; if($@) { $errsv = $@; $@ = ''; #XXX fix me, if we don't do this Apache::exit() breaks $@{$r->uri} = $errsv; } if($errsv) { xlog_error($r, $errsv); return SERVER_ERROR; } return wantarray ? (OK, $rc) : OK; } sub status { shift->{r}->status; } sub namespace_from { my($pr) = @_; my $r = $pr->{r}; my $uri = $r->uri; $r->log_error(sprintf "Apache::PerlRun->namespace escaping %s", $uri) if $Debug && $Debug & 4; my $path_info = $r->path_info; my $script_name = $path_info && $uri =~ /\Q$path_info\E$/ ? substr($uri, 0, length($uri)-length($path_info)) : $uri; if ($Apache::Registry::NameWithVirtualHost && $r->server->is_virtual) { my $name = $r->get_server_name; $script_name = join "", $name, $script_name if $name; } $script_name =~ s:/+$:/__INDEX__:; return $script_name; } sub namespace { my($pr, $root) = @_; return $pr->{'namespace'} if $pr->{'namespace'}; my $script_name = $pr->namespace_from; # Escape everything into valid perl identifiers $script_name =~ s/([^A-Za-z0-9_\/])/sprintf("_%02x",unpack("C",$1))/eg; # second pass cares for slashes and words starting with a digit $script_name =~ s{ (/+) # directory (\d?) # package's first character }[ "::" . (length $2 ? sprintf("_%02x",unpack("C",$2)) : "") ]egx; $Apache::Registry::curstash = $script_name; $root ||= "Apache::ROOT"; $pr->{r}->log_error("Apache::PerlRun->namespace: package $root$script_name") if $Debug && $Debug & 4; $pr->{'namespace'} = $root.$script_name; return $pr->{'namespace'}; } sub readscript { my $pr = shift; $pr->{'code'} = $pr->{r}->slurp_filename; } sub error_check { my $pr = shift; if ($@ and substr($@,0,4) ne " at ") { $pr->{r}->log_error("PerlRun: `$@'"); $pr->{r}->notes('error-notes', $@); $@{$pr->{r}->uri} = $@; $@ = ''; #XXX fix me, if we don't do this Apache::exit() breaks return SERVER_ERROR; } return OK; } #XXX not good enough yet my(%switches) = ( 'T' => sub { Apache::warn("Apache::PerlRun: T switch ignored, ". "enable with 'PerlTaintCheck On'\n") unless $Apache::__T; ""; }, 'w' => sub { 'BEGIN {$^W = 1;}; $^W = 1;' }, ); sub parse_cmdline { my($pr, $code) = @_; $code ||= $pr->{'code'}; my($line) = $$code =~ /^(.*)$/m; my(@cmdline) = split /\s+/, $line; return $code unless @cmdline; return $code unless shift(@cmdline) =~ /^\#!/; my($s, @s, $prepend); $prepend = ""; for $s (@cmdline) { next unless $s =~ s/^-//; last if substr($s,0,1) eq "-"; for (split //, $s) { next unless $switches{$_}; #print STDERR "parsed `$_' switch\n"; $prepend .= &{$switches{$_}}; } } $$code =~ s/^/$prepend/ if $prepend; return $code; } sub chdir_file { my($pr, $dir) = @_; my $r = $pr->{r}; $r->chdir_file($dir ? $dir : $r->filename); } sub set_script_name { *0 = \(shift->{r}->filename); } sub handler ($$) { my($class, $r); if (@_ >= 2) { ($class, $r) = (shift, shift); } else { ($class, $r) = (__PACKAGE__, shift); } my $pr = $class->new($r); my $rc = $pr->can_compile; return $rc unless $rc == OK; my $package = $pr->namespace; my $code = $pr->readscript; $pr->parse_cmdline($code); $pr->set_script_name; $pr->chdir_file; my $line = $pr->mark_line; #make sure this hooks are restored to their original state local $SIG{__DIE__} = $SIG{__DIE__}; local $SIG{__WARN__} = $SIG{__WARN__}; my %orig_inc = %INC; my $eval = join '', 'package ', $package, ';use Apache qw(exit);', $line, $$code, "\n"; $rc = $pr->compile(\$eval); $pr->chdir_file("$Apache::Server::CWD/"); #in case .pl files do not declare package ...; for (keys %INC) { next if $orig_inc{$_}; next if /\.pm$/; delete $INC{$_}; } if(my $opt = $r->dir_config("PerlRunOnce")) { $r->child_terminate if lc($opt) eq "on"; } $pr->flush_namespace($package); return $rc; } BEGIN { if ($] < 5.006) { $INC{'warnings.pm'} = __FILE__; *warnings::unimport = sub {}; } } sub flush_namespace { my($self, $package) = @_; $package ||= $self->namespace; no strict 'refs'; my $tab = \%{$package.'::'}; for (keys %$tab) { my $fullname = join '::', $package, $_; #code/hash/array/scalar might be imported #make sure the gv does not point elsewhere #before undefing each if (%$fullname) { *{$fullname} = {}; undef %$fullname; } if (@$fullname) { *{$fullname} = []; undef @$fullname; } if ($$fullname) { my $tmp; #argh, no such thing as an anonymous scalar *{$fullname} = \$tmp; undef $$fullname; } if (defined &$fullname) { no warnings; local $^W = 0; if (defined(my $p = prototype $fullname)) { *{$fullname} = eval "sub ($p) {}"; } else { *{$fullname} = sub {}; } undef &$fullname; } if (*{$fullname}{IO}) { if (fileno $fullname) { close $fullname; } } } } 1; __END__ =head1 NAME Apache::PerlRun - Run unaltered CGI scripts under mod_perl =head1 SYNOPSIS #in httpd.conf Alias /cgi-perl/ /perl/apache/scripts/ PerlModule Apache::PerlRun <Location /cgi-perl> SetHandler perl-script PerlHandler Apache::PerlRun Options +ExecCGI #optional PerlSendHeader On ... </Location> =head1 DESCRIPTION This module's B<handler> emulates the CGI environment, allowing programmers to write scripts that run under CGI or mod_perl without change. Unlike B<Apache::Registry>, the B<Apache::PerlRun> handler does not cache the script inside of a subroutine. Scripts will be "compiled" every request. After the script has run, it's namespace is flushed of all variables and subroutines. The B<Apache::Registry> handler is much faster than B<Apache::PerlRun>. However, B<Apache::PerlRun> is much faster than CGI as the fork is still avoided and scripts can use modules which have been pre-loaded at server startup time. This module is meant for "Dirty" CGI Perl scripts which relied on the single request lifetime of CGI and cannot run under B<Apache::Registry> without cleanup. =head1 CAVEATS If your scripts still have problems running under the I<Apache::PerlRun> handler, the I<PerlRunOnce> option can be used so that the process running the script will be shutdown. Add this to your httpd.conf: <Location ...> PerlSetVar PerlRunOnce On ... </Location> =head1 SEE ALSO perl(1), mod_perl(3), Apache::Registry(3) =head1 AUTHOR Doug MacEachern =cut