stas 01/10/09 05:47:38
Added: ModPerl-Registry MANIFEST Makefile.PL README TODO
ModPerl-Registry/lib/ModPerl PerlRun.pm Registry.pm
RegistryBB.pm RegistryCooker.pm RegistryNG.pm
ModPerl-Registry/t .cvsignore TEST.PL basic.t closure.t
ModPerl-Registry/t/cgi-bin basic.pl closure.pl env.pl
local-conf.pl not_executable.pl require.pl
ModPerl-Registry/t/conf .cvsignore extra.conf.in
Log:
- ModPerl::Registry and friends sub-project's basic functionality and
tests
Revision Changes Path
1.1 modperl-2.0/ModPerl-Registry/MANIFEST
Index: MANIFEST
===================================================================
MANIFEST This list of files
Makefile.PL
README
TODO
lib/ModPerl/PerlRun.pm
lib/ModPerl/Registry.pm
lib/ModPerl/RegistryBB.pm
lib/ModPerl/RegistryCooker.pm
lib/ModPerl/RegistryNG.pm
t/TEST.PL
t/basic.t
t/closure.t
t/cgi-bin/basic.pl
t/cgi-bin/closure.pl
t/cgi-bin/env.pl
t/cgi-bin/local-conf.pl
t/cgi-bin/not_executable.pl
t/cgi-bin/require.pl
t/conf/extra.conf.in
t/htdocs/index.html
1.1 modperl-2.0/ModPerl-Registry/Makefile.PL
Index: Makefile.PL
===================================================================
require 5.6.1;
use ExtUtils::MakeMaker;
use lib qw(lib ../blib/lib);
# enable 'make test|clean'
use Apache::TestMM qw(test clean);
# prerequisites
my %require =
(
"Apache::Test" => "", # any version will do?
);
my @scripts = qw(t/TEST);
# accept the configs from comman line
Apache::TestMM::filter_args();
Apache::TestMM::generate_script('t/TEST');
WriteMakefile
(
NAME => 'ModPerl::Registry',
VERSION_FROM => 'lib/ModPerl/RegistryCooker.pm',
PREREQ_PM => \%require,
clean => {
FILES => "@{ clean_files() }",
},
);
sub clean_files {
return [@scripts];
}
1.1 modperl-2.0/ModPerl-Registry/README
Index: README
===================================================================
to be written
1.1 modperl-2.0/ModPerl-Registry/TODO
Index: TODO
===================================================================
- META tags in the modules
---------------
- print STDERR is buffered in test handlers, whereas warn() works
normally. select() helps, but STDERR should be unbuffered in first
place.
---------------
> what's the replacement of NameWithVirtualHost? Obviously we need something
> to distinguish between vhs.
DougM: well, if possible we should distinguish between the uri and
requested resource instead. in otherwords, we have the: r->uri =>
r->filename translation, just need to figure out if r->filename is the
actual filename or a symlink (readlink can be used to get the real
filename). then create a package based on the filename, but with as
few package:: levels as possible (hopefully none beyond
ModPerl::RegistryROOT::filename)
DougM: using filenames makes for long packages names == lengthy
lookups and more memory than we need. at least the way it is
currently implemented where each '/' turns into '::'. could be that
s,/,_,g is good enough, but haven't thought about this for a while.
in any case, we should get rid of the NameWithVirtualHost stuff, its
caused too many problems in the past.
---------------
Bjarni R. Einarsson <[EMAIL PROTECTED]> has suggested this Registry hack
http://marc.theaimsgroup.com/?l=apache-modperl-dev&m=98961929702745&w=2
Message-ID: <[EMAIL PROTECTED]>
---------------
1.1 modperl-2.0/ModPerl-Registry/lib/ModPerl/PerlRun.pm
Index: PerlRun.pm
===================================================================
package ModPerl::PerlRun;
use strict;
use warnings FATAL => 'all';
# we try to develop so we reload ourselves without die'ing on the warning
no warnings qw(redefine); # XXX, this should go away in production!
our $VERSION = '1.99';
use ModPerl::RegistryCooker;
@ModPerl::PerlRun::ISA = qw(ModPerl::RegistryCooker);
# META: prototyping ($$) segfaults on request
sub handler {
my $class = (@_ >= 2) ? shift : __PACKAGE__;
my $r = shift;
return $class->new($r)->default_handler();
}
my $parent = 'ModPerl::RegistryCooker';
# the following code:
# - specifies package's behavior different from default of $parent class
# - speeds things up by shortcutting @ISA search, so even if the
# default is used we still use the alias
my %aliases = (
new => 'new',
init => 'init',
default_handler => 'default_handler',
run => 'run',
can_compile => 'can_compile',
make_namespace => 'make_namespace',
namespace_from => 'namespace_from_filename',
is_cached => 'FALSE',
should_compile => 'TRUE',
flush_namespace => 'flush_namespace_normal',
cache_it => 'NOP',
read_script => 'read_script',
rewrite_shebang => 'rewrite_shebang',
set_script_name => 'set_script_name',
chdir_file => 'chdir_file_normal',
get_mark_line => 'get_mark_line',
compile => 'compile',
error_check => 'error_check',
strip_end_data_segment => 'strip_end_data_segment',
convert_script_to_compiled_handler => 'convert_script_to_compiled_handler',
);
# in this module, all the methods are inherited from the same parent
# class, so we fixup aliases instead of using the source package in
# first place.
$aliases{$_} = $parent . "::" . $aliases{$_} for keys %aliases;
__PACKAGE__->install_aliases(\%aliases);
1;
__END__
=head1 NAME
ModPerl::PerlRun -
=head1 SYNOPSIS
=head1 DESCRIPTION
=cut
1.1 modperl-2.0/ModPerl-Registry/lib/ModPerl/Registry.pm
Index: Registry.pm
===================================================================
package ModPerl::Registry;
use strict;
use warnings FATAL => 'all';
# we try to develop so we reload ourselves without die'ing on the warning
no warnings qw(redefine); # XXX, this should go away in production!
our $VERSION = '1.99';
use ModPerl::RegistryCooker;
@ModPerl::Registry::ISA = qw(ModPerl::RegistryCooker);
sub handler {
my $class = (@_ >= 2) ? shift : __PACKAGE__;
my $r = shift;
return $class->new($r)->default_handler();
}
my $parent = 'ModPerl::RegistryCooker';
# the following code:
# - specifies package's behavior different from default of $parent class
# - speeds things up by shortcutting @ISA search, so even if the
# default is used we still use the alias
my %aliases = (
new => 'new',
init => 'init',
default_handler => 'default_handler',
run => 'run',
can_compile => 'can_compile',
make_namespace => 'make_namespace',
namespace_from => 'namespace_from_filename',
is_cached => 'is_cached',
should_compile => 'should_compile_if_modified',
flush_namespace => 'NOP',
cache_it => 'cache_it',
read_script => 'read_script',
rewrite_shebang => 'rewrite_shebang',
set_script_name => 'set_script_name',
chdir_file => 'chdir_file_normal',
get_mark_line => 'get_mark_line',
compile => 'compile',
error_check => 'error_check',
strip_end_data_segment => 'strip_end_data_segment',
convert_script_to_compiled_handler => 'convert_script_to_compiled_handler',
);
# in this module, all the methods are inherited from the same parent
# class, so we fixup aliases instead of using the source package in
# first place.
$aliases{$_} = $parent . "::" . $aliases{$_} for keys %aliases;
__PACKAGE__->install_aliases(\%aliases);
# Note that you don't have to do the aliases if you use defaults, it
# just speeds things up the first time the sub runs, after that
# methods are cached.
#
# But it's still handy, since you explicitly specify which subs from
# the parent package you are using
#
# META: if the ISA search results are cached on the first lookup, may
# be need to alias only the those that aren't the defaults?
1;
__END__
=head1 NAME
ModPerl::Registry -
=head1 SYNOPSIS
=head1 DESCRIPTION
=cut
1.1 modperl-2.0/ModPerl-Registry/lib/ModPerl/RegistryBB.pm
Index: RegistryBB.pm
===================================================================
package ModPerl::RegistryBB;
use strict;
use warnings FATAL => 'all';
# we try to develop so we reload ourselves without die'ing on the warning
no warnings qw(redefine); # XXX, this should go away in production!
our $VERSION = '1.99';
use ModPerl::RegistryCooker;
@ModPerl::RegistryBB::ISA = qw(ModPerl::RegistryCooker);
# META: prototyping ($$) segfaults on request
sub handler {
my $class = (@_ >= 2) ? shift : __PACKAGE__;
my $r = shift;
return $class->new($r)->default_handler();
}
# currently all the methods are inherited through the normal ISA
# search may
1;
__END__
=head1 NAME
ModPerl::RegistryBB -
=head1 SYNOPSIS
=head1 DESCRIPTION
C<ModPerl::RegistryBB> uses all the defaults, which do the very minimum
to compile the file once and run it many times.
=cut
1.1 modperl-2.0/ModPerl-Registry/lib/ModPerl/RegistryCooker.pm
Index: RegistryCooker.pm
===================================================================
# VERY IMPORTANT: Be very careful modifying the defaults, since many
# VERY IMPORTANT: packages rely on them. In fact you should never
# VERY IMPORTANT: modify the defaults after the package gets released,
# VERY IMPORTANT: since they are a hardcoded part of this suite's API.
package ModPerl::RegistryCooker;
require 5.006;
use strict;
use warnings FATAL => 'all';
# we try to develop so we reload ourselves without die'ing on the warning
no warnings qw(redefine); # XXX, this should go away in production!
our $VERSION = '1.99';
use Apache::compat ();
# Should not use Apache::compat, the following methods need to be implemented
# $r->slurp_filename
# $r->clear_rgy_endav
# $r->stash_rgy_endav
use Apache::Response;
use Apache::Log;
use Apache::Const -compile => qw(:common &OPT_EXECCGI);
use File::Spec::Functions ();
use ModPerl::Util ();
#########################################################################
# issues
#
#########################################################################
# META: who sets this? What's the default?
unless (defined $ModPerl::Registry::MarkLine) {
$ModPerl::Registry::MarkLine = 1;
}
### Optimizations
#
# - $o->[CLASS] of the subclass is known at compile time, so should
# create the subs using $o->[CLASS] on the fly for each subclass
# which wants them
### TODO
#
# - who handles END/BEGIN/,CHECK,INIT) blocks?
# - see META's accross the file
#########################################################################
# debug flag constants
#
#########################################################################
use constant D_ERROR => 1;
use constant D_WARN => 2;
use constant D_COMPILE => 4;
use constant D_NOISE => 8;
# use ModPerl::RegistryCooker::DEBUG constant if defined elsewhere
# before the compilation of this package: D_NOISE devel mode (prod==0)
#use constant DEBUG => ModPerl::RegistryCooker->can('DEBUG') || D_NOISE;
#use Apache::ServerUtil;
#use constant DEBUG => defined
Apache->server->dir_config('ModPerl::RegistryCooker::DEBUG') ?
Apache->server->dir_config('ModPerl::RegistryCooker::DEBUG') : D_NOISE;
use constant DEBUG => D_NOISE;
#########################################################################
# object's array index's access constants
#
#########################################################################
use constant REQ => 0;
use constant FILENAME => 1;
use constant URI => 2;
use constant MTIME => 3;
use constant PACKAGE => 4;
use constant CODE => 5;
use constant STATUS => 6;
use constant CLASS => 7;
#########################################################################
# OS specific constants
#
#########################################################################
use constant IS_WIN32 => $^O eq "MSWin32";
#########################################################################
# constant subs
#
#########################################################################
use constant NOP => sub { };
use constant TRUE => sub { 1 };
use constant FALSE => sub { 0 };
#########################################################################
# install the aliases into $class
#
#########################################################################
sub install_aliases {
my ($class, $rh_aliases) = @_;
no strict 'refs';
while (my($k,$v) = each %$rh_aliases) {
if (my $sub = *{$v}{CODE}){
#warn "$class: ok: $k => $v";
*{ $class . "::$k" } = $sub;
}
else {
die "$class: $k aliasing failed; sub $v doesn't exist";
}
}
}
#########################################################################
# func: new
# dflt: new
# args: $class - class to bless into
# $r - Apache::Request object
# desc: create the class's object and bless it
# rtrn: the newly created object
#########################################################################
sub new {
my($class, $r) = @_;
my $o = bless [], $class;
$o->init($r);
#$o->debug("$$: init class: $class");
return $o;
}
#########################################################################
# func: init
# dflt: init
# desc: initializes the data object's fields: CLASS REQ FILENAME URI
# args: $r - Apache::Request object
# rtrn: nothing
#########################################################################
sub init {
$_[0]->[CLASS] = ref $_[0];
$_[0]->[REQ] = $_[1];
$_[0]->[URI] = $_[1]->uri;
$_[0]->[FILENAME] = $_[1]->filename;
}
#########################################################################
# func: handler
# dflt: handler
# desc: the handler() sub that is expected by Apache
# args: $class - handler's class
# $r - Apache::Request object
# (o)can be called as handler($r) as well (without leading $class)
# rtrn: handler's response status
# note: must be implemented in a sub-class unless configured as
# Apache::Foo->handler in httpd.conf (because of the
# __PACKAGE__, which is tied to the file)
#########################################################################
# META: prototyping ($$) segfaults on request
sub handler {
my $class = (@_ >= 2) ? shift : __PACKAGE__;
my $r = shift;
$class->new($r)->default_handler();
}
#########################################################################
# func: default_handler
# dflt: META: see above
# desc: META: see above
# args: $o - registry blessed object
# rtrn: handler's response status
# note: that's what most sub-class handlers will call
#########################################################################
sub default_handler {
my $o = shift;
$o->make_namespace;
if ($o->should_compile) {
my $rc = $o->can_compile;
return $rc unless $rc == Apache::OK;
$o->convert_script_to_compiled_handler;
}
return $o->run;
}
#########################################################################
# func: run
# dflt: run
# desc: executes the compiled code
# args: $o - registry blessed object
# rtrn: execution status (Apache::?)
#########################################################################
sub run {
my $o = shift;
my $r = $o->[REQ];
my $package = $o->[PACKAGE];
$o->set_script_name;
$o->chdir_file;
my $rc = Apache::OK;
my $cv = \&{"$package\::handler"};
{ # run the code, preserve warnings setup when it's done
no warnings;
eval { $rc = &{$cv}($r, @_) } if $r->seqno;
$o->[STATUS] = $rc;
}
$o->flush_namespace;
# META: handle!
#$o->chdir_file("$Apache::Server::CWD/");
if ( ($rc = $o->error_check) != Apache::OK) {
return $rc;
}
return Apache::OK;
}
#########################################################################
# func: can_compile
# dflt: can_compile
# desc: checks whether the script is allowed and can be compiled
# args: $o - registry blessed object
# rtrn: $rc - return status to forward
# efct: initializes the data object's fields: MTIME
#########################################################################
sub can_compile {
my $o = shift;
my $r = $o->[REQ];
unless (-r $r->finfo && -s _) {
$r->log_error("$$: $o->[FILENAME] not found or unable to stat");
return Apache::NOT_FOUND;
}
return Apache::DECLINED if -d _;
$o->[MTIME] = -M _;
unless (-x _ or IS_WIN32) {
$r->log_reason("file permissions deny server execution",
$o->[FILENAME]);
return Apache::FORBIDDEN;
}
if (!($r->allow_options & Apache::OPT_EXECCGI)) {
$r->log_reason("Options ExecCGI is off in this directory",
$o->[FILENAME]);
return Apache::FORBIDDEN;
}
$o->debug("can compile $o->[FILENAME]") if DEBUG & D_NOISE;
return Apache::OK;
}
#########################################################################
# func: make_namespace
# dflt: make_namespace
# desc: prepares the namespace
# args: $o - registry blessed object
# rtrn: the namespace
# efct: initializes the field: PACKAGE
#########################################################################
sub make_namespace {
my $o = shift;
my $package = $o->namespace_from;
# Escape everything into valid perl identifiers
$package =~ s/([^A-Za-z0-9_])/sprintf("_%2x", unpack("C", $1))/eg;
# make sure that the sub-package doesn't start with a digit
$package = "_$package";
# META: ??? explain
$ModPerl::Registry::curstash = $package;
# prepend root
$package = $o->[CLASS] . "::Cache::$package";
$o->[PACKAGE] = $package;
return $package;
}
#########################################################################
# func: namespace_from
# dflt: namespace_from_filename
# desc: returns a partial raw package name based on filename, uri, else
# args: $o - registry blessed object
# rtrn: a unique string
#########################################################################
*namespace_from = \&namespace_from_filename;
# return a package name based on $r->filename only
sub namespace_from_filename {
my $o = shift;
my ($volume, $dirs, $file) =
File::Spec::Functions::splitpath($o->[FILENAME]);
my @dirs = File::Spec::Functions::splitdir($dirs);
return join '_', ($volume||''), @dirs, $file;
}
# return a package name based on $r->uri only
sub namespace_from_uri {
my $o = shift;
my $path_info = $o->[REQ]->path_info;
my $script_name = $path_info && $o->[URI] =~ /$path_info$/ ?
substr($o->[URI], 0, length($o->[URI]) - length($path_info)) :
$o->[URI];
# META: do we handle this?
# if ($ModPerl::Registry::NameWithVirtualHost && $o->[REQ]->server->is_virtual) {
# my $name = $o->[REQ]->get_server_name;
# $script_name = join "", $name, $script_name if $name;
# }
$script_name =~ s:/+$:/__INDEX__:;
return $script_name;
}
#########################################################################
# func: convert_script_to_compiled_handler
# dflt: convert_script_to_compiled_handler
# desc: reads the script, converts into a handler and compiles it
# args: $o - registry blessed object
# rtrn: success/failure status
#########################################################################
sub convert_script_to_compiled_handler {
my $o = shift;
$o->debug("Adding package $o->[PACKAGE]") if DEBUG & D_NOISE;
# get the script's source
$o->read_script;
# convert the shebang line opts into perl code
$o->rewrite_shebang;
# mod_cgi compat, should compile the code while in its dir, so
# relative require/open will work.
$o->chdir_file;
# META: what's this?
# # compile this subroutine into the uniq package name
# $o->debug("handler eval-ing") if DEBUG & D_NOISE;
# undef &{"$o->[PACKAGE]\::handler"};# unless $Debug && $Debug & 4; #avoid
warnings
# $o->[PACKAGE]->can('undef_functions') && $o->[PACKAGE]->undef_functions;
my $line = $o->get_mark_line;
$o->strip_end_data_segment;
my $eval = join '',
'package ',
$o->[PACKAGE], ";",
"sub handler {\n",
$line,
${ $o->[CODE] },
"\n}"; # last line comment without newline?
my %orig_inc = %INC;
#warn "[-- $eval --]";
my $rc = $o->compile(\$eval);
$o->debug(qq{compiled package \"$o->[PACKAGE]\"}) if DEBUG & D_NOISE;
# META: handle!
#$o->chdir_file("$Apache::Server::CWD/");
# %INC cleanup
#in case .pl files do not declare package ...;
for (keys %INC) {
next if $orig_inc{$_};
next if /\.pm$/;
delete $INC{$_};
}
# META: $r->child_terminate is not implemented
# if(my $opt = $r->dir_config("PerlRunOnce")) {
# $r->child_terminate if lc($opt) eq "on";
# }
$o->cache_it;
return $rc;
}
#########################################################################
# func: cache_it
# dflt: cache_it
# desc: mark the package as cached by storing its modification time
# args: $o - registry blessed object
# rtrn: nothing
#########################################################################
sub cache_it {
my $o = shift;
no strict 'refs';
${$o->[CLASS]}->{ $o->[PACKAGE] }{mtime} = $o->[MTIME];
}
#########################################################################
# func: is_cached
# dflt: is_cached
# desc: checks whether the package is already cached
# args: $o - registry blessed object
# rtrn: TRUE if cached,
# FALSE otherwise
#########################################################################
sub is_cached {
my $o = shift;
no strict 'refs';
exists ${$o->[CLASS]}->{ $o->[PACKAGE] }{mtime};
}
#########################################################################
# func: should_compile
# dflt: should_compile_once
# desc: decide whether code should be compiled or not
# args: $o - registry blessed object
# rtrn: TRUE if should compile
# FALSE otherwise
# efct: sets MTIME if it's not set yet
#########################################################################
*should_compile = \&should_compile_once;
# return false only if the package is cached and its source file
# wasn't modified
sub should_compile_if_modified {
my $o = shift;
$o->[MTIME] ||= -M $o->[REQ]->finfo;
no strict 'refs';
!($o->is_cached &&
${$o->[CLASS]}->{ $o->[PACKAGE] }{mtime} <= $o->[MTIME]);
}
# return false if the package is cached already
sub should_compile_once {
not shift->is_cached;
}
#########################################################################
# func: flush_namespace
# dflt: NOP (don't flush)
# desc: flush the compiled package's namespace
# args: $o - registry blessed object
# rtrn: nothing
#########################################################################
*flush_namespace = \&NOP;
sub flush_namespace_normal {
my $o = shift;
$o->debug("flushing namespace") if DEBUG & D_NOISE;
no strict 'refs';
my $tab = \%{ $o->[PACKAGE] . '::' };
for (keys %$tab) {
my $fullname = join '::', $o->[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 (my $p = prototype $fullname) {
*{$fullname} = eval "sub ($p) {}";
}
else {
*{$fullname} = sub {};
}
undef &$fullname;
}
if (*{$fullname}{IO}) {
if (fileno $fullname) {
close $fullname;
}
}
}
}
#########################################################################
# func: read_script
# dflt: read_script
# desc: reads the script in
# args: $o - registry blessed object
# rtrn: nothing
# efct: initializes the CODE field with the source script
#########################################################################
# reads the contents of the file
sub read_script {
my $o = shift;
$o->debug("reading $o->[FILENAME]") if DEBUG & D_NOISE;
$o->[CODE] = $o->[REQ]->slurp_filename;
}
#########################################################################
# func: rewrite_shebang
# dflt: rewrite_shebang
# desc: parse the shebang line and convert command line switches
# (defined in %switches) into a perl code.
# args: $o - registry blessed object
# rtrn: nothing
# efct: the CODE field gets adjusted
#########################################################################
my %switches = (
'T' => sub {
Apache::warn("T switch ignored, ".
"enable with 'PerlTaintCheck On'\n")
unless $Apache::__T; "";
},
'w' => sub { "use warnings;\n" },
);
sub rewrite_shebang {
my $o = shift;
my($line) = ${ $o->[CODE] } =~ /^(.*)$/m;
my @cmdline = split /\s+/, $line;
return unless @cmdline;
return unless shift(@cmdline) =~ /^\#!/;
my $prepend = "";
for my $s (@cmdline) {
next unless $s =~ s/^-//;
last if substr($s,0,1) eq "-";
for (split //, $s) {
next unless exists $switches{$_};
#print STDERR "parsed `$_' switch\n";
$prepend .= &{$switches{$_}};
}
}
${ $o->[CODE] } =~ s/^/$prepend/ if $prepend;
}
#########################################################################
# func: set_script_name
# dflt: set_script_name
# desc: set $0 to the script's name
# args: $o - registry blessed object
# rtrn: nothing
#########################################################################
sub set_script_name {
*0 = \(shift->[FILENAME]);
}
#########################################################################
# func: chdir_file
# dflt: NOP
# desc: chdirs into $dir
# args: $o - registry blessed object
# $dir - a dir
# rtrn: nothing (?or success/failure?)
#########################################################################
*chdir_file = \&NOP;
sub chdir_file_normal {
my($o, $dir) = @_;
# META: not implemented
# META: see todo/api.txt unsafe!
# $o->[REQ]->chdir_file($dir ? $dir : $o->[FILENAME]);
}
#########################################################################
# func: get_mark_line
# dflt: get_mark_line
# desc: generates the perl compiler #line directive
# args: $o - registry blessed object
# rtrn: returns the perl compiler #line directive
#########################################################################
sub get_mark_line {
my $o = shift;
# META: shouldn't this be $o->[CLASS]?
$ModPerl::Registry::MarkLine ? "\n#line 1 $o->[FILENAME]\n" : "";
}
#########################################################################
# func: strip_end_data_segment
# dflt: strip_end_data_segment
# desc: remove the trailing non-code from $o->[CODE]
# args: $o - registry blessed object
# rtrn: nothing
#########################################################################
sub strip_end_data_segment {
${ +shift->[CODE] } =~ s/__(END|DATA)__(.*)//s;
}
#########################################################################
# func: compile
# dflt: compile
# desc: compile the code in $eval
# args: $o - registry blessed object
# $eval - a ref to a scalar with the code to compile
# rtrn: success/failure
#########################################################################
sub compile {
my($o, $eval) = @_;
my $r = $o->[REQ];
$o->debug("compiling $o->[FILENAME]") if DEBUG && D_COMPILE;
$r->clear_rgy_endav;
ModPerl::Util::untaint($$eval);
{
# let the code define its own warn and strict level
no strict;
no warnings FATAL => 'all'; # because we use FATAL
eval $$eval;
}
$r->stash_rgy_endav;
return $o->error_check;
}
#########################################################################
# func: error_check
# dflt: error_check
# desc: checks $@ for errors
# args: $o - registry blessed object
# rtrn: Apache::SERVER_ERROR if $@ is set, Apache::OK otherwise
#########################################################################
sub error_check {
my $o = shift;
if ($@ and substr($@,0,4) ne " at ") {
$o->[REQ]->log_error("$$: $o->[CLASS]: `$@'");
$@{$o->[REQ]->uri} = $@;
$@ = ''; #XXX fix me, if we don't do this Apache::exit() breaks
return Apache::SERVER_ERROR;
}
return Apache::OK;
}
### helper methods
sub debug{
my $o = shift;
$o->[REQ]->log_error("$$: $o->[CLASS]: " . join '', @_);
}
1;
__END__
=head1 NAME
ModPerl::RegistryCooker -
=head1 SYNOPSIS
=head1 DESCRIPTION
=cut
1.1 modperl-2.0/ModPerl-Registry/lib/ModPerl/RegistryNG.pm
Index: RegistryNG.pm
===================================================================
package ModPerl::RegistryNG;
# a back-compatibility placeholder
*ModPerl::RegistryNG:: = \*ModPerl::Registry::;
# META: prototyping ($$) segfaults on request
sub handler {
my $class = (@_ >= 2) ? shift : __PACKAGE__;
my $r = shift;
return $class->new($r)->default_handler();
}
1;
__END__
=head1 NAME
ModPerl::RegistryNG -- See ModPerl::Registry
=head1 SYNOPSIS
=head1 DESCRIPTION
C<ModPerl::RegistryNG> is the same as C<ModPerl::Registry>.
=cut
1.1 modperl-2.0/ModPerl-Registry/t/.cvsignore
Index: .cvsignore
===================================================================
logs
htdocs
1.1 modperl-2.0/ModPerl-Registry/t/TEST.PL
Index: TEST.PL
===================================================================
#!perl
use strict;
use warnings FATAL => 'all';
# XXX: fixme
#use lib map { "$_/Apache-Test/lib" } qw(. ..);
#use lib map { "$_/blib/lib" } qw(. .. ../..);
#use lib map { "$_/lib" } qw(. .. ../..);
#use blib map { $_ } qw(. .. ../..);
use lib map {("../blib/$_", "../../blib/$_")} qw(lib arch);
#use blib qw(..);
use Apache::TestRunPerl ();
Apache::TestRunPerl->new->run(@ARGV);
1.1 modperl-2.0/ModPerl-Registry/t/basic.t
Index: basic.t
===================================================================
use strict;
use warnings FATAL => 'all';
use ModPerl::Registry;
use Apache::Test;
use Apache::TestUtil;
use Apache::TestRequest;
my @modules = qw(registry registry_ng registry_bb perlrun);
plan tests => scalar @modules * 3;
my $cfg = Apache::Test::config();
# very basic compilation/response test
for my $module (@modules) {
my $url = "/$module/basic.pl";
ok t_cmp(
"ok",
$cfg->http_raw_get($url),
"basic cgi test",
);
}
# test non-executable bit
for my $module (@modules) {
my $url = "/$module/not_executable.pl";
ok t_cmp(
"403 Forbidden",
HEAD($url)->status_line(),
"non-executable file",
);
}
# test environment pre-set
for my $module (@modules) {
my $url = "/$module/env.pl?foo=bar";
ok t_cmp(
"foo=bar",
$cfg->http_raw_get($url),
"mod_cgi-like environment pre-set",
);
}
# chdir is not safe yet!
#
# require (actually chdir test)
#for my $module (@modules) {
# my $url = "/$module/require.pl";
# ok t_cmp(
# "it works",
# $cfg->http_raw_get($url),
# "mod_cgi-like environment pre-set",
# );
#}
1.1 modperl-2.0/ModPerl-Registry/t/closure.t
Index: closure.t
===================================================================
use strict;
use warnings FATAL => 'all';
use ModPerl::Registry;
use Apache::Test;
use File::Spec::Functions;
use Apache::TestUtil;
# this test tests how various registry packages cache and flush the
# scripts their run, and whether they check modification on the disk
# or not
my @modules = qw(registry registry_ng registry_bb perlrun);
plan tests => 6;
my $cfg = Apache::Test::config();
my $file = 'closure.pl';
my $path = catfile $cfg->{vars}->{serverroot}, 'cgi-bin', $file;
# for all sub-tests in this test, we assume that we always get onto
# the same interpreter (since there are no other requests happening in
# parallel
{
# ModPerl::PerlRun
# always flush
# no cache
my $url = "/perlrun/$file";
# should be no closure effect, always returns 1
my $first = $cfg->http_raw_get($url);
my $second = $cfg->http_raw_get($url);
ok t_cmp(
0,
$second - $first,
"never a closure problem",
);
# modify the file
sleep_and_touch_file($path);
# it doesn't matter, since the script is not cached anyway
ok t_cmp(
1,
$cfg->http_raw_get($url),
"never a closure problem",
);
}
{
# ModPerl::Registry
# no flush
# cache, but reload on modification
my $url = "/registry/$file";
# we don't know what other test has called this uri before, so we
# check the difference between two subsequent calls. In this case
# the difference should be 1.
my $first = $cfg->http_raw_get($url);
my $second = $cfg->http_raw_get($url);
ok t_cmp(
1,
$second - $first,
"closure problem should exist",
);
# modify the file
sleep_and_touch_file($path);
# should no notice closure effect on first request
ok t_cmp(
1,
$cfg->http_raw_get($url),
"no closure on the first request",
);
}
{
# ModPerl::RegistryBB
# no flush
# cache once, don't check for mods
my $url = "/registry_bb/$file";
# we don't know what other test has called this uri before, so we
# check the difference between two subsequent calls. In this case
# the difference should be 0.
my $first = $cfg->http_raw_get($url);
my $second = $cfg->http_raw_get($url);
ok t_cmp(
1,
$second - $first,
"closure problem should exist",
);
# modify the file
sleep_and_touch_file($path);
#
my $third = $cfg->http_raw_get($url);
ok t_cmp(
1,
$third - $second,
"no reload on mod, closure persist",
);
}
sub sleep_and_touch_file {
my $file = shift;
sleep 2; # so -M will be different, res: 1 sec, granularity > 1sec
my $now = time;
utime $now, $now, $file;
}
1.1 modperl-2.0/ModPerl-Registry/t/cgi-bin/basic.pl
Index: basic.pl
===================================================================
#!perl -w
# test all the basic functionality
print "Content-type: text/plain\r\n\r\n";
print "ok";
__END__
this is some irrelevant data
1.1 modperl-2.0/ModPerl-Registry/t/cgi-bin/closure.pl
Index: closure.pl
===================================================================
#!perl -w
# this script will suffer from a closure problem under registry
# should see it under ::Registry
# should not see it under ::PerlRun
print "Content-type: text/plain\r\n\r\n";
# this is a closure (when compiled inside handler()):
my $counter = 0;
counter();
sub counter {
#warn "$$";
print ++$counter;
}
1.1 modperl-2.0/ModPerl-Registry/t/cgi-bin/env.pl
Index: env.pl
===================================================================
# test env vars
print "Content-type: text/plain\r\n\r\n";
print exists $ENV{QUERY_STRING} && $ENV{QUERY_STRING};
__END__
1.1 modperl-2.0/ModPerl-Registry/t/cgi-bin/local-conf.pl
Index: local-conf.pl
===================================================================
$test_require = 'it works';
1;
1.1 modperl-2.0/ModPerl-Registry/t/cgi-bin/not_executable.pl
Index: not_executable.pl
===================================================================
#!perl -w
# this test should return forbidden, since it should be not-executable
print "Content-type: text/plain\r\n\r\n";
print "ok";
__END__
this is some irrelevant data
1.1 modperl-2.0/ModPerl-Registry/t/cgi-bin/require.pl
Index: require.pl
===================================================================
# test the require
print "Content-type: text/plain\r\n\r\n";
use lib qw(.);
my $file = "./local-conf.pl";
require $file;
print defined $test_require && $test_require;
1.1 modperl-2.0/ModPerl-Registry/t/conf/.cvsignore
Index: .cvsignore
===================================================================
extra.conf
httpd.conf
apache_test_config.pm
1.1 modperl-2.0/ModPerl-Registry/t/conf/extra.conf.in
Index: extra.conf.in
===================================================================
#this file will be Include-d by @ServerRoot@/httpd.conf
# make sure that we test under Taint mode
PerlSwitches -T
PerlSwitches -Mlib=@ServerRoot@/../lib
PerlSwitches -Mlib=@ServerRoot@/../../lib
PerlSwitches -Mlib=@ServerRoot@/../../blib/lib
PerlSwitches -Mlib=@ServerRoot@/../../blib/arch
Alias /registry/ @ServerRoot@/cgi-bin/
Alias /registry_ng/ @ServerRoot@/cgi-bin/
Alias /registry_bb/ @ServerRoot@/cgi-bin/
Alias /registry_oo_conf/ @ServerRoot@/cgi-bin/
Alias /perlrun/ @ServerRoot@/cgi-bin/
#PerlModule TestDebugMy
PerlSetVar ModPerl::RegistryCooker::DEBUG 0
### DEVMODE: Remove in production ###
PerlModule Apache::Reload
PerlInitHandler Apache::Reload
PerlSetVar ReloadAll Off
PerlSetVar ReloadModules "ModPerl::*"
PerlModule ModPerl::RegistryCooker
PerlModule ModPerl::Util
PerlModule ModPerl::RegistryNG
<Location /registry_ng>
PerlOptions +GlobalRequest
SetHandler perl-script
Options +ExecCGI
PerlResponseHandler ModPerl::RegistryNG
PerlOptions +ParseHeaders
</Location>
PerlModule ModPerl::RegistryBB
<Location /registry_bb>
PerlOptions +GlobalRequest
SetHandler perl-script
Options +ExecCGI
PerlResponseHandler ModPerl::RegistryBB
PerlOptions +ParseHeaders
</Location>
PerlModule ModPerl::PerlRun
<Location /perlrun>
PerlOptions +GlobalRequest
SetHandler perl-script
Options +ExecCGI
PerlResponseHandler ModPerl::PerlRun
PerlOptions +ParseHeaders
</Location>
PerlModule ModPerl::Registry
<Location /registry>
PerlOptions +GlobalRequest
SetHandler perl-script
Options +ExecCGI
PerlResponseHandler ModPerl::Registry
PerlOptions +ParseHeaders
</Location>
# META: dumps core on OO handlers
<Location /registry_oo_conf>
PerlOptions +GlobalRequest
SetHandler perl-script
Options +ExecCGI
PerlResponseHandler ModPerl::Registry->handler
PerlOptions +ParseHeaders
</Location>