From 901ce06e6c9218b93b84fee09f9720204623dc19 Mon Sep 17 00:00:00 2001 From: "mkanat%bugzilla.org" <> Date: Tue, 12 Sep 2006 04:27:52 +0000 Subject: Bug 345547: shutdownhtml will not work under mod_perl Patch By Max Kanat-Alexander r=justdave, a=justdave --- Bugzilla.pm | 123 +++++++++++++++++++++++--------------------------- Bugzilla/Constants.pm | 3 ++ mod_perl.pl | 69 ++++++++++++++++++++++++---- 3 files changed, 121 insertions(+), 74 deletions(-) diff --git a/Bugzilla.pm b/Bugzilla.pm index 24e93edc7..287e054ae 100644 --- a/Bugzilla.pm +++ b/Bugzilla.pm @@ -77,61 +77,65 @@ use constant SHUTDOWNHTML_EXIT_SILENTLY => [ #} #$::SIG{__DIE__} = \&Bugzilla::die_with_dignity; -# Some environment variables are not taint safe -delete @::ENV{'PATH', 'IFS', 'CDPATH', 'ENV', 'BASH_ENV'}; - -# If Bugzilla is shut down, do not allow anything to run, just display a -# message to the user about the downtime and log out. Scripts listed in -# SHUTDOWNHTML_EXEMPT are exempt from this message. -# -# Because this is code which is run live from perl "use" commands of other -# scripts, we're skipping this part if we get here during a perl syntax check -# -- runtests.pl compiles scripts without running them, so we need to make sure -# that this check doesn't apply to 'perl -c' calls. -# -# This code must go here. It cannot go anywhere in Bugzilla::CGI, because -# it uses Template, and that causes various dependency loops. -if (!$^C - && Bugzilla->params->{"shutdownhtml"} - && lsearch(SHUTDOWNHTML_EXEMPT, basename($0)) == -1) -{ - # Allow non-cgi scripts to exit silently (without displaying any - # message), if desired. At this point, no DBI call has been made - # yet, and no error will be returned if the DB is inaccessible. - if (lsearch(SHUTDOWNHTML_EXIT_SILENTLY, basename($0)) > -1 - && !i_am_cgi()) +sub init_page { + + # Some environment variables are not taint safe + delete @::ENV{'PATH', 'IFS', 'CDPATH', 'ENV', 'BASH_ENV'}; + + # If Bugzilla is shut down, do not allow anything to run, just display a + # message to the user about the downtime and log out. Scripts listed in + # SHUTDOWNHTML_EXEMPT are exempt from this message. + # + # Because this is code which is run live from perl "use" commands of other + # scripts, we're skipping this part if we get here during a perl syntax + # check -- runtests.pl compiles scripts without running them, so we + # need to make sure that this check doesn't apply to 'perl -c' calls. + # + # This code must go here. It cannot go anywhere in Bugzilla::CGI, because + # it uses Template, and that causes various dependency loops. + if (!$^C && Bugzilla->params->{"shutdownhtml"} + && lsearch(SHUTDOWNHTML_EXEMPT, basename($0)) == -1) { - exit; - } + # Allow non-cgi scripts to exit silently (without displaying any + # message), if desired. At this point, no DBI call has been made + # yet, and no error will be returned if the DB is inaccessible. + if (lsearch(SHUTDOWNHTML_EXIT_SILENTLY, basename($0)) > -1 + && !i_am_cgi()) + { + exit; + } - # For security reasons, log out users when Bugzilla is down. - # Bugzilla->login() is required to catch the logincookie, if any. - my $user = Bugzilla->login(LOGIN_OPTIONAL); - my $userid = $user->id; - Bugzilla->logout(); - - my $template = Bugzilla->template; - my $vars = {}; - $vars->{'message'} = 'shutdown'; - $vars->{'userid'} = $userid; - # Generate and return a message about the downtime, appropriately - # for if we're a command-line script or a CGI script. - my $extension; - if (i_am_cgi() && (!Bugzilla->cgi->param('ctype') - || Bugzilla->cgi->param('ctype') eq 'html')) { - $extension = 'html'; - } - else { - $extension = 'txt'; + # For security reasons, log out users when Bugzilla is down. + # Bugzilla->login() is required to catch the logincookie, if any. + my $user = Bugzilla->login(LOGIN_OPTIONAL); + my $userid = $user->id; + Bugzilla->logout(); + + my $template = Bugzilla->template; + my $vars = {}; + $vars->{'message'} = 'shutdown'; + $vars->{'userid'} = $userid; + # Generate and return a message about the downtime, appropriately + # for if we're a command-line script or a CGI script. + my $extension; + if (i_am_cgi() && (!Bugzilla->cgi->param('ctype') + || Bugzilla->cgi->param('ctype') eq 'html')) { + $extension = 'html'; + } + else { + $extension = 'txt'; + } + print Bugzilla->cgi->header() if i_am_cgi(); + my $t_output; + $template->process("global/message.$extension.tmpl", $vars, \$t_output) + || ThrowTemplateError($template->error); + print $t_output . "\n"; + exit; } - print Bugzilla->cgi->header() if i_am_cgi(); - my $t_output; - $template->process("global/message.$extension.tmpl", $vars, \$t_output) - || ThrowTemplateError($template->error); - print $t_output . "\n"; - exit; } +init_page() if !$ENV{MOD_PERL}; + ##################################################################### # Subroutines and Methods ##################################################################### @@ -352,21 +356,7 @@ sub hook_args { sub request_cache { if ($ENV{MOD_PERL}) { require Apache2::RequestUtil; - my $request = Apache2::RequestUtil->request; - my $cache = $request->pnotes(); - # Sometimes mod_perl doesn't properly call DESTROY on all - # the objects in pnotes(), so we register a cleanup handler - # to make sure that this happens. - if (!$cache->{cleanup_registered}) { - $request->push_handlers(PerlCleanupHandler => sub { - my $r = shift; - foreach my $key (keys %{$r->pnotes}) { - delete $r->pnotes->{$key}; - } - }); - $cache->{cleanup_registered} = 1; - } - return $cache; + return Apache2::RequestUtil->request->pnotes(); } return $_request_cache; } @@ -385,7 +375,8 @@ sub _cleanup { } sub END { - _cleanup(); + # Bugzilla.pm cannot compile in mod_perl.pl if this runs. + _cleanup() unless $ENV{MOD_PERL}; } 1; diff --git a/Bugzilla/Constants.pm b/Bugzilla/Constants.pm index 9559dcae3..93d8d8d2c 100644 --- a/Bugzilla/Constants.pm +++ b/Bugzilla/Constants.pm @@ -365,6 +365,9 @@ sub bz_locations { # That means that if you modify these paths, they must be absolute paths. return { 'libpath' => $libpath, + # If you put the libraries in a different location than the CGIs, + # make sure this still points to the CGIs. + 'cgi_path' => $libpath, 'templatedir' => "$libpath/template", 'project' => $project, 'localconfig' => "$libpath/$localconfig", diff --git a/mod_perl.pl b/mod_perl.pl index f36b219b6..05d781400 100644 --- a/mod_perl.pl +++ b/mod_perl.pl @@ -15,6 +15,8 @@ # # Contributor(s): Max Kanat-Alexander +package Bugzilla::ModPerl; + use strict; # If you have an Apache2::Status handler in your Apache configuration, @@ -27,27 +29,78 @@ use strict; # file. use Apache::DBI (); +use Apache2::ServerUtil; +use ModPerl::RegistryLoader (); +use CGI (); +CGI->compile(qw(:cgi -no_xhtml -oldstyle_urls :private_tempfiles + :unique_headers SERVER_PUSH :push)); +use Template::Config (); +Template::Config->preload(); + use Bugzilla (); use Bugzilla::Constants (); use Bugzilla::CGI (); use Bugzilla::Mailer (); use Bugzilla::Template (); use Bugzilla::Util (); -use CGI (); -CGI->compile(qw(:cgi -no_xhtml -oldstyle_urls :private_tempfiles - :unique_headers SERVER_PUSH :push)); -use Template::Config (); -Template::Config->preload(); -# ModPerl::RegistryLoader can pre-compile all CGI scripts. -use ModPerl::RegistryLoader (); +my $cgi_path = Bugzilla::Constants::bz_locations()->{'cgi_path'}; + +# Set up the configuration for the web server +my $server = Apache2::ServerUtil->server; +my $conf = < + AddHandler perl-script .cgi + # No need to PerlModule these because they're already defined in mod_perl.pl + PerlResponseHandler Bugzilla::ModPerl::ResponseHandler + PerlCleanupHandler Bugzilla::ModPerl::CleanupHandler + PerlOptions +ParseHeaders + Options +ExecCGI + +EOT + +$server->add_config([split("\n", $conf)]); + +# Have ModPerl::RegistryLoader pre-compile all CGI scripts. my $rl = new ModPerl::RegistryLoader(); # Note that $cgi_path will be wrong if somebody puts the libraries # in a different place than the CGIs. -my $cgi_path = Bugzilla::Constants::bz_locations()->{'libpath'}; foreach my $file (glob "$cgi_path/*.cgi") { Bugzilla::Util::trick_taint($file); $rl->handler($file, $file); } + +package Bugzilla::ModPerl::ResponseHandler; +use strict; +use base qw(ModPerl::Registry); +use Bugzilla; + +sub handler : method { + my $class = shift; + + # $0 is broken under mod_perl before 2.0.2, so we have to set it + # here explicitly or init_page's shutdownhtml code won't work right. + $0 = $ENV{'SCRIPT_FILENAME'}; + Bugzilla::init_page(); + return $class->SUPER::handler(@_); +} + + +package Bugzilla::ModPerl::CleanupHandler; +use strict; +use Apache2::Const -compile => qw(OK); + +sub handler { + my $r = shift; + + # Sometimes mod_perl doesn't properly call DESTROY on all + # the objects in pnotes() + foreach my $key (keys %{$r->pnotes}) { + delete $r->pnotes->{$key}; + } + + return Apache2::Const::OK; +} + 1; -- cgit v1.2.3-24-g4f1b