Commit 901ce06e authored by mkanat%bugzilla.org's avatar mkanat%bugzilla.org

Bug 345547: shutdownhtml will not work under mod_perl

Patch By Max Kanat-Alexander <mkanat@bugzilla.org> r=justdave, a=justdave
parent 5af900f5
...@@ -77,61 +77,65 @@ use constant SHUTDOWNHTML_EXIT_SILENTLY => [ ...@@ -77,61 +77,65 @@ use constant SHUTDOWNHTML_EXIT_SILENTLY => [
#} #}
#$::SIG{__DIE__} = \&Bugzilla::die_with_dignity; #$::SIG{__DIE__} = \&Bugzilla::die_with_dignity;
# Some environment variables are not taint safe sub init_page {
delete @::ENV{'PATH', 'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
# Some environment variables are not taint safe
# If Bugzilla is shut down, do not allow anything to run, just display a delete @::ENV{'PATH', 'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
# message to the user about the downtime and log out. Scripts listed in
# SHUTDOWNHTML_EXEMPT are exempt from this message. # 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
# Because this is code which is run live from perl "use" commands of other # SHUTDOWNHTML_EXEMPT are exempt from this message.
# 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 # Because this is code which is run live from perl "use" commands of other
# that this check doesn't apply to 'perl -c' calls. # scripts, we're skipping this part if we get here during a perl syntax
# # check -- runtests.pl compiles scripts without running them, so we
# This code must go here. It cannot go anywhere in Bugzilla::CGI, because # need to make sure that this check doesn't apply to 'perl -c' calls.
# it uses Template, and that causes various dependency loops. #
if (!$^C # This code must go here. It cannot go anywhere in Bugzilla::CGI, because
&& Bugzilla->params->{"shutdownhtml"} # it uses Template, and that causes various dependency loops.
&& lsearch(SHUTDOWNHTML_EXEMPT, basename($0)) == -1) 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())
{ {
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. # For security reasons, log out users when Bugzilla is down.
# Bugzilla->login() is required to catch the logincookie, if any. # Bugzilla->login() is required to catch the logincookie, if any.
my $user = Bugzilla->login(LOGIN_OPTIONAL); my $user = Bugzilla->login(LOGIN_OPTIONAL);
my $userid = $user->id; my $userid = $user->id;
Bugzilla->logout(); Bugzilla->logout();
my $template = Bugzilla->template; my $template = Bugzilla->template;
my $vars = {}; my $vars = {};
$vars->{'message'} = 'shutdown'; $vars->{'message'} = 'shutdown';
$vars->{'userid'} = $userid; $vars->{'userid'} = $userid;
# Generate and return a message about the downtime, appropriately # Generate and return a message about the downtime, appropriately
# for if we're a command-line script or a CGI script. # for if we're a command-line script or a CGI script.
my $extension; my $extension;
if (i_am_cgi() && (!Bugzilla->cgi->param('ctype') if (i_am_cgi() && (!Bugzilla->cgi->param('ctype')
|| Bugzilla->cgi->param('ctype') eq 'html')) { || Bugzilla->cgi->param('ctype') eq 'html')) {
$extension = 'html'; $extension = 'html';
} }
else { else {
$extension = 'txt'; $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 # Subroutines and Methods
##################################################################### #####################################################################
...@@ -352,21 +356,7 @@ sub hook_args { ...@@ -352,21 +356,7 @@ sub hook_args {
sub request_cache { sub request_cache {
if ($ENV{MOD_PERL}) { if ($ENV{MOD_PERL}) {
require Apache2::RequestUtil; require Apache2::RequestUtil;
my $request = Apache2::RequestUtil->request; return Apache2::RequestUtil->request->pnotes();
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 $_request_cache; return $_request_cache;
} }
...@@ -385,7 +375,8 @@ sub _cleanup { ...@@ -385,7 +375,8 @@ sub _cleanup {
} }
sub END { sub END {
_cleanup(); # Bugzilla.pm cannot compile in mod_perl.pl if this runs.
_cleanup() unless $ENV{MOD_PERL};
} }
1; 1;
......
...@@ -365,6 +365,9 @@ sub bz_locations { ...@@ -365,6 +365,9 @@ sub bz_locations {
# That means that if you modify these paths, they must be absolute paths. # That means that if you modify these paths, they must be absolute paths.
return { return {
'libpath' => $libpath, '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", 'templatedir' => "$libpath/template",
'project' => $project, 'project' => $project,
'localconfig' => "$libpath/$localconfig", 'localconfig' => "$libpath/$localconfig",
......
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
# #
# Contributor(s): Max Kanat-Alexander <mkanat@bugzilla.org> # Contributor(s): Max Kanat-Alexander <mkanat@bugzilla.org>
package Bugzilla::ModPerl;
use strict; use strict;
# If you have an Apache2::Status handler in your Apache configuration, # If you have an Apache2::Status handler in your Apache configuration,
...@@ -27,27 +29,78 @@ use strict; ...@@ -27,27 +29,78 @@ use strict;
# file. # file.
use Apache::DBI (); 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 ();
use Bugzilla::Constants (); use Bugzilla::Constants ();
use Bugzilla::CGI (); use Bugzilla::CGI ();
use Bugzilla::Mailer (); use Bugzilla::Mailer ();
use Bugzilla::Template (); use Bugzilla::Template ();
use Bugzilla::Util (); 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. my $cgi_path = Bugzilla::Constants::bz_locations()->{'cgi_path'};
use ModPerl::RegistryLoader ();
# Set up the configuration for the web server
my $server = Apache2::ServerUtil->server;
my $conf = <<EOT;
<Directory "$cgi_path">
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
</Directory>
EOT
$server->add_config([split("\n", $conf)]);
# Have ModPerl::RegistryLoader pre-compile all CGI scripts.
my $rl = new ModPerl::RegistryLoader(); my $rl = new ModPerl::RegistryLoader();
# Note that $cgi_path will be wrong if somebody puts the libraries # Note that $cgi_path will be wrong if somebody puts the libraries
# in a different place than the CGIs. # in a different place than the CGIs.
my $cgi_path = Bugzilla::Constants::bz_locations()->{'libpath'};
foreach my $file (glob "$cgi_path/*.cgi") { foreach my $file (glob "$cgi_path/*.cgi") {
Bugzilla::Util::trick_taint($file); Bugzilla::Util::trick_taint($file);
$rl->handler($file, $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; 1;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment