summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDylan William Hardison <dylan@hardison.net>2018-09-19 00:19:03 +0200
committerGitHub <noreply@github.com>2018-09-19 00:19:03 +0200
commitb8b2a943056adbb112474df7bdf766970a56b2dc (patch)
treeac62e6bcd7d795066ce66256a6fdf2d1be101514
parent2f3ca2822570ae271ca4603b5d3de119b40d9eb8 (diff)
downloadbugzilla-b8b2a943056adbb112474df7bdf766970a56b2dc.tar.gz
bugzilla-b8b2a943056adbb112474df7bdf766970a56b2dc.tar.xz
Bug 1455495 - Replace apache with Mojolicious
-rw-r--r--.circleci/config.yml8
-rw-r--r--.perlcriticrc2
-rw-r--r--Bugzilla.pm3
-rw-r--r--Bugzilla/Attachment/PatchReader.pm15
-rw-r--r--Bugzilla/CGI.pm36
-rw-r--r--Bugzilla/Config/General.pm6
-rw-r--r--Bugzilla/DaemonControl.pm26
-rw-r--r--Bugzilla/Error.pm4
-rw-r--r--Bugzilla/Install/Filesystem.pm135
-rw-r--r--Bugzilla/Memcached.pm2
-rw-r--r--Bugzilla/ModPerl.pm118
-rw-r--r--Bugzilla/ModPerl/BasicAuth.pm65
-rw-r--r--Bugzilla/ModPerl/BlockIP.pm65
-rw-r--r--Bugzilla/ModPerl/Hostage.pm71
-rw-r--r--Bugzilla/ModPerl/StartupFix.pm51
-rw-r--r--Bugzilla/Quantum.pm118
-rw-r--r--Bugzilla/Quantum/CGI.pm160
-rw-r--r--Bugzilla/Quantum/Plugin/BasicAuth.pm40
-rw-r--r--Bugzilla/Quantum/Plugin/BlockIP.pm43
-rw-r--r--Bugzilla/Quantum/Plugin/Glue.pm101
-rw-r--r--Bugzilla/Quantum/Plugin/Hostage.pm86
-rw-r--r--[-rwxr-xr-x]Bugzilla/Quantum/SES.pm (renamed from ses/index.cgi)150
-rw-r--r--Bugzilla/Quantum/Static.pm30
-rw-r--r--Bugzilla/Quantum/Stdout.pm60
-rw-r--r--Bugzilla/Template.pm1
-rw-r--r--Bugzilla/Util.pm3
-rw-r--r--Bugzilla/WebService/Server/XMLRPC.pm6
-rw-r--r--Bugzilla/WebService/Util.pm8
-rw-r--r--Dockerfile11
-rw-r--r--Log/Log4perl/Layout/Mozilla.pm3
-rwxr-xr-xMakefile.PL20
-rw-r--r--README.rst35
-rwxr-xr-xbuglist.cgi50
-rwxr-xr-xbugzilla.pl20
-rwxr-xr-xchecksetup.pl3
-rwxr-xr-xcolchange.cgi16
-rw-r--r--conf/httpd.conf103
-rw-r--r--conf/log4perl-test.conf4
-rw-r--r--docker-compose.yml1
-rw-r--r--docs/en/rst/administering/parameters.rst6
-rw-r--r--docs/en/rst/style.rst5
-rwxr-xr-xeditparams.cgi3
-rw-r--r--extensions/BMO/Extension.pm101
-rwxr-xr-xheartbeat.cgi10
-rwxr-xr-x[-rw-r--r--]jobqueue-worker.pl0
-rw-r--r--mod_perl.pl204
-rw-r--r--qa/t/lib/QA/Util.pm28
-rw-r--r--qa/t/test_bug_edit.t117
-rw-r--r--qa/t/test_shutdown.t72
-rwxr-xr-xscripts/block-ip.pl10
-rwxr-xr-xscripts/entrypoint.pl14
-rwxr-xr-x[-rw-r--r--]scripts/undo.pl0
-rw-r--r--t/001compile.t14
-rw-r--r--t/002goodperl.t7
-rw-r--r--template/en/default/admin/params/editparams.html.tmpl1
-rw-r--r--template/en/default/admin/params/general.html.tmpl5
-rw-r--r--template/en/default/global/field-descs.none.tmpl10
-rw-r--r--template/en/default/global/header.html.tmpl2
-rw-r--r--template/en/default/global/messages.html.tmpl62
-rw-r--r--vagrant_support/apache.yml8
-rwxr-xr-xvagrant_support/hypnotoad122
-rw-r--r--vagrant_support/hypnotoad.yml27
-rw-r--r--vagrant_support/playbook.yml6
-rw-r--r--vagrant_support/update.yml5
64 files changed, 1237 insertions, 1281 deletions
diff --git a/.circleci/config.yml b/.circleci/config.yml
index fe1263ee9..f64524c80 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -7,7 +7,7 @@ version: 2
defaults:
bmo_slim_image: &bmo_slim_image
- image: mozillabteam/bmo-slim:20180801.2
+ image: mozillabteam/bmo-slim:20180809.1
user: app
mysql_image: &mysql_image
@@ -37,12 +37,6 @@ defaults:
BMO_memcached_servers: localhost:11211
BMO_memcached_namespace: "bugzilla:"
BMO_urlbase: AUTOMATIC
- HTTPD_StartServers: 1
- HTTPD_MinSpareServers: 1
- HTTPD_MaxSpareServers: 1
- HTTPD_ServerLimit: 1
- HTTPD_MaxClients: 1
- HTTPD_MaxRequestsPerChild: 4000
mysql_env: &mysql_env
MYSQL_DATABASE: bugs
diff --git a/.perlcriticrc b/.perlcriticrc
index 0b8e4c862..d5fc03fa0 100644
--- a/.perlcriticrc
+++ b/.perlcriticrc
@@ -5,6 +5,8 @@ severity = 1
#perltidyrc = .perltidyrc
#severity = 2
+[-CodeLayout::ProhibitParensWithBuiltins]
+
[InputOutput::RequireCheckedSyscalls]
severity = 2
functions = :builtins
diff --git a/Bugzilla.pm b/Bugzilla.pm
index 69b255d17..bb036fb06 100644
--- a/Bugzilla.pm
+++ b/Bugzilla.pm
@@ -838,7 +838,7 @@ sub check_rate_limit {
my $limit = join("/", @$limit);
Bugzilla->audit("[rate_limit] action=$action, ip=$ip, limit=$limit, name=$name");
if ($action eq 'block') {
- Bugzilla::ModPerl::BlockIP->block_ip($ip);
+ $Bugzilla::Quantum::CGI::C->block_ip($ip);
ThrowUserError("rate_limit");
}
}
@@ -854,6 +854,7 @@ sub markdown_parser {
# Per-process cleanup. Note that this is a plain subroutine, not a method,
# so we don't have $class available.
+*cleanup = \&_cleanup;
sub _cleanup {
return if $^C;
diff --git a/Bugzilla/Attachment/PatchReader.pm b/Bugzilla/Attachment/PatchReader.pm
index 2cfbf2c6b..8025f5b82 100644
--- a/Bugzilla/Attachment/PatchReader.pm
+++ b/Bugzilla/Attachment/PatchReader.pm
@@ -116,18 +116,9 @@ sub process_interdiff {
$ENV{'PATH'} = $lc->{diffpath};
my ($pid, $interdiff_stdout, $interdiff_stderr);
- if ($ENV{MOD_PERL}) {
- require Apache2::RequestUtil;
- require Apache2::SubProcess;
- my $request = Apache2::RequestUtil->request;
- (undef, $interdiff_stdout, $interdiff_stderr) = $request->spawn_proc_prog(
- $lc->{interdiffbin}, [$old_filename, $new_filename]
- );
- } else {
- $interdiff_stderr = gensym;
- my $pid = open3(gensym, $interdiff_stdout, $interdiff_stderr,
- $lc->{interdiffbin}, $old_filename, $new_filename);
- }
+ $interdiff_stderr = gensym;
+ $pid = open3(gensym, $interdiff_stdout, $interdiff_stderr,
+ $lc->{interdiffbin}, $old_filename, $new_filename);
binmode $interdiff_stdout;
# Check for errors
diff --git a/Bugzilla/CGI.pm b/Bugzilla/CGI.pm
index 985e504f7..e76b1c609 100644
--- a/Bugzilla/CGI.pm
+++ b/Bugzilla/CGI.pm
@@ -117,7 +117,7 @@ sub new {
# Under mod_perl, CGI's global variables get reset on each request,
# so we need to set them up again every time.
- $class->_init_bz_cgi_globals() if $ENV{MOD_PERL};
+ $class->_init_bz_cgi_globals();
my $self = $class->SUPER::new(@args);
@@ -135,6 +135,7 @@ sub new {
# apache collapses // to / in $ENV{PATH_INFO} but not in $self->path_info.
# url() requires the full path in ENV in order to generate the correct url.
$ENV{PATH_INFO} = $path;
+ DEBUG("redirecting because we see PATH_INFO and don't like it");
print $self->redirect($self->url(-path => 0, -query => 1));
exit;
}
@@ -145,6 +146,7 @@ sub new {
# Redirect to urlbase if we are not viewing an attachment.
if ($self->url_is_attachment_base and $script ne 'attachment.cgi') {
+ DEBUG("Redirecting to urlbase because the url is in the attachment base and not attachment.cgi");
$self->redirect_to_urlbase();
}
@@ -475,11 +477,6 @@ sub _prevent_unsafe_response {
print $self->SUPER::header(-type => 'text/html', -status => '403 Forbidden');
if ($content_type ne 'text/html') {
print "Untrusted Referer Header\n";
- if ($ENV{MOD_PERL}) {
- my $r = $self->r;
- $r->rflush;
- $r->status(200);
- }
}
exit;
}
@@ -597,8 +594,25 @@ sub header {
$headers{'-link'} .= ', <https://www.google-analytics.com>; rel="preconnect"; crossorigin';
}
}
-
- return $self->SUPER::header(%headers) || "";
+ my $headers = $self->SUPER::header(%headers) || '';
+ if ($self->server_software eq 'Bugzilla::Quantum::CGI') {
+ my $c = $Bugzilla::Quantum::CGI::C;
+ $c->res->headers->parse($headers);
+ my $status = $c->res->headers->status;
+ if ($status && $status =~ /^([0-9]+)/) {
+ $c->res->code($1);
+ }
+ elsif ($c->res->headers->location) {
+ $c->res->code(302);
+ }
+ else {
+ $c->res->code(200);
+ }
+ return '';
+ }
+ else {
+ LOGDIE("Bugzilla::CGI->header() should only be called from inside Bugzilla::Quantum::CGI!");
+ }
}
sub param {
@@ -715,6 +729,7 @@ sub redirect {
return $self->SUPER::redirect(@_);
}
+use Bugzilla::Logging;
# This helps implement Bugzilla::Search::Recent, and also shortens search
# URLs that get POSTed to buglist.cgi.
sub redirect_search_url {
@@ -763,6 +778,7 @@ sub redirect_search_url {
# are only redirected if they're under the CGI_URI_LIMIT though.
my $self_url = $self->self_url();
if ($self->request_method() ne 'POST' or length($self_url) < CGI_URI_LIMIT) {
+ DEBUG("Redirecting search url");
print $self->redirect(-url => $self_url);
exit;
}
@@ -784,10 +800,8 @@ sub redirect_to_https {
# XML-RPC clients (SOAP::Lite at least) require a 301 to redirect properly
# and do not work with 302. Our redirect really is permanent anyhow, so
# it doesn't hurt to make it a 301.
+ DEBUG("Redirecting to https");
print $self->redirect(-location => $url, -status => 301);
-
- # When using XML-RPC with mod_perl, we need the headers sent immediately.
- $self->r->rflush if $ENV{MOD_PERL};
exit;
}
diff --git a/Bugzilla/Config/General.pm b/Bugzilla/Config/General.pm
index 15688dfd3..c870c7376 100644
--- a/Bugzilla/Config/General.pm
+++ b/Bugzilla/Config/General.pm
@@ -40,12 +40,6 @@ use constant get_param_list => (
},
{
- name => 'shutdownhtml',
- type => 'l',
- default => ''
- },
-
- {
name => 'announcehtml',
type => 'l',
default => ''
diff --git a/Bugzilla/DaemonControl.pm b/Bugzilla/DaemonControl.pm
index 6ff883af0..5cb32973f 100644
--- a/Bugzilla/DaemonControl.pm
+++ b/Bugzilla/DaemonControl.pm
@@ -23,7 +23,8 @@ use IO::Async::Protocol::LineStream;
use IO::Async::Signal;
use IO::Socket;
use LWP::Simple qw(get);
-use POSIX qw(setsid WEXITSTATUS);
+use JSON::MaybeXS qw(encode_json);
+use POSIX qw(WEXITSTATUS);
use base qw(Exporter);
@@ -43,8 +44,14 @@ our %EXPORT_TAGS = (
my $BUGZILLA_DIR = bz_locations->{cgi_path};
my $JOBQUEUE_BIN = catfile( $BUGZILLA_DIR, 'jobqueue.pl' );
my $CEREAL_BIN = catfile( $BUGZILLA_DIR, 'scripts', 'cereal.pl' );
-my $HTTPD_BIN = '/usr/sbin/httpd';
-my $HTTPD_CONFIG = catfile( bz_locations->{confdir}, 'httpd.conf' );
+my $BUGZILLA_BIN = catfile( $BUGZILLA_DIR, 'bugzilla.pl' );
+my $HYPNOTOAD_BIN = catfile( $BUGZILLA_DIR, 'local', 'bin', 'hypnotoad' );
+my @PERL5LIB = ( $BUGZILLA_DIR, catdir($BUGZILLA_DIR, 'lib'), catdir($BUGZILLA_DIR, 'local', 'lib', 'perl5') );
+
+my %HTTP_BACKENDS = (
+ hypnotoad => [ $HYPNOTOAD_BIN, $BUGZILLA_BIN, '-f' ],
+ simple => [ $BUGZILLA_BIN, 'daemon' ],
+);
sub catch_signal {
my ($name, @done) = @_;
@@ -98,13 +105,12 @@ sub run_httpd {
my $exit_f = $loop->new_future;
my $httpd = IO::Async::Process->new(
code => sub {
-
- # we have to setsid() to make a new process group
- # or else apache will kill its parent.
- setsid();
- my @command = ( $HTTPD_BIN, '-DFOREGROUND', '-f' => $HTTPD_CONFIG, @args );
- exec @command
- or die "failed to exec $command[0] $!";
+ $ENV{BUGZILLA_HTTPD_ARGS} = encode_json(\@args);
+ $ENV{PERL5LIB} = join(':', @PERL5LIB);
+ my $backend = $ENV{HTTP_BACKEND} // 'hypnotoad';
+ my $command = $HTTP_BACKENDS{ $backend };
+ exec @$command
+ or die "failed to exec $command->[0] $!";
},
on_finish => on_finish($exit_f),
on_exception => on_exception( 'httpd', $exit_f ),
diff --git a/Bugzilla/Error.pm b/Bugzilla/Error.pm
index 9fcd16386..f932294b0 100644
--- a/Bugzilla/Error.pm
+++ b/Bugzilla/Error.pm
@@ -31,7 +31,7 @@ use Scalar::Util qw(blessed);
sub _in_eval {
my $in_eval = 0;
for (my $stack = 1; my $sub = (caller($stack))[3]; $stack++) {
- last if $sub =~ /^ModPerl/;
+ last if $sub =~ /^Bugzilla::Quantum::CGI::try/;
$in_eval = 1 if $sub =~ /^\(eval\)/;
}
return $in_eval;
@@ -196,7 +196,7 @@ sub ThrowTemplateError {
# mod_perl overrides exit to call die with this string
# we never want to display this to the user
- exit if $template_err =~ /\bModPerl::Util::exit\b/;
+ die $template_err if ref($template_err) eq 'ARRAY' && $template_err->[0] eq "EXIT\n";
state $logger = Log::Log4perl->get_logger('Bugzilla.Error.Template');
$logger->error($template_err);
diff --git a/Bugzilla/Install/Filesystem.pm b/Bugzilla/Install/Filesystem.pm
index 003be22e4..317152962 100644
--- a/Bugzilla/Install/Filesystem.pm
+++ b/Bugzilla/Install/Filesystem.pm
@@ -41,56 +41,11 @@ use English qw(-no_match_vars $OSNAME);
use base qw(Exporter);
our @EXPORT = qw(
update_filesystem
- create_htaccess
fix_all_file_permissions
fix_dir_permissions
fix_file_permissions
);
-use constant HT_DEFAULT_DENY => <<'EOT';
-# nothing in this directory is retrievable unless overridden by an .htaccess
-# in a subdirectory
-deny from all
-EOT
-
-use constant HT_GRAPHS_DIR => <<'EOT';
-# Allow access to .png and .gif files.
-<FilesMatch (\.gif|\.png)$>
- Allow from all
-</FilesMatch>
-
-# And no directory listings, either.
-Deny from all
-EOT
-
-use constant HT_WEBDOT_DIR => <<'EOT';
-# Restrict access to .dot files to the public webdot server at research.att.com
-# if research.att.com ever changes their IP, or if you use a different
-# webdot server, you'll need to edit this
-<FilesMatch \.dot$>
- Allow from 192.20.225.0/24
- Deny from all
-</FilesMatch>
-
-# Allow access to .png files created by a local copy of 'dot'
-<FilesMatch \.png\$>
- Allow from all
-</FilesMatch>
-
-# And no directory listings, either.
-Deny from all
-EOT
-
-use constant HT_ASSETS_DIR => <<'EOT';
-# Allow access to .css and js files
-<FilesMatch \.(css|js)$>
- Allow from all
-</FilesMatch>
-
-# And no directory listings, either.
-Deny from all
-EOT
-
use constant INDEX_HTML => <<'EOT';
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
@@ -112,11 +67,6 @@ use constant HTTPD_ENV => qw(
NYTPROF_DIR
);
-sub HTTPD_ENV_CONF {
- my @env = (ENV_KEYS, HTTPD_ENV);
- return join( "\n", map { "PerlPassEnv " . $_ } @env ) . "\n";
-}
-
###############
# Permissions #
###############
@@ -230,13 +180,13 @@ sub FILESYSTEM {
'jobqueue-worker.pl' => { perms => OWNER_EXECUTE },
'clean-bug-user-last-visit.pl' => { perms => WS_EXECUTE },
+ 'bugzilla.pl' => { perms => OWNER_EXECUTE },
'Bugzilla.pm' => { perms => CGI_READ },
"$localconfig*" => { perms => CGI_READ },
'META.*' => { perms => CGI_READ },
'MYMETA.*' => { perms => CGI_READ },
'bugzilla.dtd' => { perms => WS_SERVE },
'mod_perl.pl' => { perms => WS_SERVE },
- '.htaccess' => { perms => WS_SERVE },
'cvs-update.log' => { perms => WS_SERVE },
'scripts/sendunsentbugmail.pl' => { perms => WS_EXECUTE },
'docs/bugzilla.ent' => { perms => OWNER_WRITE },
@@ -427,9 +377,6 @@ sub FILESYSTEM {
"skins/yui3.css" => { perms => CGI_READ,
overwrite => 1,
contents => $yui3_all_css },
- "$confdir/env.conf" => { perms => CGI_READ,
- overwrite => 1,
- contents => \&HTTPD_ENV_CONF },
);
# Because checksetup controls the creation of index.html separately
@@ -438,54 +385,15 @@ sub FILESYSTEM {
'index.html' => { perms => WS_SERVE, contents => INDEX_HTML }
);
- # Because checksetup controls the .htaccess creation separately
- # by a localconfig variable, these go in a separate variable from
- # %create_files.
- #
- # Note that these get WS_SERVE as their permission
- # because they're *read* by the webserver, even though they're not
- # actually, themselves, served.
- my %htaccess = (
- "$attachdir/.htaccess" => { perms => WS_SERVE,
- contents => HT_DEFAULT_DENY },
- "$libdir/Bugzilla/.htaccess" => { perms => WS_SERVE,
- contents => HT_DEFAULT_DENY },
- "$extlib/.htaccess" => { perms => WS_SERVE,
- contents => HT_DEFAULT_DENY },
- "$templatedir/.htaccess" => { perms => WS_SERVE,
- contents => HT_DEFAULT_DENY },
- 'contrib/.htaccess' => { perms => WS_SERVE,
- contents => HT_DEFAULT_DENY },
- 'scripts/.htaccess' => { perms => WS_SERVE,
- contents => HT_DEFAULT_DENY },
- 't/.htaccess' => { perms => WS_SERVE,
- contents => HT_DEFAULT_DENY },
- 'xt/.htaccess' => { perms => WS_SERVE,
- contents => HT_DEFAULT_DENY },
- '.circleci/.htaccess' => { perms => WS_SERVE,
- contents => HT_DEFAULT_DENY },
- "$confdir/.htaccess" => { perms => WS_SERVE,
- contents => HT_DEFAULT_DENY },
- "$datadir/.htaccess" => { perms => WS_SERVE,
- contents => HT_DEFAULT_DENY },
- "$graphsdir/.htaccess" => { perms => WS_SERVE,
- contents => HT_GRAPHS_DIR },
- "$webdotdir/.htaccess" => { perms => WS_SERVE,
- contents => HT_WEBDOT_DIR },
- "$assetsdir/.htaccess" => { perms => WS_SERVE,
- contents => HT_ASSETS_DIR },
- );
-
Bugzilla::Hook::process('install_filesystem', {
files => \%files,
create_dirs => \%create_dirs,
non_recurse_dirs => \%non_recurse_dirs,
recurse_dirs => \%recurse_dirs,
create_files => \%create_files,
- htaccess => \%htaccess,
});
- my %all_files = (%create_files, %htaccess, %index_html, %files);
+ my %all_files = (%create_files, %index_html, %files);
my %all_dirs = (%create_dirs, %non_recurse_dirs);
return {
@@ -494,7 +402,6 @@ sub FILESYSTEM {
all_dirs => \%all_dirs,
create_files => \%create_files,
- htaccess => \%htaccess,
index_html => \%index_html,
all_files => \%all_files,
};
@@ -542,13 +449,6 @@ sub update_filesystem {
_rename_file($oldparamsfile, "$datadir/$oldparamsfile");
}
- # Remove old assets htaccess file to force recreation with correct values.
- if (-e "$assetsdir/.htaccess") {
- if (read_file("$assetsdir/.htaccess") =~ /<FilesMatch \\\.css\$>/) {
- unlink("$assetsdir/.htaccess");
- }
- }
-
_create_files(%files);
if ($params->{index_html}) {
_create_files(%{$fs->{index_html}});
@@ -653,27 +553,6 @@ sub _convert_single_file_skins {
}
}
-sub create_htaccess {
- _create_files(%{FILESYSTEM()->{htaccess}});
-
- # Repair old .htaccess files
-
- my $webdot_dir = bz_locations()->{'webdotdir'};
- # The public webdot IP address changed.
- my $webdot = new IO::File("$webdot_dir/.htaccess", 'r')
- || die "$webdot_dir/.htaccess: $!";
- my $webdot_data;
- { local $/; $webdot_data = <$webdot>; }
- $webdot->close;
- if ($webdot_data =~ /192\.20\.225\.10/) {
- print "Repairing $webdot_dir/.htaccess...\n";
- $webdot_data =~ s/192\.20\.225\.10/192.20.225.0\/24/g;
- $webdot = new IO::File("$webdot_dir/.htaccess", 'w') || die $!;
- print $webdot $webdot_data;
- $webdot->close;
- }
-}
-
sub _rename_file {
my ($from, $to) = @_;
print install_string('file_rename', { from => $from, to => $to }), "\n";
@@ -984,16 +863,6 @@ Params: C<index_html> - Whether or not we should create
Returns: nothing
-=item C<create_htaccess()>
-
-Description: Creates all of the .htaccess files for Apache,
- in the various Bugzilla directories. Also updates
- the .htaccess files if they need updating.
-
-Params: none
-
-Returns: nothing
-
=item C<fix_all_file_permissions($output)>
Description: Sets all the file permissions on all of Bugzilla's files
diff --git a/Bugzilla/Memcached.pm b/Bugzilla/Memcached.pm
index 40755aa29..6bbef080a 100644
--- a/Bugzilla/Memcached.pm
+++ b/Bugzilla/Memcached.pm
@@ -25,6 +25,8 @@ use Sys::Syslog qw(:DEFAULT);
use constant MAX_KEY_LENGTH => 250;
use constant RATE_LIMIT_PREFIX => "rate:";
+*new = \&_new;
+
sub _new {
my $invocant = shift;
my $class = ref($invocant) || $invocant;
diff --git a/Bugzilla/ModPerl.pm b/Bugzilla/ModPerl.pm
deleted file mode 100644
index 19cd1128f..000000000
--- a/Bugzilla/ModPerl.pm
+++ /dev/null
@@ -1,118 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-#
-# This Source Code Form is "Incompatible With Secondary Licenses", as
-# defined by the Mozilla Public License, v. 2.0.
-package Bugzilla::ModPerl;
-
-use 5.10.1;
-use strict;
-use warnings;
-
-use File::Find ();
-use Cwd ();
-use Carp ();
-
-# We don't need (or want) to use Bugzilla's template subclass.
-# it is easier to reason with the code without all the extra things Bugzilla::Template adds
-# (and there might be side-effects, since this code is loaded very early in the httpd startup)
-use Template ();
-
-use Bugzilla::ModPerl::BlockIP;
-use Bugzilla::ModPerl::Hostage;
-
-sub apache_config {
- my ($class, $cgi_path) = @_;
-
- Carp::croak "\$cgi_path is required" unless $cgi_path;
-
- my %htaccess;
- $cgi_path = Cwd::realpath($cgi_path);
- my $wanted = sub {
- package File::Find;
- our ($name, $dir);
-
- if ($name =~ m#/\.htaccess$#) {
- open my $fh, '<', $name or die "cannot open $name $!";
- my $contents = do {
- local $/ = undef;
- <$fh>;
- };
- close $fh;
- $htaccess{$dir} = { file => $name, contents => $contents, dir => $dir };
- }
- };
-
- File::Find::find( { wanted => $wanted, no_chdir => 1 }, $cgi_path );
- my $template = Template->new;
- my $conf;
- my %vars = (
- root_htaccess => delete $htaccess{$cgi_path},
- htaccess_files => [ map { $htaccess{$_} } sort { length $a <=> length $b } keys %htaccess ],
- cgi_path => $cgi_path,
- );
- $template->process(\*DATA, \%vars, \$conf);
- my $apache_version = Apache2::ServerUtil::get_server_version();
- if ($apache_version =~ m!Apache/(\d+)\.(\d+)\.(\d+)!) {
- my ($major, $minor, $patch) = ($1, $2, $3);
- if ($major > 2 || $major == 2 && $minor >= 4) {
- $conf =~ s{^\s+deny\s+from\s+all.*$}{Require all denied}gmi;
- $conf =~ s{^\s+allow\s+from\s+all.*$}{Require all granted}gmi;
- $conf =~ s{^\s+allow\s+from\s+(\S+).*$}{Require host $1}gmi;
- }
- }
-
- return $conf;
-}
-
-1;
-
-__DATA__
-# Make sure each httpd child receives a different random seed (bug 476622).
-# Bugzilla::RNG has one srand that needs to be called for
-# every process, and Perl has another. (Various Perl modules still use
-# the built-in rand(), even though we never use it in Bugzilla itself,
-# so we need to srand() both of them.)
-PerlChildInitHandler "sub { Bugzilla::RNG::srand(); srand(); eval { Bugzilla->dbh->ping } }"
-PerlInitHandler Bugzilla::ModPerl::Hostage
-PerlAccessHandler Bugzilla::ModPerl::BlockIP
-
-# It is important to specify ErrorDocuments outside of all directories.
-# These used to be in .htaccess, but then things like "AllowEncodedSlashes no"
-# mean that urls containing %2f are unstyled.
-ErrorDocument 401 /errors/401.html
-ErrorDocument 403 /errors/403.html
-ErrorDocument 404 /errors/404.html
-ErrorDocument 500 /errors/500.html
-
-<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 Apache2::SizeLimit
- PerlOptions +ParseHeaders
- Options +ExecCGI +FollowSymLinks
- DirectoryIndex index.cgi index.html
- AllowOverride none
- # from [% root_htaccess.file %]
- [% root_htaccess.contents FILTER indent %]
-</Directory>
-
-# AWS SES endpoint for handling mail bounces/complaints
-<Location "/ses">
- PerlSetEnv AUTH_VAR_NAME ses_username
- PerlSetEnv AUTH_VAR_PASS ses_password
- PerlAuthenHandler Bugzilla::ModPerl::BasicAuth
- AuthName SES
- AuthType Basic
- require valid-user
-</Location>
-
-# directory rules for all the other places we have .htaccess files
-[% FOREACH htaccess IN htaccess_files %]
-# from [% htaccess.file %]
-<Directory "[% htaccess.dir %]">
- [% htaccess.contents FILTER indent %]
-</Directory>
-[% END %]
diff --git a/Bugzilla/ModPerl/BasicAuth.pm b/Bugzilla/ModPerl/BasicAuth.pm
deleted file mode 100644
index 7248a19f3..000000000
--- a/Bugzilla/ModPerl/BasicAuth.pm
+++ /dev/null
@@ -1,65 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-#
-# This Source Code Form is "Incompatible With Secondary Licenses", as
-# defined by the Mozilla Public License, v. 2.0.
-package Bugzilla::ModPerl::BasicAuth;
-use 5.10.1;
-use strict;
-use warnings;
-
-# Protects a mod_perl <Location> with Basic HTTP authentication.
-#
-# Example use:
-#
-# <Location "/ses">
-# PerlAuthenHandler Bugzilla::ModPerl::BasicAuth
-# PerlSetEnv AUTH_VAR_NAME ses_username
-# PerlSetEnv AUTH_VAR_PASS ses_password
-# AuthName SES
-# AuthType Basic
-# require valid-user
-# </Location>
-#
-# AUTH_VAR_NAME and AUTH_VAR_PASS are the names of variables defined in
-# `localconfig` which hold the authentication credentials.
-
-use Apache2::Const -compile => qw(OK HTTP_UNAUTHORIZED); ## no critic (Freenode::ModPerl)
-use Bugzilla::Logging;
-use Bugzilla ();
-
-sub handler {
- my $r = shift;
- my ($status, $password) = $r->get_basic_auth_pw;
- if ($status != Apache2::Const::OK) {
- WARN("Got non-OK status: $status when trying to get password");
- return $status
- }
-
- my $auth_var_name = $ENV{AUTH_VAR_NAME};
- my $auth_var_pass = $ENV{AUTH_VAR_PASS};
- unless ($auth_var_name && $auth_var_pass) {
- ERROR('AUTH_VAR_NAME and AUTH_VAR_PASS environmental vars not set');
- $r->note_basic_auth_failure;
- return Apache2::Const::HTTP_UNAUTHORIZED;
- }
-
- my $auth_user = Bugzilla->localconfig->{$auth_var_name};
- my $auth_pass = Bugzilla->localconfig->{$auth_var_pass};
- unless ($auth_user && $auth_pass) {
- ERROR("$auth_var_name and $auth_var_pass not configured");
- $r->note_basic_auth_failure;
- return Apache2::Const::HTTP_UNAUTHORIZED;
- }
-
- unless ($r->user eq $auth_user && $password eq $auth_pass) {
- $r->note_basic_auth_failure;
- WARN('username and password do not match');
- return Apache2::Const::HTTP_UNAUTHORIZED;
- }
-
- return Apache2::Const::OK;
-}
-
-1;
diff --git a/Bugzilla/ModPerl/BlockIP.pm b/Bugzilla/ModPerl/BlockIP.pm
deleted file mode 100644
index 4e9a4be5c..000000000
--- a/Bugzilla/ModPerl/BlockIP.pm
+++ /dev/null
@@ -1,65 +0,0 @@
-package Bugzilla::ModPerl::BlockIP;
-use 5.10.1;
-use strict;
-use warnings;
-
-use Apache2::RequestRec ();
-use Apache2::Connection ();
-
-use Apache2::Const -compile => qw(OK);
-use Cache::Memcached::Fast;
-
-use constant BLOCK_TIMEOUT => 60*60;
-
-my $MEMCACHED = Bugzilla::Memcached->_new()->{memcached};
-my $STATIC_URI = qr{
- ^/
- (?: extensions/[^/]+/web
- | robots\.txt
- | __heartbeat__
- | __lbheartbeat__
- | __version__
- | images
- | skins
- | js
- | errors
- )
-}xms;
-
-sub block_ip {
- my ($class, $ip) = @_;
- $MEMCACHED->set("block_ip:$ip" => 1, BLOCK_TIMEOUT) if $MEMCACHED;
-}
-
-sub unblock_ip {
- my ($class, $ip) = @_;
- $MEMCACHED->delete("block_ip:$ip") if $MEMCACHED;
-}
-
-sub handler {
- my $r = shift;
- return Apache2::Const::OK if $r->uri =~ $STATIC_URI;
-
- my $ip = $r->headers_in->{'X-Forwarded-For'};
- if ($ip) {
- $ip = (split(/\s*,\s*/ms, $ip))[-1];
- }
- else {
- $ip = $r->connection->remote_ip;
- }
-
- if ($MEMCACHED && $MEMCACHED->get("block_ip:$ip")) {
- __PACKAGE__->block_ip($ip);
- $r->status_line("429 Too Many Requests");
- # 500 is used here because apache 2.2 doesn't understand 429.
- # the above line and the return value together mean we produce 429.
- # Any other variation doesn't work.
- $r->custom_response(500, "Too Many Requests");
- return 429;
- }
- else {
- return Apache2::Const::OK;
- }
-}
-
-1;
diff --git a/Bugzilla/ModPerl/Hostage.pm b/Bugzilla/ModPerl/Hostage.pm
deleted file mode 100644
index a3bdfac58..000000000
--- a/Bugzilla/ModPerl/Hostage.pm
+++ /dev/null
@@ -1,71 +0,0 @@
-package Bugzilla::ModPerl::Hostage;
-use 5.10.1;
-use strict;
-use warnings;
-
-use Apache2::Const qw(:common); ## no critic (Freenode::ModPerl)
-
-sub _attachment_root {
- my ($base) = @_;
- return undef unless $base;
- return $base =~ m{^https?://(?:bug)?\%bugid\%\.([a-zA-Z\.-]+)}
- ? $1
- : undef;
-}
-
-sub _attachment_host_regex {
- my ($base) = @_;
- return undef unless $base;
- my $val = $base;
- $val =~ s{^https?://}{}s;
- $val =~ s{/$}{}s;
- my $regex = quotemeta $val;
- $regex =~ s/\\\%bugid\\\%/\\d+/g;
- return qr/^$regex$/s;
-}
-
-sub handler {
- my $r = shift;
- state $urlbase = Bugzilla->localconfig->{urlbase};
- state $urlbase_uri = URI->new($urlbase);
- state $urlbase_host = $urlbase_uri->host;
- state $urlbase_host_regex = qr/^bug(\d+)\.\Q$urlbase_host\E$/;
- state $attachment_base = Bugzilla->localconfig->{attachment_base};
- state $attachment_root = _attachment_root($attachment_base);
- state $attachment_host_regex = _attachment_host_regex($attachment_base);
-
- my $hostname = $r->hostname;
- return OK if $hostname eq $urlbase_host;
-
- my $path = $r->uri;
- return OK if $path eq '/__lbheartbeat__';
-
- if ($attachment_base && $hostname eq $attachment_root) {
- $r->headers_out->set(Location => $urlbase);
- return REDIRECT;
- }
- elsif ($attachment_base && $hostname =~ $attachment_host_regex) {
- if ($path =~ m{^/attachment\.cgi}s) {
- return OK;
- } else {
- my $new_uri = URI->new($r->unparsed_uri);
- $new_uri->scheme($urlbase_uri->scheme);
- $new_uri->host($urlbase_host);
- $r->headers_out->set(Location => $new_uri);
- return REDIRECT;
- }
- }
- elsif (my ($id) = $hostname =~ $urlbase_host_regex) {
- my $new_uri = $urlbase_uri->clone;
- $new_uri->path('/show_bug.cgi');
- $new_uri->query_form(id => $id);
- $r->headers_out->set(Location => $new_uri);
- return REDIRECT;
- }
- else {
- $r->headers_out->set(Location => $urlbase);
- return REDIRECT;
- }
-}
-
-1; \ No newline at end of file
diff --git a/Bugzilla/ModPerl/StartupFix.pm b/Bugzilla/ModPerl/StartupFix.pm
deleted file mode 100644
index bcc467e9f..000000000
--- a/Bugzilla/ModPerl/StartupFix.pm
+++ /dev/null
@@ -1,51 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-#
-# This Source Code Form is "Incompatible With Secondary Licenses", as
-# defined by the Mozilla Public License, v. 2.0.
-package Bugzilla::ModPerl::StartupFix;
-use 5.10.1;
-use strict;
-use warnings;
-
-use Filter::Util::Call;
-use Apache2::ServerUtil ();
-
-# This module is a source filter that removes every subsequent line
-# if this is the first time apache has started,
-# as reported by Apache2::ServerUtil::restart_count(), which is 1
-# on the first start.
-
-my $FIRST_STARTUP = <<'CODE';
-warn "Bugzilla::ModPerl::StartupFix: Skipping first startup using source filter\n";
-1;
-CODE
-
-sub import {
- my ($class) = @_;
- my ($ref) = {};
- filter_add( bless $ref, $class );
-}
-
-# this will be called for each line.
-# For the first line replaced, we insert $FIRST_STARTUP.
-# Every subsequent line is replaced with an empty string.
-sub filter {
- my ($self) = @_;
- my ($status);
- if ($status = filter_read() > 0) {
- if (Apache2::ServerUtil::restart_count() < 2) {
- if (!$self->{did_it}) {
- $self->{did_it} = 1;
- $_ = $FIRST_STARTUP;
- }
- else {
- $_ = "";
- }
- }
- }
- return $status;
-}
-
-1; \ No newline at end of file
diff --git a/Bugzilla/Quantum.pm b/Bugzilla/Quantum.pm
new file mode 100644
index 000000000..d2352f6d8
--- /dev/null
+++ b/Bugzilla/Quantum.pm
@@ -0,0 +1,118 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This Source Code Form is "Incompatible With Secondary Licenses", as
+# defined by the Mozilla Public License, v. 2.0.
+
+package Bugzilla::Quantum;
+use Mojo::Base 'Mojolicious';
+
+# Needed for its exit() overload, must happen early in execution.
+use CGI::Compile;
+
+use Bugzilla ();
+use Bugzilla::BugMail ();
+use Bugzilla::CGI ();
+use Bugzilla::Constants qw(bz_locations);
+use Bugzilla::Extension ();
+use Bugzilla::Install::Requirements ();
+use Bugzilla::Logging;
+use Bugzilla::Quantum::CGI;
+use Bugzilla::Quantum::SES;
+use Bugzilla::Quantum::Static;
+use Mojo::Loader qw( find_modules );
+use Module::Runtime qw( require_module );
+use Bugzilla::Util ();
+use Cwd qw(realpath);
+use MojoX::Log::Log4perl::Tiny;
+
+has 'static' => sub { Bugzilla::Quantum::Static->new };
+
+sub startup {
+ my ($self) = @_;
+
+ DEBUG('Starting up');
+ $self->plugin('Bugzilla::Quantum::Plugin::Glue');
+ $self->plugin('Bugzilla::Quantum::Plugin::Hostage');
+ $self->plugin('Bugzilla::Quantum::Plugin::BlockIP');
+ $self->plugin('Bugzilla::Quantum::Plugin::BasicAuth');
+
+ Bugzilla::Extension->load_all();
+ if ( $self->mode ne 'development' ) {
+ Bugzilla->preload_features();
+ DEBUG('preloading templates');
+ Bugzilla->preload_templates();
+ DEBUG('done preloading templates');
+ require_module($_) for find_modules('Bugzilla::User::Setting');
+
+ $self->hook(
+ after_static => sub {
+ my ($c) = @_;
+ $c->res->headers->cache_control('public, max-age=31536000');
+ }
+ );
+ }
+
+ my $r = $self->routes;
+ Bugzilla::Quantum::CGI->load_all($r);
+ Bugzilla::Quantum::CGI->load_one( 'bzapi_cgi', 'extensions/BzAPI/bin/rest.cgi' );
+
+ Bugzilla::WebService::Server::REST->preload;
+
+ $r->any('/')->to('CGI#index_cgi');
+ $r->any('/bug/<id:num>')->to('CGI#show_bug_cgi');
+ $r->any('/<id:num>')->to('CGI#show_bug_cgi');
+
+ $r->any('/rest')->to('CGI#rest_cgi');
+ $r->any('/rest.cgi/*PATH_INFO')->to( 'CGI#rest_cgi' => { PATH_INFO => '' } );
+ $r->any('/rest/*PATH_INFO')->to( 'CGI#rest_cgi' => { PATH_INFO => '' } );
+ $r->any('/extensions/BzAPI/bin/rest.cgi/*PATH_INFO')->to('CGI#bzapi_cgi');
+ $r->any('/bzapi/*PATH_INFO')->to('CGI#bzapi_cgi');
+
+ $r->get(
+ '/__lbheartbeat__' => sub {
+ my $c = shift;
+ $c->reply->file( $c->app->home->child('__lbheartbeat__') );
+ },
+ );
+
+ $r->get(
+ '/__version__' => sub {
+ my $c = shift;
+ $c->reply->file( $c->app->home->child('version.json') );
+ },
+ );
+
+ $r->get(
+ '/version.json' => sub {
+ my $c = shift;
+ $c->reply->file( $c->app->home->child('version.json') );
+ },
+ );
+
+ $r->get('/__heartbeat__')->to('CGI#heartbeat_cgi');
+ $r->get('/robots.txt')->to('CGI#robots_cgi');
+
+ $r->any('/review')->to( 'CGI#page_cgi' => { 'id' => 'splinter.html' } );
+ $r->any('/user_profile')->to( 'CGI#page_cgi' => { 'id' => 'user_profile.html' } );
+ $r->any('/userprofile')->to( 'CGI#page_cgi' => { 'id' => 'user_profile.html' } );
+ $r->any('/request_defer')->to( 'CGI#page_cgi' => { 'id' => 'request_defer.html' } );
+ $r->any('/login')->to( 'CGI#index_cgi' => { 'GoAheadAndLogIn' => '1' } );
+
+ $r->any( '/:new_bug' => [ new_bug => qr{new[-_]bug} ] )->to('CGI#new_bug_cgi');
+
+ my $ses_auth = $r->under(
+ '/ses' => sub {
+ my ($c) = @_;
+ my $lc = Bugzilla->localconfig;
+
+ return $c->basic_auth( 'SES', $lc->{ses_username}, $lc->{ses_password} );
+ }
+ );
+ $ses_auth->any('/index.cgi')->to('SES#main');
+
+ Bugzilla::Hook::process( 'app_startup', { app => $self } );
+}
+
+1;
diff --git a/Bugzilla/Quantum/CGI.pm b/Bugzilla/Quantum/CGI.pm
new file mode 100644
index 000000000..0a74f1ee5
--- /dev/null
+++ b/Bugzilla/Quantum/CGI.pm
@@ -0,0 +1,160 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This Source Code Form is "Incompatible With Secondary Licenses", as
+# defined by the Mozilla Public License, v. 2.0.
+
+package Bugzilla::Quantum::CGI;
+use Mojo::Base 'Mojolicious::Controller';
+
+use CGI::Compile;
+use Try::Tiny;
+use Taint::Util qw(untaint);
+use Sys::Hostname;
+use Sub::Quote 2.005000;
+use Sub::Name;
+use Socket qw(AF_INET inet_aton);
+use File::Spec::Functions qw(catfile);
+use File::Slurper qw(read_text);
+use English qw(-no_match_vars);
+use Bugzilla::Quantum::Stdout;
+use Bugzilla::Constants qw(bz_locations);
+
+our $C;
+my %SEEN;
+
+sub load_all {
+ my ( $class, $r ) = @_;
+
+ foreach my $file ( glob '*.cgi' ) {
+ my $name = _file_to_method($file);
+ $class->load_one( $name, $file );
+ $r->any("/$file")->to("CGI#$name");
+ }
+}
+
+sub load_one {
+ my ( $class, $name, $file ) = @_;
+ my $package = __PACKAGE__ . "::$name", my $inner_name = "_$name";
+ my $content = read_text( catfile( bz_locations->{cgi_path}, $file ) );
+ $content = "package $package; $content";
+ untaint($content);
+ my %options = (
+ package => $package,
+ file => $file,
+ line => 1,
+ no_defer => 1,
+ );
+ die "Tried to load $file more than once" if $SEEN{$file}++;
+ my $inner = quote_sub $inner_name, $content, {}, \%options;
+ my $wrapper = sub {
+ my ($c) = @_;
+ my $stdin = $c->_STDIN;
+ local $C = $c;
+ local %ENV = $c->_ENV($file);
+ local $CGI::Compile::USE_REAL_EXIT = 0;
+ local $PROGRAM_NAME = $file;
+ local *STDIN; ## no critic (local)
+ open STDIN, '<', $stdin->path or die "STDIN @{[$stdin->path]}: $!" if -s $stdin->path;
+ tie *STDOUT, 'Bugzilla::Quantum::Stdout', controller => $c; ## no critic (tie)
+ try {
+ Bugzilla->init_page();
+ $inner->();
+ }
+ catch {
+ die $_ unless ref $_ eq 'ARRAY' && $_->[0] eq "EXIT\n";
+ }
+ finally {
+ untie *STDOUT;
+ $c->finish;
+ Bugzilla->cleanup;
+ CGI::initialize_globals();
+ };
+ };
+
+ no strict 'refs'; ## no critic (strict)
+ *{$name} = subname( $name, $wrapper );
+ return 1;
+}
+
+
+sub _ENV {
+ my ( $c, $script_name ) = @_;
+ my $tx = $c->tx;
+ my $req = $tx->req;
+ my $headers = $req->headers;
+ my $content_length = $req->content->is_multipart ? $req->body_size : $headers->content_length;
+ my %env_headers = ( HTTP_COOKIE => '', HTTP_REFERER => '' );
+
+ for my $name ( @{ $headers->names } ) {
+ my $key = uc "http_$name";
+ $key =~ s/\W/_/g;
+ $env_headers{$key} = $headers->header($name);
+ }
+
+ my $remote_user;
+ if ( my $userinfo = $req->url->to_abs->userinfo ) {
+ $remote_user = $userinfo =~ /([^:]+)/ ? $1 : '';
+ }
+ elsif ( my $authenticate = $headers->authorization ) {
+ $remote_user = $authenticate =~ /Basic\s+(.*)/ ? b64_decode $1 : '';
+ $remote_user = $remote_user =~ /([^:]+)/ ? $1 : '';
+ }
+ my $path_info = $c->stash->{'mojo.captures'}{'PATH_INFO'};
+ my %captures = %{ $c->stash->{'mojo.captures'} // {} };
+ foreach my $key ( keys %captures ) {
+ if ( $key eq 'controller' || $key eq 'action' || $key eq 'PATH_INFO' || $key =~ /^REWRITE_/ ) {
+ delete $captures{$key};
+ }
+ }
+ my $cgi_query = Mojo::Parameters->new(%captures);
+ $cgi_query->append( $req->url->query );
+ my $prefix = $c->stash->{bmo_prefix} ? '/bmo/' : '/';
+
+ return (
+ %ENV,
+ CONTENT_LENGTH => $content_length || 0,
+ CONTENT_TYPE => $headers->content_type || '',
+ GATEWAY_INTERFACE => 'CGI/1.1',
+ HTTPS => $req->is_secure ? 'on' : 'off',
+ %env_headers,
+ QUERY_STRING => $cgi_query->to_string,
+ PATH_INFO => $path_info ? "/$path_info" : '',
+ REMOTE_ADDR => $tx->original_remote_address,
+ REMOTE_HOST => $tx->original_remote_address,
+ REMOTE_PORT => $tx->remote_port,
+ REMOTE_USER => $remote_user || '',
+ REQUEST_METHOD => $req->method,
+ SCRIPT_NAME => "$prefix$script_name",
+ SERVER_NAME => hostname,
+ SERVER_PORT => $tx->local_port,
+ SERVER_PROTOCOL => $req->is_secure ? 'HTTPS' : 'HTTP', # TODO: Version is missing
+ SERVER_SOFTWARE => __PACKAGE__,
+ );
+}
+
+sub _STDIN {
+ my $c = shift;
+ my $stdin;
+
+ if ( $c->req->content->is_multipart ) {
+ $stdin = Mojo::Asset::File->new;
+ $stdin->add_chunk( $c->req->build_body );
+ }
+ else {
+ $stdin = $c->req->content->asset;
+ }
+
+ return $stdin if $stdin->isa('Mojo::Asset::File');
+ return Mojo::Asset::File->new->add_chunk( $stdin->slurp );
+}
+
+sub _file_to_method {
+ my ($name) = @_;
+ $name =~ s/\./_/s;
+ $name =~ s/\W+/_/gs;
+ return $name;
+}
+
+1;
diff --git a/Bugzilla/Quantum/Plugin/BasicAuth.pm b/Bugzilla/Quantum/Plugin/BasicAuth.pm
new file mode 100644
index 000000000..e17273404
--- /dev/null
+++ b/Bugzilla/Quantum/Plugin/BasicAuth.pm
@@ -0,0 +1,40 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This Source Code Form is "Incompatible With Secondary Licenses", as
+# defined by the Mozilla Public License, v. 2.0.
+package Bugzilla::Quantum::Plugin::BasicAuth;
+use 5.10.1;
+use Mojo::Base qw(Mojolicious::Plugin);
+
+use Bugzilla::Logging;
+use Carp;
+
+sub register {
+ my ( $self, $app, $conf ) = @_;
+
+ $app->renderer->add_helper(
+ basic_auth => sub {
+ my ( $c, $realm, $auth_user, $auth_pass ) = @_;
+ my $req = $c->req;
+ my ( $user, $password ) = $req->url->to_abs->userinfo =~ /^([^:]+):(.*)/;
+
+ unless ( $realm && $auth_user && $auth_pass ) {
+ croak 'basic_auth() called with missing parameters.';
+ }
+
+ unless ( $user eq $auth_user && $password eq $auth_pass ) {
+ WARN('username and password do not match');
+ $c->res->headers->www_authenticate("Basic realm=\"$realm\"");
+ $c->res->code(401);
+ $c->rendered;
+ return 0;
+ }
+
+ return 1;
+ }
+ );
+}
+
+1; \ No newline at end of file
diff --git a/Bugzilla/Quantum/Plugin/BlockIP.pm b/Bugzilla/Quantum/Plugin/BlockIP.pm
new file mode 100644
index 000000000..058ecbf64
--- /dev/null
+++ b/Bugzilla/Quantum/Plugin/BlockIP.pm
@@ -0,0 +1,43 @@
+package Bugzilla::Quantum::Plugin::BlockIP;
+use 5.10.1;
+use Mojo::Base 'Mojolicious::Plugin';
+
+use Bugzilla::Memcached;
+
+use constant BLOCK_TIMEOUT => 60 * 60;
+
+my $MEMCACHED = Bugzilla::Memcached->new()->{memcached};
+
+sub register {
+ my ( $self, $app, $conf ) = @_;
+
+ $app->hook( before_routes => \&_before_routes );
+ $app->helper( block_ip => \&_block_ip );
+ $app->helper( unblock_ip => \&_unblock_ip );
+}
+
+sub _block_ip {
+ my ( $class, $ip ) = @_;
+ $MEMCACHED->set( "block_ip:$ip" => 1, BLOCK_TIMEOUT ) if $MEMCACHED;
+}
+
+sub _unblock_ip {
+ my ( $class, $ip ) = @_;
+ $MEMCACHED->delete("block_ip:$ip") if $MEMCACHED;
+}
+
+sub _before_routes {
+ my ($c) = @_;
+ return if $c->stash->{'mojo.static'};
+
+ my $ip = $c->tx->remote_address;
+ if ( $MEMCACHED && $MEMCACHED->get("block_ip:$ip") ) {
+ $c->block_ip($ip);
+ $c->res->code(429);
+ $c->res->message('Too Many Requests');
+ $c->res->body('Too Many Requests');
+ $c->finish;
+ }
+}
+
+1;
diff --git a/Bugzilla/Quantum/Plugin/Glue.pm b/Bugzilla/Quantum/Plugin/Glue.pm
new file mode 100644
index 000000000..ded4daf15
--- /dev/null
+++ b/Bugzilla/Quantum/Plugin/Glue.pm
@@ -0,0 +1,101 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This Source Code Form is "Incompatible With Secondary Licenses", as
+# defined by the Mozilla Public License, v. 2.0.
+
+package Bugzilla::Quantum::Plugin::Glue;
+use 5.10.1;
+use Mojo::Base 'Mojolicious::Plugin';
+
+use Try::Tiny;
+use Bugzilla::Constants;
+use Bugzilla::Logging;
+use Bugzilla::RNG ();
+use JSON::MaybeXS qw(decode_json);
+
+sub register {
+ my ( $self, $app, $conf ) = @_;
+
+ my %D;
+ if ( $ENV{BUGZILLA_HTTPD_ARGS} ) {
+ my $args = decode_json( $ENV{BUGZILLA_HTTPD_ARGS} );
+ foreach my $arg (@$args) {
+ if ( $arg =~ /^-D(\w+)$/ ) {
+ $D{$1} = 1;
+ }
+ else {
+ die "Unknown httpd arg: $arg";
+ }
+ }
+ }
+
+ # hypnotoad is weird and doesn't look for MOJO_LISTEN itself.
+ $app->config(
+ hypnotoad => {
+ proxy => 1,
+ listen => [ $ENV{MOJO_LISTEN} ],
+ },
+ );
+
+ # Make sure each httpd child receives a different random seed (bug 476622).
+ # Bugzilla::RNG has one srand that needs to be called for
+ # every process, and Perl has another. (Various Perl modules still use
+ # the built-in rand(), even though we never use it in Bugzilla itself,
+ # so we need to srand() both of them.)
+ # Also, ping the dbh to force a reconnection.
+ Mojo::IOLoop->next_tick(
+ sub {
+ Bugzilla::RNG::srand();
+ srand();
+ try { Bugzilla->dbh->ping };
+ }
+ );
+
+ $app->hook(
+ before_dispatch => sub {
+ my ($c) = @_;
+ if ( $D{HTTPD_IN_SUBDIR} ) {
+ my $path = $c->req->url->path;
+ if ( $path =~ s{^/bmo}{}s ) {
+ $c->stash->{bmo_prefix} = 1;
+ $c->req->url->path($path);
+ }
+ }
+ Log::Log4perl::MDC->put( request_id => $c->req->request_id );
+ }
+ );
+
+
+ $app->secrets( [ Bugzilla->localconfig->{side_wide_secret} ] );
+
+ $app->renderer->add_handler(
+ 'bugzilla' => sub {
+ my ( $renderer, $c, $output, $options ) = @_;
+ my $vars = delete $c->stash->{vars};
+
+ # Helpers
+ my %helper;
+ foreach my $method ( grep {m/^\w+\z/} keys %{ $renderer->helpers } ) {
+ my $sub = $renderer->helpers->{$method};
+ $helper{$method} = sub { $c->$sub(@_) };
+ }
+ $vars->{helper} = \%helper;
+
+ # The controller
+ $vars->{c} = $c;
+ my $name = $options->{template};
+ unless ( $name =~ /\./ ) {
+ $name = sprintf '%s.%s.tmpl', $options->{template}, $options->{format};
+ }
+ my $template = Bugzilla->template;
+ $template->process( $name, $vars, $output )
+ or die $template->error;
+ }
+ );
+
+ $app->log( MojoX::Log::Log4perl::Tiny->new( logger => Log::Log4perl->get_logger( ref $app ) ) );
+}
+
+1;
diff --git a/Bugzilla/Quantum/Plugin/Hostage.pm b/Bugzilla/Quantum/Plugin/Hostage.pm
new file mode 100644
index 000000000..cbde7b5ee
--- /dev/null
+++ b/Bugzilla/Quantum/Plugin/Hostage.pm
@@ -0,0 +1,86 @@
+package Bugzilla::Quantum::Plugin::Hostage;
+use 5.10.1;
+use Mojo::Base 'Mojolicious::Plugin';
+use Bugzilla::Logging;
+
+sub _attachment_root {
+ my ($base) = @_;
+ return undef unless $base;
+ return $base =~ m{^https?://(?:bug)?\%bugid\%\.([a-zA-Z\.-]+)}
+ ? $1
+ : undef;
+}
+
+sub _attachment_host_regex {
+ my ($base) = @_;
+ return undef unless $base;
+ my $val = $base;
+ $val =~ s{^https?://}{}s;
+ $val =~ s{/$}{}s;
+ my $regex = quotemeta $val;
+ $regex =~ s/\\\%bugid\\\%/\\d+/g;
+ return qr/^$regex$/s;
+}
+
+sub register {
+ my ( $self, $app, $conf ) = @_;
+
+ $app->hook( before_routes => \&_before_routes );
+}
+
+sub _before_routes {
+ my ($c) = @_;
+ state $urlbase = Bugzilla->localconfig->{urlbase};
+ state $urlbase_uri = URI->new($urlbase);
+ state $urlbase_host = $urlbase_uri->host;
+ state $urlbase_host_regex = qr/^bug(\d+)\.\Q$urlbase_host\E$/;
+ state $attachment_base = Bugzilla->localconfig->{attachment_base};
+ state $attachment_root = _attachment_root($attachment_base);
+ state $attachment_host_regex = _attachment_host_regex($attachment_base);
+
+ my $stash = $c->stash;
+ my $req = $c->req;
+ my $url = $req->url->to_abs;
+
+ return if $stash->{'mojo.static'};
+
+ my $hostname = $url->host;
+ return if $hostname eq $urlbase_host;
+
+ my $path = $url->path;
+ return if $path eq '/__lbheartbeat__';
+
+ if ( $attachment_base && $hostname eq $attachment_root ) {
+ DEBUG("redirecting to $urlbase because $hostname is $attachment_root");
+ $c->redirect_to($urlbase);
+ return;
+ }
+ elsif ( $attachment_base && $hostname =~ $attachment_host_regex ) {
+ if ( $path =~ m{^/attachment\.cgi}s ) {
+ return;
+ }
+ else {
+ my $new_uri = $url->clone;
+ $new_uri->scheme( $urlbase_uri->scheme );
+ $new_uri->host($urlbase_host);
+ DEBUG("redirecting to $new_uri because $hostname matches attachment regex");
+ $c->redirect_to($new_uri);
+ return;
+ }
+ }
+ elsif ( my ($id) = $hostname =~ $urlbase_host_regex ) {
+ my $new_uri = $urlbase_uri->clone;
+ $new_uri->path('/show_bug.cgi');
+ $new_uri->query_form( id => $id );
+ DEBUG("redirecting to $new_uri because $hostname includes bug id");
+ $c->redirect_to($new_uri);
+ return;
+ }
+ else {
+ DEBUG("redirecting to $urlbase because $hostname doesn't make sense");
+ $c->redirect_to($urlbase);
+ return;
+ }
+}
+
+1;
diff --git a/ses/index.cgi b/Bugzilla/Quantum/SES.pm
index e36956b1d..03916075d 100755..100644
--- a/ses/index.cgi
+++ b/Bugzilla/Quantum/SES.pm
@@ -1,4 +1,4 @@
-#!/usr/bin/perl
+package Bugzilla::Quantum::SES;
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
@@ -7,12 +7,8 @@
# defined by the Mozilla Public License, v. 2.0.
use 5.10.1;
-use strict;
-use warnings;
+use Mojo::Base qw( Mojolicious::Controller );
-use lib qw(.. ../lib ../local/lib/perl5);
-
-use Bugzilla ();
use Bugzilla::Constants qw(ERROR_MODE_DIE);
use Bugzilla::Logging;
use Bugzilla::Mailer qw(MessageToMTA);
@@ -22,51 +18,62 @@ use JSON::MaybeXS qw(decode_json);
use LWP::UserAgent ();
use Try::Tiny qw(catch try);
-Bugzilla->error_mode(ERROR_MODE_DIE);
-try {
- main();
-}
-catch {
- FATAL("Fatal error: $_");
- respond( 500 => 'Internal Server Error' );
-};
+use Types::Standard qw( :all );
+use Type::Utils;
+use Type::Params qw( compile );
+
+my $Invocant = class_type { class => __PACKAGE__ };
sub main {
- my $message = decode_json_wrapper( Bugzilla->cgi->param('POSTDATA') ) // return;
- my $message_type = $ENV{HTTP_X_AMZ_SNS_MESSAGE_TYPE} // '(missing)';
+ my ($self) = @_;
+ try {
+ $self->_main;
+ }
+ catch {
+ FATAL("Error in SES Handler: ", $_);
+ $self->_respond( 400 => 'Bad Request' );
+ };
+}
+
+sub _main {
+ my ($self) = @_;
+ Bugzilla->error_mode(ERROR_MODE_DIE);
+ my $message = $self->_decode_json_wrapper( $self->req->body ) // return;
+ my $message_type = $self->req->headers->header('X-Amz-SNS-Message-Type') // '(missing)';
if ( $message_type eq 'SubscriptionConfirmation' ) {
- confirm_subscription($message);
+ $self->_confirm_subscription($message);
}
elsif ( $message_type eq 'Notification' ) {
- my $notification = decode_json_wrapper( $message->{Message} ) // return;
+ my $notification = $self->_decode_json_wrapper( $message->{Message} ) // return;
unless (
# https://docs.aws.amazon.com/ses/latest/DeveloperGuide/event-publishing-retrieving-sns-contents.html
- handle_notification( $notification, 'eventType' )
+ $self->_handle_notification( $notification, 'eventType' )
# https://docs.aws.amazon.com/ses/latest/DeveloperGuide/notification-contents.html
- || handle_notification( $notification, 'notificationType' )
+ || $self->_handle_notification( $notification, 'notificationType' )
)
{
WARN('Failed to find notification type');
- respond( 400 => 'Bad Request' );
+ $self->_respond( 400 => 'Bad Request' );
}
}
else {
WARN("Unsupported message-type: $message_type");
- respond( 200 => 'OK' );
+ $self->_respond( 200 => 'OK' );
}
}
-sub confirm_subscription {
- my ($message) = @_;
+sub _confirm_subscription {
+ state $check = compile($Invocant, Dict[SubscribeURL => Str, slurpy Any]);
+ my ($self, $message) = $check->(@_);
my $subscribe_url = $message->{SubscribeURL};
if ( !$subscribe_url ) {
WARN('Bad SubscriptionConfirmation request: missing SubscribeURL');
- respond( 400 => 'Bad Request' );
+ $self->_respond( 400 => 'Bad Request' );
return;
}
@@ -74,15 +81,24 @@ sub confirm_subscription {
my $res = $ua->get( $message->{SubscribeURL} );
if ( !$res->is_success ) {
WARN( 'Bad response from SubscribeURL: ' . $res->status_line );
- respond( 400 => 'Bad Request' );
+ $self->_respond( 400 => 'Bad Request' );
return;
}
- respond( 200 => 'OK' );
+ $self->_respond( 200 => 'OK' );
}
-sub handle_notification {
- my ( $notification, $type_field ) = @_;
+my $NotificationType = Enum [qw( Bounce Complaint )];
+my $TypeField = Enum [qw(eventType notificationType)];
+my $Notification = Dict [
+ eventType => Optional [$NotificationType],
+ notificationType => Optional [$NotificationType],
+ slurpy Any,
+];
+
+sub _handle_notification {
+ state $check = compile($Invocant, $Notification, $TypeField );
+ my ( $self, $notification, $type_field ) = $check->(@_);
if ( !exists $notification->{$type_field} ) {
return 0;
@@ -90,20 +106,40 @@ sub handle_notification {
my $type = $notification->{$type_field};
if ( $type eq 'Bounce' ) {
- process_bounce($notification);
+ $self->_process_bounce($notification);
}
elsif ( $type eq 'Complaint' ) {
- process_complaint($notification);
+ $self->_process_complaint($notification);
}
else {
WARN("Unsupported notification-type: $type");
- respond( 200 => 'OK' );
+ $self->_respond( 200 => 'OK' );
}
return 1;
}
-sub process_bounce {
- my ($notification) = @_;
+my $BouncedRecipients = ArrayRef[
+ Dict[
+ emailAddress => Str,
+ action => Str,
+ diagnosticCode => Str,
+ slurpy Any,
+ ],
+];
+my $BounceNotification = Dict [
+ bounce => Dict [
+ bouncedRecipients => $BouncedRecipients,
+ reportingMTA => Str,
+ bounceSubType => Str,
+ bounceType => Str,
+ slurpy Any,
+ ],
+ slurpy Any,
+];
+
+sub _process_bounce {
+ state $check = compile($Invocant, $BounceNotification);
+ my ($self, $notification) = $check->(@_);
# disable each account that is bouncing
foreach my $recipient ( @{ $notification->{bounce}->{bouncedRecipients} } ) {
@@ -140,13 +176,22 @@ sub process_bounce {
}
}
- respond( 200 => 'OK' );
+ $self->_respond( 200 => 'OK' );
}
-sub process_complaint {
-
- # email notification to bugzilla admin
- my ($notification) = @_;
+my $ComplainedRecipients = ArrayRef[Dict[ emailAddress => Str, slurpy Any ]];
+my $ComplaintNotification = Dict[
+ complaint => Dict [
+ complainedRecipients => $ComplainedRecipients,
+ complaintFeedbackType => Str,
+ slurpy Any,
+ ],
+ slurpy Any,
+];
+
+sub _process_complaint {
+ state $check = compile($Invocant, $ComplaintNotification);
+ my ($self, $notification) = $check->(@_);
my $template = Bugzilla->template_inner();
my $json = JSON::MaybeXS->new(
pretty => 1,
@@ -170,31 +215,24 @@ sub process_complaint {
MessageToMTA($message);
}
- respond( 200 => 'OK' );
+ $self->_respond( 200 => 'OK' );
}
-sub respond {
- my ( $code, $message ) = @_;
- print Bugzilla->cgi->header( -status => "$code $message" );
-
- # apache will generate non-200 response pages for us
- say html_quote($message) if $code == 200;
+sub _respond {
+ my ( $self, $code, $message ) = @_;
+ $self->render(text => "$message\n", status => $code);
}
-sub decode_json_wrapper {
- my ($json) = @_;
+sub _decode_json_wrapper {
+ state $check = compile($Invocant, Str);
+ my ($self, $json) = $check->(@_);
my $result;
- if ( !defined $json ) {
- WARN( 'Missing JSON from ' . remote_ip() );
- respond( 400 => 'Bad Request' );
- return undef;
- }
my $ok = try {
$result = decode_json($json);
}
catch {
- WARN( 'Malformed JSON from ' . remote_ip() );
- respond( 400 => 'Bad Request' );
+ WARN( 'Malformed JSON from ' . $self->tx->remote_address );
+ $self->_respond( 400 => 'Bad Request' );
return undef;
};
return $ok ? $result : undef;
@@ -212,3 +250,5 @@ sub ua {
}
return $ua;
}
+
+1;
diff --git a/Bugzilla/Quantum/Static.pm b/Bugzilla/Quantum/Static.pm
new file mode 100644
index 000000000..4543d1b84
--- /dev/null
+++ b/Bugzilla/Quantum/Static.pm
@@ -0,0 +1,30 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This Source Code Form is "Incompatible With Secondary Licenses", as
+# defined by the Mozilla Public License, v. 2.0.
+
+package Bugzilla::Quantum::Static;
+use Mojo::Base 'Mojolicious::Static';
+use Bugzilla::Constants qw(bz_locations);
+
+my $LEGACY_RE = qr{
+ ^ (?:static/v[0-9]+\.[0-9]+/) ?
+ ( (?:extensions/[^/]+/web|(?:image|skin|j|graph)s)/.+)
+ $
+}xs;
+
+sub file {
+ my ( $self, $rel ) = @_;
+
+ if ( my ($legacy_rel) = $rel =~ $LEGACY_RE ) {
+ local $self->{paths} = [ bz_locations->{cgi_path} ];
+ return $self->SUPER::file($legacy_rel);
+ }
+ else {
+ return $self->SUPER::file($rel);
+ }
+}
+
+1;
diff --git a/Bugzilla/Quantum/Stdout.pm b/Bugzilla/Quantum/Stdout.pm
new file mode 100644
index 000000000..9cf19992c
--- /dev/null
+++ b/Bugzilla/Quantum/Stdout.pm
@@ -0,0 +1,60 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This Source Code Form is "Incompatible With Secondary Licenses", as
+# defined by the Mozilla Public License, v. 2.0.
+
+package Bugzilla::Quantum::Stdout;
+use 5.10.1;
+use Moo;
+
+use Bugzilla::Logging;
+use Encode;
+use English qw(-no_match_vars);
+
+has 'controller' => (
+ is => 'ro',
+ required => 1,
+);
+
+has '_encoding' => (
+ is => 'rw',
+ default => '',
+);
+
+sub TIEHANDLE { ## no critic (unpack)
+ my $class = shift;
+
+ return $class->new(@_);
+}
+
+sub PRINTF { ## no critic (unpack)
+ my $self = shift;
+ $self->PRINT( sprintf @_ );
+}
+
+sub PRINT { ## no critic (unpack)
+ my $self = shift;
+ my $c = $self->controller;
+ my $bytes = join '', @_;
+ return unless $bytes;
+ if ( $self->_encoding ) {
+ $bytes = encode( $self->_encoding, $bytes );
+ }
+ $c->write($bytes . ( $OUTPUT_RECORD_SEPARATOR // '' ) );
+}
+
+sub BINMODE {
+ my ( $self, $mode ) = @_;
+ if ($mode) {
+ if ( $mode eq ':bytes' or $mode eq ':raw' ) {
+ $self->_encoding('');
+ }
+ elsif ( $mode eq ':utf8' ) {
+ $self->_encoding('utf8');
+ }
+ }
+}
+
+1;
diff --git a/Bugzilla/Template.pm b/Bugzilla/Template.pm
index 299734d64..39272a538 100644
--- a/Bugzilla/Template.pm
+++ b/Bugzilla/Template.pm
@@ -12,6 +12,7 @@ use 5.10.1;
use strict;
use warnings;
+use Bugzilla::Logging;
use Bugzilla::Template::PreloadProvider;
use Bugzilla::Bug;
use Bugzilla::Constants;
diff --git a/Bugzilla/Util.pm b/Bugzilla/Util.pm
index a8477a62d..aa524b263 100644
--- a/Bugzilla/Util.pm
+++ b/Bugzilla/Util.pm
@@ -29,7 +29,7 @@ use base qw(Exporter);
get_text template_var disable_utf8
enable_utf8 detect_encoding email_filter
round extract_nicks);
-
+use Bugzilla::Logging;
use Bugzilla::Constants;
use Bugzilla::RNG qw(irand);
@@ -317,6 +317,7 @@ sub do_ssl_redirect_if_required {
# If we're already running under SSL, never redirect.
return if $ENV{HTTPS} && $ENV{HTTPS} eq 'on';
+ DEBUG("Redirect to HTTPS because \$ENV{HTTPS}=$ENV{HTTPS}");
Bugzilla->cgi->redirect_to_https();
}
diff --git a/Bugzilla/WebService/Server/XMLRPC.pm b/Bugzilla/WebService/Server/XMLRPC.pm
index 6bb73af01..5ad50e91c 100644
--- a/Bugzilla/WebService/Server/XMLRPC.pm
+++ b/Bugzilla/WebService/Server/XMLRPC.pm
@@ -14,11 +14,7 @@ use warnings;
use Bugzilla::Logging;
use XMLRPC::Transport::HTTP;
use Bugzilla::WebService::Server;
-if ($ENV{MOD_PERL}) {
- our @ISA = qw(XMLRPC::Transport::HTTP::Apache Bugzilla::WebService::Server);
-} else {
- our @ISA = qw(XMLRPC::Transport::HTTP::CGI Bugzilla::WebService::Server);
-}
+our @ISA = qw(XMLRPC::Transport::HTTP::CGI Bugzilla::WebService::Server);
use Bugzilla::WebService::Constants;
use Bugzilla::Error;
diff --git a/Bugzilla/WebService/Util.pm b/Bugzilla/WebService/Util.pm
index 29ff05448..d462c884a 100644
--- a/Bugzilla/WebService/Util.pm
+++ b/Bugzilla/WebService/Util.pm
@@ -23,7 +23,7 @@ use base qw(Exporter);
# We have to "require", not "use" this, because otherwise it tries to
# use features of Test::More during import().
-require Test::Taint;
+require Test::Taint if ${^TAINT};
our @EXPORT_OK = qw(
extract_flags
@@ -193,8 +193,10 @@ sub taint_data {
# Though this is a private function, it hasn't changed since 2004 and
# should be safe to use, and prevents us from having to write it ourselves
# or require another module to do it.
- Test::Taint::_deeply_traverse(\&_delete_bad_keys, \@params);
- Test::Taint::taint_deeply(\@params);
+ if (${^TAINT}) {
+ Test::Taint::_deeply_traverse(\&_delete_bad_keys, \@params);
+ Test::Taint::taint_deeply(\@params);
+ }
}
sub _delete_bad_keys {
diff --git a/Dockerfile b/Dockerfile
index 6426f1ad8..fd02f222d 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,4 @@
-FROM mozillabteam/bmo-slim:20180801.2
+FROM mozillabteam/bmo-slim:20180809.1
ARG CI
ARG CIRCLE_SHA1
@@ -9,12 +9,6 @@ ENV CIRCLE_BUILD_URL=${CIRCLE_BUILD_URL}
ENV CIRCLE_SHA1=${CIRCLE_SHA1}
ENV LOG4PERL_CONFIG_FILE=log4perl-json.conf
-ENV HTTPD_StartServers=8
-ENV HTTPD_MinSpareServers=5
-ENV HTTPD_MaxSpareServers=20
-ENV HTTPD_ServerLimit=256
-ENV HTTPD_MaxClients=256
-ENV HTTPD_MaxRequestsPerChild=4000
ENV PORT=8000
@@ -28,7 +22,8 @@ RUN mv /opt/bmo/local /app && \
chown -R app:app /app && \
perl -I/app -I/app/local/lib/perl5 -c -E 'use Bugzilla; BEGIN { Bugzilla->extensions }' && \
perl -c /app/scripts/entrypoint.pl && \
- setcap 'cap_net_bind_service=+ep' /usr/sbin/httpd
+ setcap 'cap_net_bind_service=+ep' /usr/sbin/httpd && \
+ setcap 'cap_net_bind_service=+ep' /usr/bin/perl
USER app
diff --git a/Log/Log4perl/Layout/Mozilla.pm b/Log/Log4perl/Layout/Mozilla.pm
index b625c54f4..4aedd9843 100644
--- a/Log/Log4perl/Layout/Mozilla.pm
+++ b/Log/Log4perl/Layout/Mozilla.pm
@@ -53,6 +53,9 @@ sub render {
my $mdc = Log::Log4perl::MDC->get_context;
my $fields = $mdc->{fields} // {};
+ if ($mdc->{request_id}) {
+ $fields->{request_id} = $mdc->{request_id}
+ }
my %out = (
EnvVersion => LOGGING_FORMAT_VERSION,
Hostname => $HOSTNAME,
diff --git a/Makefile.PL b/Makefile.PL
index 6d4225e9a..7e3095867 100755
--- a/Makefile.PL
+++ b/Makefile.PL
@@ -69,6 +69,7 @@ my %requires = (
'Module::Metadata' => '1.000033',
'Module::Runtime' => '0.014',
'Mojolicious' => '7.71',
+ 'MojoX::Log::Log4perl::Tiny' => '0.01',
'Moo' => '2.002004',
'MooX::StrictConstructor' => '0.008',
'Mozilla::CA' => '20160104',
@@ -81,10 +82,12 @@ my %requires = (
'Template' => '2.24',
'Text::CSV_XS' => '1.26',
'Throwable' => '0.200013',
- 'Type::Tiny' => '1.000005',
+ 'Sub::Quote' => '2.005000',
+ 'Type::Tiny' => '1.004002',
'URI' => '1.55',
'URI::Escape::XS' => '0.14',
'version' => '0.87',
+ 'EV' => '4.0',
);
my %build_requires = ( 'ExtUtils::MakeMaker' => '7.22', );
@@ -97,7 +100,7 @@ my %test_requires = (
'Perl::Critic::Freenode' => 0,
'Capture::Tiny' => 0,
);
-my %recommends = ( Safe => '2.30' );
+my %recommends = ( Safe => '2.30',);
# Windows requires some additional modules.
if ( $OSNAME eq 'MSWin32' ) {
@@ -285,18 +288,6 @@ my %optional_features = (
}
},
},
- mod_perl => {
- description => 'mod_perl support under Apache',
- prereqs => {
- runtime => {
- requires => {
- 'mod_perl2' => '1.999022',
- 'Apache2::SizeLimit' => '0.96',
- 'Plack::Handler::Apache2' => 0,
- }
- }
- }
- },
inbound_email => {
description => 'Inbound Email',
prereqs => {
@@ -468,7 +459,6 @@ sub is_bmo_feature {
^
(?: pg
| oracle
- | mod_perl
| sqlite
| auth_ldap
| auth_radius
diff --git a/README.rst b/README.rst
index 05eb1df1f..2a0fa289c 100644
--- a/README.rst
+++ b/README.rst
@@ -333,41 +333,6 @@ BMO_use_mailer_queue
Usually configured on the MTA section of the admin interface, you may change this here for testing purposes.
Should be 1 or 0. If 1, the job queue will be used. For testing, only set to 0 if the BMO_mail_delivery_method is None or Test.
-HTTPD_StartServers
- Sets the number of child server processes created on startup.
- As the number of processes is dynamically controlled depending on the load,
- there is usually little reason to adjust this parameter.
- Default: 8
-
-HTTPD_MinSpareServers
- Sets the desired minimum number of idle child server processes. An idle
- process is one which is not handling a request. If there are fewer than
- MinSpareServers idle, then the parent process creates new children at a
- maximum rate of 1 per second.
- Default: 5
-
-HTTPD_MaxSpareServers
- Sets the desired maximum number of idle child server processes. An idle
- process is one which is not handling a request. If there are more than
- MaxSpareServers idle, then the parent process will kill off the excess
- processes.
- Default: 20
-
-HTTPD_MaxClients
- Sets the maximum number of child processes that will be launched to serve requests.
- Default: 256
-
-HTTPD_ServerLimit
- Sets the maximum configured value for MaxClients for the lifetime of the
- Apache process.
- Default: 256
-
-HTTPD_MaxRequestsPerChild
- Sets the limit on the number of requests that an individual child server
- process will handle. After MaxRequestsPerChild requests, the child process
- will die. If MaxRequestsPerChild is 0, then the process will never expire.
- Default: 4000
-
USE_NYTPROF
Write `Devel::NYTProf`_ profiles out for each requests.
These will be named /app/data/nytprof.$host.$script.$n.$pid, where $host is
diff --git a/buglist.cgi b/buglist.cgi
index 4d3ad1a86..019bf0d4e 100755
--- a/buglist.cgi
+++ b/buglist.cgi
@@ -41,6 +41,8 @@ my $vars = {};
my $user = Bugzilla->login();
$cgi->redirect_search_url();
+use Bugzilla::Logging;
+DEBUG("After the redirect.");
my $buffer = $cgi->query_string();
if (length($buffer) == 0) {
@@ -103,27 +105,6 @@ my $agent = ($cgi->http('X-Moz') && $cgi->http('X-Moz') =~ /\bmicrosummary\b/);
my $format = $template->get_format("list/list", scalar $cgi->param('format'),
scalar $cgi->param('ctype'));
-# Use server push to display a "Please wait..." message for the user while
-# executing their query if their browser supports it and they are viewing
-# the bug list as HTML and they have not disabled it by adding &serverpush=0
-# to the URL.
-#
-# Server push is a Netscape 3+ hack incompatible with MSIE, Lynx, and others.
-# Even Communicator 4.51 has bugs with it, especially during page reload.
-# http://www.browsercaps.org used as source of compatible browsers.
-# Safari (WebKit) does not support it, despite a UA that says otherwise (bug 188712)
-# MSIE 5+ supports it on Mac (but not on Windows) (bug 190370)
-#
-my $serverpush =
- $format->{'extension'} eq "html"
- && exists $ENV{'HTTP_USER_AGENT'}
- && $ENV{'HTTP_USER_AGENT'} =~ /Mozilla.[3-9]/
- && (($ENV{'HTTP_USER_AGENT'} !~ /[Cc]ompatible/) || ($ENV{'HTTP_USER_AGENT'} =~ /MSIE 5.*Mac_PowerPC/))
- && $ENV{'HTTP_USER_AGENT'} !~ /(?:WebKit|Trident|KHTML)/
- && !$agent
- && !defined($cgi->param('serverpush'))
- || $cgi->param('serverpush');
-
my $order = $cgi->param('order') || "";
# The params object to use for the actual query itself
@@ -744,24 +725,6 @@ $params->delete('limit') if $vars->{'default_limited'};
# Time to use server push to display an interim message to the user until
# the query completes and we can display the bug list.
-if ($serverpush) {
- print $cgi->multipart_init();
- print $cgi->multipart_start(-type => 'text/html');
-
- # Generate and return the UI (HTML page) from the appropriate template.
- $template->process("list/server-push.html.tmpl", $vars)
- || ThrowTemplateError($template->error());
-
- # Under mod_perl, flush stdout so that the page actually shows up.
- if ($ENV{MOD_PERL}) {
- require Apache2::RequestUtil;
- Apache2::RequestUtil->request->rflush();
- }
-
- # Don't do multipart_end() until we're ready to display the replacement
- # page, otherwise any errors that happen before then (like SQL errors)
- # will result in a blank page being shown to the user instead of the error.
-}
# Connect to the shadow database if this installation is using one to improve
# query performance.
@@ -1140,11 +1103,4 @@ $cgi->close_standby_message($contenttype, $disposition, $disp_prefix, $format->{
# Generate and return the UI (HTML page) from the appropriate template.
$template->process($format->{'template'}, $vars)
- || ThrowTemplateError($template->error());
-
-
-################################################################################
-# Script Conclusion
-################################################################################
-
-print $cgi->multipart_final() if $serverpush;
+ || ThrowTemplateError($template->error()); \ No newline at end of file
diff --git a/bugzilla.pl b/bugzilla.pl
new file mode 100755
index 000000000..efcea293b
--- /dev/null
+++ b/bugzilla.pl
@@ -0,0 +1,20 @@
+#!/usr/bin/perl
+use 5.10.1;
+use strict;
+use warnings;
+
+use File::Basename qw(basename dirname);
+use File::Spec::Functions qw(catdir);
+use Cwd qw(realpath);
+
+BEGIN {
+ require lib;
+ my $dir = realpath( dirname(__FILE__) );
+ lib->import( $dir, catdir( $dir, 'lib' ), catdir( $dir, qw(local lib perl5) ) );
+}
+use Mojolicious::Commands;
+
+$ENV{MOJO_LISTEN} ||= $ENV{PORT} ? "http://*:$ENV{PORT}" : "http://*:3001";
+
+# Start command line interface for application
+Mojolicious::Commands->start_app('Bugzilla::Quantum');
diff --git a/checksetup.pl b/checksetup.pl
index d3f08e024..7c9826ee3 100755
--- a/checksetup.pl
+++ b/checksetup.pl
@@ -135,7 +135,7 @@ require Bugzilla::Install::Localconfig;
import Bugzilla::Install::Localconfig qw(update_localconfig);
require Bugzilla::Install::Filesystem;
-import Bugzilla::Install::Filesystem qw(update_filesystem create_htaccess
+import Bugzilla::Install::Filesystem qw(update_filesystem
fix_all_file_permissions);
require Bugzilla::Install::DB;
require Bugzilla::DB;
@@ -201,7 +201,6 @@ unless ($switch{'no-database'}) {
###########################################################################
update_filesystem({ index_html => $lc_hash->{'index_html'} });
-create_htaccess() if $lc_hash->{'create_htaccess'};
# Remove parameters from the params file that no longer exist in Bugzilla,
# and set the defaults for new ones
diff --git a/colchange.cgi b/colchange.cgi
index d77782bec..46d25ecdf 100755
--- a/colchange.cgi
+++ b/colchange.cgi
@@ -136,26 +136,12 @@ if (defined $cgi->param('rememberedquery')) {
$params->param('columnlist', join(",", @collist));
$vars->{'redirect_url'} = "buglist.cgi?".$params->query_string();
-
# If we're running on Microsoft IIS, $cgi->redirect discards
# the Set-Cookie lines. In mod_perl, $cgi->redirect with cookies
# causes the page to be rendered as text/plain.
# Workaround is to use the old-fashioned redirection mechanism.
# See bug 214466 and bug 376044 for details.
- if ($ENV{'MOD_PERL'}
- || $ENV{'SERVER_SOFTWARE'} =~ /Microsoft-IIS/
- || $ENV{'SERVER_SOFTWARE'} =~ /Sun ONE Web/)
- {
- print $cgi->header(-type => "text/html",
- -refresh => "0; URL=$vars->{'redirect_url'}");
- }
- else {
- print $cgi->redirect($vars->{'redirect_url'});
- exit;
- }
-
- $template->process("global/message.html.tmpl", $vars)
- || ThrowTemplateError($template->error());
+ print $cgi->redirect($vars->{'redirect_url'});
exit;
}
diff --git a/conf/httpd.conf b/conf/httpd.conf
deleted file mode 100644
index 539ab4231..000000000
--- a/conf/httpd.conf
+++ /dev/null
@@ -1,103 +0,0 @@
-ServerName 127.0.0.1
-ServerTokens Prod
-ServerRoot "/etc/httpd"
-ServerAdmin root@localhost
-
-PidFile /tmp/httpd.pid
-Timeout 120
-LimitRequestLine 35000
-KeepAlive Off
-MaxKeepAliveRequests 100
-KeepAliveTimeout 15
-
-StartServers ${HTTPD_StartServers}
-MinSpareServers ${HTTPD_MinSpareServers}
-MaxSpareServers ${HTTPD_MaxSpareServers}
-ServerLimit ${HTTPD_ServerLimit}
-MaxClients ${HTTPD_MaxClients}
-MaxRequestsPerChild ${HTTPD_MaxRequestsPerChild}
-
-Listen ${PORT}
-User app
-Group app
-
-LoadModule auth_basic_module modules/mod_auth_basic.so
-LoadModule auth_digest_module modules/mod_auth_digest.so
-LoadModule authn_file_module modules/mod_authn_file.so
-LoadModule authn_alias_module modules/mod_authn_alias.so
-LoadModule authn_anon_module modules/mod_authn_anon.so
-LoadModule authn_dbm_module modules/mod_authn_dbm.so
-LoadModule authn_default_module modules/mod_authn_default.so
-LoadModule authz_host_module modules/mod_authz_host.so
-LoadModule authz_user_module modules/mod_authz_user.so
-LoadModule authz_owner_module modules/mod_authz_owner.so
-LoadModule authz_groupfile_module modules/mod_authz_groupfile.so
-LoadModule authz_default_module modules/mod_authz_default.so
-LoadModule log_config_module modules/mod_log_config.so
-LoadModule env_module modules/mod_env.so
-LoadModule mime_magic_module modules/mod_mime_magic.so
-LoadModule expires_module modules/mod_expires.so
-LoadModule deflate_module modules/mod_deflate.so
-LoadModule headers_module modules/mod_headers.so
-LoadModule setenvif_module modules/mod_setenvif.so
-LoadModule mime_module modules/mod_mime.so
-LoadModule negotiation_module modules/mod_negotiation.so
-LoadModule dir_module modules/mod_dir.so
-LoadModule alias_module modules/mod_alias.so
-LoadModule rewrite_module modules/mod_rewrite.so
-LoadModule perl_module modules/mod_perl.so
-
-UseCanonicalName Off
-<Directory />
- Options FollowSymLinks
- AllowOverride None
-</Directory>
-AccessFileName .htaccess
-<Files ~ "^\.ht">
- Order allow,deny
- Deny from all
- Satisfy All
-</Files>
-TypesConfig /etc/mime.types
-DefaultType text/plain
-MIMEMagicFile conf/magic
-HostnameLookups Off
-<IfDefine NETCAT_LOGS>
- ErrorLog "|/usr/bin/nc localhost ${LOGGING_PORT}"
- <IfDefine ACCESS_LOGS>
- TransferLog "|/usr/bin/nc localhost ${LOGGING_PORT}"
- </IfDefine>
-</IfDefine>
-<IfDefine !NETCAT_LOGS>
- ErrorLog /dev/stderr
- <IfDefine ACCESS_LOGS>
- TransferLog /dev/stdout
- </IfDefine>
-</IfDefine>
-LogLevel warn
-LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
-LogFormat "%h %l %u %t \"%r\" %>s %b" common
-LogFormat "%{Referer}i -> %U" referer
-LogFormat "%{User-agent}i" agent
-ServerSignature Off
-AddDefaultCharset UTF-8
-
-Include /app/conf/env.conf
-
-PerlSwitches -wT
-PerlRequire /app/mod_perl.pl
-PerlSetEnv LOG4PERL_STDERR_DISABLE 1
-DirectoryIndex index.cgi
-DocumentRoot "/app"
-<IfDefine HTTPD_IN_SUBDIR>
-Alias "/bmo" "/app"
-</IfDefine>
-<IfDefine HTTPS>
- SetEnvIf X-Forwarded-Proto "https" HTTPS=on
-</IfDefine>
-<Directory "/app">
- Options -Indexes -FollowSymLinks
- AllowOverride None
- Order allow,deny
- Allow from all
-</Directory>
diff --git a/conf/log4perl-test.conf b/conf/log4perl-test.conf
index 77fc00af8..1760279db 100644
--- a/conf/log4perl-test.conf
+++ b/conf/log4perl-test.conf
@@ -4,14 +4,14 @@ log4perl.appender.Cereal.PeerAddr=127.0.0.1
log4perl.appender.Cereal.PeerPort=5880
log4perl.appender.Cereal.defer_connection=1
log4perl.appender.Cereal.layout = Log::Log4perl::Layout::PatternLayout
-log4perl.appender.Cereal.layout.ConversionPattern = %d %6p | %c | %m{chomp}%n
+log4perl.appender.Cereal.layout.ConversionPattern = %X{request_id} %d %6p | %c | %m{chomp}%n
log4perl.filter.LOG_TO_STDERR = sub { not $ENV{LOG4PERL_STDERR_DISABLE} }
log4perl.appender.Screen = Log::Log4perl::Appender::Screen
log4perl.appender.Screen.Filter = LOG_TO_STDERR
log4perl.appender.Screen.stderr = 1
log4perl.appender.Screen.layout = Log::Log4perl::Layout::PatternLayout
-log4perl.appender.Screen.layout.ConversionPattern = %d %6p | %c | %m{chomp}%n
+log4perl.appender.Screen.layout.ConversionPattern = STDERR: %X{request_id} %d %6p | %c | %m{chomp}%n
log4perl.appender.File = Log::Log4perl::Appender::File
log4perl.appender.File.layout = Log::Log4perl::Layout::Mozilla
diff --git a/docker-compose.yml b/docker-compose.yml
index 1ca6f5c90..b00c6bc03 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -19,6 +19,7 @@ services:
- LOCALCONFIG_ENV=1
- LOG4PERL_CONFIG_FILE=log4perl-docker.conf
- BUGZILLA_UNSAFE_AUTH_DELEGATION=1
+ - HTTP_BACKEND=simple
- PORT=80
- BMO_db_host=bmo-db.vm
- BMO_db_name=bugs
diff --git a/docs/en/rst/administering/parameters.rst b/docs/en/rst/administering/parameters.rst
index 338df3eb3..0492e0070 100644
--- a/docs/en/rst/administering/parameters.rst
+++ b/docs/en/rst/administering/parameters.rst
@@ -28,12 +28,6 @@ utf8
.. note:: If you turn this parameter from :paramval:`off` to :paramval:`on`,
you must re-run :file:`checksetup.pl` immediately afterward.
-shutdownhtml
- If there is any text in this field, this Bugzilla installation will
- be completely disabled and this text will appear instead of all
- Bugzilla pages for all users, including Admins. Used in the event
- of site maintenance or outage situations.
-
announcehtml
Any text in this field will be displayed at the top of every HTML
page in this Bugzilla installation. The text is not wrapped in any
diff --git a/docs/en/rst/style.rst b/docs/en/rst/style.rst
index aa3957b95..5058a51a3 100644
--- a/docs/en/rst/style.rst
+++ b/docs/en/rst/style.rst
@@ -65,7 +65,7 @@ Other block types:
aware of.
.. todo:: This is some documentation-related task that still needs doing.
-
+
Use both of the above block types sparingly. Consider putting the information
in the main text, omitting it, or (if long) placing it in a subsidiary file.
@@ -103,9 +103,6 @@ Inline Directives
* A command to type in the shell:
:command:`command --arguments`
-* A parameter name:
- :param:`shutdownhtml`
-
* A parameter value:
:paramval:`DB`
diff --git a/editparams.cgi b/editparams.cgi
index ac7976d99..495d53937 100755
--- a/editparams.cgi
+++ b/editparams.cgi
@@ -137,9 +137,6 @@ if ($action eq 'save' && $current_module) {
}
push(@changes, $name);
SetParam($name, $value);
- if (($name eq "shutdownhtml") && ($value ne "")) {
- $vars->{'shutdown_is_active'} = 1;
- }
if ($name eq 'duplicate_or_move_bug_status') {
Bugzilla::Status::add_missing_bug_status_transitions($value);
}
diff --git a/extensions/BMO/Extension.pm b/extensions/BMO/Extension.pm
index 3b1c03eec..6c4ad2ef2 100644
--- a/extensions/BMO/Extension.pm
+++ b/extensions/BMO/Extension.pm
@@ -2719,4 +2719,105 @@ sub enter_bug_entrydefaultvars {
}
}
+sub app_startup {
+ my ($self, $args) = @_;
+ my $app = $args->{app};
+ my $r = $app->routes;
+
+ $r->get(
+ '/favicon.ico' => sub {
+ my $c = shift;
+ $c->reply->file(
+ $c->app->home->child('extensions/BMO/web/images/favicon.ico')
+ );
+ }
+ );
+
+ $r->any( '/:REWRITE_itrequest' => [ REWRITE_itrequest => qr{form[\.:]itrequest} ] )
+ ->to( 'CGI#enter_bug_cgi' => { 'product' => 'Infrastructure & Operations', 'format' => 'itrequest' } );
+ $r->any( '/:REWRITE_mozlist' => [ REWRITE_mozlist => qr{form[\.:]mozlist} ] )
+ ->to( 'CGI#enter_bug_cgi' => { 'product' => 'mozilla.org', 'format' => 'mozlist' } );
+ $r->any( '/:REWRITE_poweredby' => [ REWRITE_poweredby => qr{form[\.:]poweredby} ] )
+ ->to( 'CGI#enter_bug_cgi' => { 'product' => 'mozilla.org', 'format' => 'poweredby' } );
+ $r->any( '/:REWRITE_presentation' => [ REWRITE_presentation => qr{form[\.:]presentation} ] )
+ ->to( 'cgi#enter_bug_cgi' => { 'product' => 'mozilla.org', 'format' => 'presentation' } );
+ $r->any( '/:REWRITE_trademark' => [ REWRITE_trademark => qr{form[\.:]trademark} ] )
+ ->to( 'cgi#enter_bug_cgi' => { 'product' => 'mozilla.org', 'format' => 'trademark' } );
+ $r->any( '/:REWRITE_recoverykey' => [ REWRITE_recoverykey => qr{form[\.:]recoverykey} ] )
+ ->to( 'cgi#enter_bug_cgi' => { 'product' => 'mozilla.org', 'format' => 'recoverykey' } );
+ $r->any( '/:REWRITE_legal' => [ REWRITE_legal => qr{form[\.:]legal} ] )
+ ->to( 'CGI#enter_bug_cgi' => { 'product' => 'Legal', 'format' => 'legal' }, );
+ $r->any( '/:REWRITE_recruiting' => [ REWRITE_recruiting => qr{form[\.:]recruiting} ] )
+ ->to( 'CGI#enter_bug_cgi' => { 'product' => 'Recruiting', 'format' => 'recruiting' } );
+ $r->any( '/:REWRITE_intern' => [ REWRITE_intern => qr{form[\.:]intern} ] )
+ ->to( 'CGI#enter_bug_cgi' => { 'product' => 'Recruiting', 'format' => 'intern' } );
+ $r->any( '/:REWRITE_mozpr' => [ REWRITE_mozpr => qr{form[\.:]mozpr} ] )
+ ->to( 'CGI#enter_bug_cgi' => { 'product' => 'Mozilla PR', 'format' => 'mozpr' }, );
+ $r->any( '/:REWRITE_reps_mentorship' => [ REWRITE_reps_mentorship => qr{form[\.:]reps[\.:]mentorship} ] )
+ ->to( 'CGI#enter_bug_cgi' => { 'product' => 'Mozilla Reps', 'format' => 'mozreps' }, );
+ $r->any( '/:REWRITE_reps_budget' => [ REWRITE_reps_budget => qr{form[\.:]reps[\.:]budget} ] )
+ ->to( 'CGI#enter_bug_cgi' => { 'product' => 'Mozilla Reps', 'format' => 'remo-budget' } );
+ $r->any( '/:REWRITE_reps_swag' => [ REWRITE_reps_swag => qr{form[\.:]reps[\.:]swag} ] )
+ ->to( 'CGI#enter_bug_cgi' => { 'product' => 'Mozilla Reps', 'format' => 'remo-swag' } );
+ $r->any( '/:REWRITE_reps_it' => [ REWRITE_reps_it => qr{form[\.:]reps[\.:]it} ] )
+ ->to( 'CGI#enter_bug_cgi' => { 'product' => 'Mozilla Reps', 'format' => 'remo-it' } );
+ $r->any( '/:REWRITE_reps_payment' => [ REWRITE_reps_payment => qr{form[\.:]reps[\.:]payment} ] )
+ ->to( 'CGI#page_cgi' => { 'id' => 'remo-form-payment.html' } );
+ $r->any( '/:REWRITE_csa_discourse' => [ REWRITE_csa_discourse => qr{form[\.:]csa[\.:]discourse} ] )
+ ->to( 'CGI#enter_bug_cgi' => { 'product' => 'Infrastructure & Operations', 'format' => 'csa-discourse' } );
+ $r->any( '/:REWRITE_employee_incident' => [ REWRITE_employee_incident => qr{form[\.:]employee[\.\-:]incident} ] )
+ ->to( 'CGI#enter_bug_cgi' => { 'product' => 'mozilla.org', 'format' => 'employee-incident' } );
+ $r->any( '/:REWRITE_brownbag' => [ REWRITE_brownbag => qr{form[\.:]brownbag} ] )
+ ->to( 'CGI#https_air_mozilla_org_requests' => {} );
+ $r->any( '/:REWRITE_finance' => [ REWRITE_finance => qr{form[\.:]finance} ] )
+ ->to( 'CGI#enter_bug_cgi' => { 'product' => 'Finance', 'format' => 'finance' } );
+ $r->any(
+ '/:REWRITE_moz_project_review' => [ REWRITE_moz_project_review => qr{form[\.:]moz[\.\-:]project[\.\-:]review} ]
+ )->to( 'CGI#enter_bug_cgi' => { 'product' => 'mozilla.org', 'format' => 'moz-project-review' } );
+ $r->any( '/:REWRITE_docs' => [ REWRITE_docs => qr{form[\.:]docs?} ] )
+ ->to( 'CGI#enter_bug_cgi' => { 'product' => 'Developer Documentation', 'format' => 'doc' } );
+ $r->any( '/:REWRITE_mdn' => [ REWRITE_mdn => qr{form[\.:]mdn?} ] )
+ ->to( 'CGI#enter_bug_cgi' => { 'format' => 'mdn', 'product' => 'developer.mozilla.org' } );
+ $r->any( '/:REWRITE_swag_gear' => [ REWRITE_swag_gear => qr{form[\.:](swag|gear)} ] )
+ ->to( 'CGI#enter_bug_cgi' => { 'format' => 'swag', 'product' => 'Marketing' } );
+ $r->any( '/:REWRITE_costume' => [ REWRITE_costume => qr{form[\.:]costume} ] )
+ ->to( 'CGI#enter_bug_cgi' => { 'product' => 'Marketing', 'format' => 'costume' } );
+ $r->any( '/:REWRITE_ipp' => [ REWRITE_ipp => qr{form[\.:]ipp} ] )
+ ->to( 'CGI#enter_bug_cgi' => { 'product' => 'Internet Public Policy', 'format' => 'ipp' } );
+ $r->any( '/:REWRITE_creative' => [ REWRITE_creative => qr{form[\.:]creative} ] )
+ ->to( 'CGI#enter_bug_cgi' => { 'format' => 'creative', 'product' => 'Marketing' } );
+ $r->any( '/:REWRITE_user_engagement' => [ REWRITE_user_engagement => qr{form[\.:]user[\.\-:]engagement} ] )
+ ->to( 'CGI#enter_bug_cgi' => { 'format' => 'user-engagement', 'product' => 'Marketing' } );
+ $r->any( '/:REWRITE_dev_engagement_event' =>
+ [ REWRITE_dev_engagement_event => qr{form[\.:]dev[\.\-:]engagement[\.\-\:]event} ] )
+ ->to( 'CGI#enter_bug_cgi' => { 'product' => 'Developer Engagement', 'format' => 'dev-engagement-event' } );
+ $r->any( '/:REWRITE_mobile_compat' => [ REWRITE_mobile_compat => qr{form[\.:]mobile[\.\-:]compat} ] )
+ ->to( 'CGI#enter_bug_cgi' => { 'product' => 'Tech Evangelism', 'format' => 'mobile-compat' } );
+ $r->any( '/:REWRITE_web_bounty' => [ REWRITE_web_bounty => qr{form[\.:]web[\.:]bounty} ] )
+ ->to( 'CGI#enter_bug_cgi' => { 'format' => 'web-bounty', 'product' => 'mozilla.org' } );
+ $r->any( '/:REWRITE_automative' => [ REWRITE_automative => qr{form[\.:]automative} ] )
+ ->to( 'CGI#enter_bug_cgi' => { 'product' => 'Testing', 'format' => 'automative' } );
+ $r->any( '/:REWRITE_comm_newsletter' => [ REWRITE_comm_newsletter => qr{form[\.:]comm[\.:]newsletter} ] )
+ ->to( 'CGI#enter_bug_cgi' => { 'format' => 'comm-newsletter', 'product' => 'Marketing' } );
+ $r->any( '/:REWRITE_screen_share_whitelist' =>
+ [ REWRITE_screen_share_whitelist => qr{form[\.:]screen[\.:]share[\.:]whitelist} ] )
+ ->to( 'CGI#enter_bug_cgi' => { 'format' => 'screen-share-whitelist', 'product' => 'Firefox' } );
+ $r->any( '/:REWRITE_data_compliance' => [ REWRITE_data_compliance => qr{form[\.:]data[\.\-:]compliance} ] )
+ ->to( 'CGI#enter_bug_cgi' => { 'product' => 'Data Compliance', 'format' => 'data-compliance' } );
+ $r->any( '/:REWRITE_fsa_budget' => [ REWRITE_fsa_budget => qr{form[\.:]fsa[\.:]budget} ] )
+ ->to( 'CGI#enter_bug_cgi' => { 'product' => 'FSA', 'format' => 'fsa-budget' } );
+ $r->any( '/:REWRITE_triage_request' => [ REWRITE_triage_request => qr{form[\.:]triage[\.\-]request} ] )
+ ->to( 'CGI#page_cgi' => { 'id' => 'triage_request.html' } );
+ $r->any( '/:REWRITE_crm_CRM' => [ REWRITE_crm_CRM => qr{form[\.:](crm|CRM)} ] )
+ ->to( 'CGI#enter_bug_cgi' => { 'format' => 'crm', 'product' => 'Marketing' } );
+ $r->any( '/:REWRITE_nda' => [ REWRITE_nda => qr{form[\.:]nda} ] )
+ ->to( 'CGI#enter_bug_cgi' => { 'product' => 'Legal', 'format' => 'nda' } );
+ $r->any( '/:REWRITE_name_clearance' => [ REWRITE_name_clearance => qr{form[\.:]name[\.:]clearance} ] )
+ ->to( 'CGI#enter_bug_cgi' => { 'format' => 'name-clearance', 'product' => 'Legal' } );
+ $r->any( '/:REWRITE_shield_studies' => [ REWRITE_shield_studies => qr{form[\.:]shield[\.:]studies} ] )
+ ->to( 'CGI#enter_bug_cgi' => { 'product' => 'Shield', 'format' => 'shield-studies' } );
+ $r->any( '/:REWRITE_client_bounty' => [ REWRITE_client_bounty => qr{form[\.:]client[\.:]bounty} ] )
+ ->to( 'CGI#enter_bug_cgi' => { 'product' => 'Firefox', 'format' => 'client-bounty' } );
+}
+
__PACKAGE__->NAME;
diff --git a/heartbeat.cgi b/heartbeat.cgi
index 3edbed371..493674c16 100755
--- a/heartbeat.cgi
+++ b/heartbeat.cgi
@@ -29,7 +29,6 @@ my $ok = eval {
die "database not available" unless $database_ok;
die "memcached server(s) not available" unless $memcached_ok;
- die "mod_perl not configured?" unless $ENV{MOD_PERL};
if ($dbh->isa('Bugzilla::DB::Mysql') && Bugzilla->params->{utf8} eq 'utf8mb4') {
my $mysql_var = $dbh->selectall_hashref(q{SHOW VARIABLES LIKE 'character_set%'}, 'Variable_name');
foreach my $name (qw( character_set_client character_set_connection character_set_database )) {
@@ -45,11 +44,4 @@ FATAL("heartbeat error: $@") if !$ok && $@;
my $cgi = Bugzilla->cgi;
print $cgi->header(-type => 'text/plain', -status => $ok ? '200 OK' : '500 Internal Server Error');
-print $ok ? "Bugzilla OK\n" : "Bugzilla NOT OK\n";
-
-if ($ENV{MOD_PERL}) {
- my $r = $cgi->r;
- # doing this supresses the error document, but does not change the http response code.
- $r->rflush;
- $r->status(200);
-}
+print $ok ? "Bugzilla OK\n" : "Bugzilla NOT OK\n"; \ No newline at end of file
diff --git a/jobqueue-worker.pl b/jobqueue-worker.pl
index b26aacdba..b26aacdba 100644..100755
--- a/jobqueue-worker.pl
+++ b/jobqueue-worker.pl
diff --git a/mod_perl.pl b/mod_perl.pl
deleted file mode 100644
index 09e3bac38..000000000
--- a/mod_perl.pl
+++ /dev/null
@@ -1,204 +0,0 @@
-#!/usr/bin/perl -T
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-#
-# This Source Code Form is "Incompatible With Secondary Licenses", as
-# defined by the Mozilla Public License, v. 2.0.
-
-package Bugzilla::ModPerl;
-
-use 5.10.1;
-use strict;
-use warnings;
-
-# This sets up our libpath without having to specify it in the mod_perl
-# configuration.
-use File::Basename;
-use File::Spec;
-BEGIN {
- require lib;
- my $dir = dirname(__FILE__);
- lib->import($dir, File::Spec->catdir($dir, "lib"), File::Spec->catdir($dir, qw(local lib perl5)));
-}
-
-use Bugzilla::ModPerl::StartupFix;
-use Taint::Util qw(untaint);
-
-use constant USE_NYTPROF => !! $ENV{USE_NYTPROF};
-use constant NYTPROF_DIR => do {
- my $dir = $ENV{NYTPROF_DIR};
- untaint($dir);
- $dir;
-};
-BEGIN {
- if (USE_NYTPROF) {
- $ENV{NYTPROF} = "savesrc=0:start=no:addpid=1";
- }
-}
-use if USE_NYTPROF, 'Devel::NYTProf::Apache';
-
-use Bugzilla::Constants ();
-
-# If you have an Apache2::Status handler in your Apache configuration,
-# you need to load Apache2::Status *here*, so that any later-loaded modules
-# can report information to Apache2::Status.
-#use Apache2::Status ();
-
-# We don't want to import anything into the global scope during
-# startup, so we always specify () after using any module in this
-# file.
-
-use Apache2::Log ();
-use Apache2::ServerUtil;
-use Apache2::SizeLimit;
-use ModPerl::RegistryLoader ();
-use File::Basename ();
-use File::Find ();
-use English qw(-no_match_vars $OSNAME);
-
-# This loads most of our modules.
-use Bugzilla ();
-# Loading Bugzilla.pm doesn't load this, though, and we want it preloaded.
-use Bugzilla::BugMail ();
-use Bugzilla::CGI ();
-use Bugzilla::Extension ();
-use Bugzilla::Install::Requirements ();
-use Bugzilla::Util ();
-use Bugzilla::RNG ();
-use Bugzilla::ModPerl ();
-use Mojo::Loader qw(find_modules);
-use Module::Runtime qw(require_module);
-use Bugzilla::WebService::Server::REST;
-
-# Make warnings go to the virtual host's log and not the main
-# server log.
-BEGIN { *CORE::GLOBAL::warn = \&Apache2::ServerRec::warn; }
-
-# Pre-compile the CGI.pm methods that we're going to use.
-Bugzilla::CGI->compile(qw(:cgi :push));
-
-# This means that every httpd child will die after processing a request if it
-# is taking up more than $apache_size_limit of RAM all by itself, not counting RAM it is
-# sharing with the other httpd processes.
-my $limit = Bugzilla->localconfig->{apache_size_limit};
-if ($OSNAME eq 'linux' && ! eval { require Linux::Smaps }) {
- WARN('SizeLimit requires Linux::Smaps on linux. size limit set to 800MB');
- $limit = 800_000;
-}
-Apache2::SizeLimit->set_max_unshared_size($limit);
-
-my $cgi_path = Bugzilla::Constants::bz_locations()->{'cgi_path'};
-
-# Set up the configuration for the web server
-my $server = Apache2::ServerUtil->server;
-my $conf = Bugzilla::ModPerl->apache_config($cgi_path);
-$server->add_config([ grep { length $_ } split("\n", $conf)]);
-
-# Pre-load localconfig. It might already be loaded, but we need to make sure.
-Bugzilla->localconfig;
-if ($ENV{LOCALCONFIG_ENV}) {
- delete @ENV{ (Bugzilla::Install::Localconfig::ENV_KEYS) };
-}
-
-# Pre-load all extensions
-Bugzilla::Extension->load_all();
-
-Bugzilla->preload_features();
-
-require_module($_) for find_modules('Bugzilla::User::Setting');
-
-Bugzilla::WebService::Server::REST->preload;
-
-# Force instantiation of template so Bugzilla::Template::PreloadProvider can do its magic.
-Bugzilla->preload_templates;
-
-# Have ModPerl::RegistryLoader pre-compile all CGI scripts.
-my $rl = new ModPerl::RegistryLoader();
-# If we try to do this in "new" it fails because it looks for a
-# Bugzilla/ModPerl/ResponseHandler.pm
-$rl->{package} = 'Bugzilla::ModPerl::ResponseHandler';
-my $feature_files = Bugzilla::Install::Requirements::map_files_to_features();
-
-# Prevent "use lib" from doing anything when the .cgi files are compiled.
-# This is important to prevent the current directory from getting into
-# @INC and messing things up. (See bug 630750.)
-no warnings 'redefine';
-local *lib::import = sub {};
-use warnings;
-
-foreach my $file (glob "$cgi_path/*.cgi") {
- my $base_filename = File::Basename::basename($file);
- if (my $feature = $feature_files->{$base_filename}) {
- next if !Bugzilla->feature($feature);
- }
- Bugzilla::Util::trick_taint($file);
- $rl->handler($file, $file);
-}
-
-# Some items might already be loaded into the request cache
-# best to make sure it starts out empty.
-# Because of bug 1347335 we also do this in init_page().
-Bugzilla::clear_request_cache();
-
-package Bugzilla::ModPerl::ResponseHandler;
-use strict;
-use base qw(ModPerl::Registry);
-use Bugzilla;
-use Bugzilla::Constants qw(USAGE_MODE_REST bz_locations);
-use Time::HiRes;
-use Sys::Hostname;
-
-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'};
-
- # Prevent "use lib" from modifying @INC in the case where a .cgi file
- # is being automatically recompiled by mod_perl when Apache is
- # running. (This happens if a file changes while Apache is already
- # running.)
- no warnings 'redefine';
- local *lib::import = sub {};
- use warnings;
-
- if (Bugzilla::ModPerl::USE_NYTPROF) {
- state $count = {};
- state $dir = Bugzilla::ModPerl::NYTPROF_DIR // bz_locations()->{datadir};
- state $host = (split(/\./, hostname()))[0];
- my $script = File::Basename::basename($ENV{SCRIPT_FILENAME});
- $script =~ s/\.cgi$//;
- my $file = $dir . "/nytprof.$host.$script." . ++$count->{$$};
- DB::enable_profile($file);
- }
- Bugzilla::init_page();
- my $result = $class->SUPER::handler(@_);
- if (Bugzilla::ModPerl::USE_NYTPROF) {
- DB::disable_profile();
- DB::finish_profile();
- }
-
- # When returning data from the REST api we must only return 200 or 304,
- # which tells Apache not to append its error html documents to the
- # response.
- return Bugzilla->usage_mode == USAGE_MODE_REST && $result != 304
- ? Apache2::Const::OK
- : $result;
-}
-
-
-package Bugzilla::ModPerl::CleanupHandler;
-use strict;
-use Apache2::Const -compile => qw(OK);
-
-sub handler {
- my $r = shift;
-
- Bugzilla::_cleanup();
-
- return Apache2::Const::OK;
-}
-
-1;
diff --git a/qa/t/lib/QA/Util.pm b/qa/t/lib/QA/Util.pm
index 5d041d560..bf9151fee 100644
--- a/qa/t/lib/QA/Util.pm
+++ b/qa/t/lib/QA/Util.pm
@@ -18,6 +18,7 @@ use Sys::Hostname qw(hostname);
use Socket qw(inet_ntoa);
use WWW::Selenium::Util qw(server_is_running);
use URI;
+use URI::QueryParam;
# Fixes wide character warnings
BEGIN {
@@ -50,6 +51,7 @@ use base qw(Exporter);
get_selenium
get_rpc_clients
+ check_page_load
WAIT_TIME
CHROME_MODE
@@ -396,6 +398,32 @@ sub set_parameters {
}
}
+my @ANY_KEYS = qw( t token );
+
+sub check_page_load {
+ my ($sel, $wait, $expected) = @_;
+ my $expected_uri = URI->new($expected);
+ $sel->wait_for_page_to_load_ok($wait);
+ my $uri = URI->new($sel->get_location);
+
+ foreach my $u ($expected_uri, $uri) {
+ $u->host('HOSTNAME');
+ foreach my $any_key (@ANY_KEYS) {
+ if ($u->query_param($any_key)) {
+ $u->query_param($any_key => '__ANYTHING__');
+ }
+ }
+ }
+
+ if ($expected_uri->query_param('id')) {
+ if ($expected_uri->query_param('id') eq '__BUG_ID__') {
+ $uri->query_param('id' => '__BUG_ID__');
+ }
+ }
+ my ($pkg, $file, $line) = caller;
+ is($uri, $expected_uri, "checking location on $file line $line");
+}
+
1;
__END__
diff --git a/qa/t/test_bug_edit.t b/qa/t/test_bug_edit.t
index 07a64876b..01037aa1e 100644
--- a/qa/t/test_bug_edit.t
+++ b/qa/t/test_bug_edit.t
@@ -32,10 +32,10 @@ if ($sel->is_text_present("My bugs from QA_Selenium")) {
# Just in case the test failed before completion previously, reset the CANEDIT bit.
go_to_admin($sel);
$sel->click_ok("link=Groups");
-$sel->wait_for_page_to_load_ok(WAIT_TIME);
+check_page_load($sel, WAIT_TIME, q{http://HOSTNAME:8000/bmo/editgroups.cgi});
$sel->title_is("Edit Groups");
$sel->click_ok("link=Master");
-$sel->wait_for_page_to_load_ok(WAIT_TIME);
+check_page_load($sel, WAIT_TIME, q{http://HOSTNAME:8000/bmo/editgroups.cgi?action=changeform&group=26});
$sel->title_is("Change Group: Master");
my $group_url = $sel->get_location();
$group_url =~ /group=(\d+)$/;
@@ -52,7 +52,7 @@ $sel->select_ok("bug_severity", "label=critical");
$sel->type_ok("short_desc", "Test bug editing");
$sel->type_ok("comment", "ploc");
$sel->click_ok("commit");
-$sel->wait_for_page_to_load_ok(WAIT_TIME);
+check_page_load($sel, WAIT_TIME, qq{http://HOSTNAME:8000/bmo/show_bug.cgi?id=__BUG_ID__});
my $bug1_id = $sel->get_value('//input[@name="id" and @type="hidden"]');
$sel->is_text_present_ok('has been added to the database', "Bug $bug1_id created");
@@ -67,28 +67,28 @@ $sel->type_ok("status_whiteboard", "[Selenium was here]");
$sel->type_ok("comment", "new comment from me :)");
$sel->select_ok("bug_status", "label=RESOLVED");
$sel->click_ok("commit");
-$sel->wait_for_page_to_load_ok(WAIT_TIME);
+check_page_load($sel, WAIT_TIME, qq{http://HOSTNAME:8000/bmo/show_bug.cgi?id=$bug1_id});
$sel->is_text_present_ok("Changes submitted for bug $bug1_id");
# Now move the bug into another product, which has a mandatory group.
$sel->click_ok("link=bug $bug1_id");
-$sel->wait_for_page_to_load_ok(WAIT_TIME);
+check_page_load($sel, WAIT_TIME, qq{http://HOSTNAME:8000/bmo/show_bug.cgi?id=$bug1_id});
$sel->title_like(qr/^$bug1_id /);
$sel->select_ok("product", "label=QA-Selenium-TEST");
$sel->type_ok("comment", "moving to QA-Selenium-TEST");
$sel->click_ok("commit");
-$sel->wait_for_page_to_load_ok(WAIT_TIME);
+check_page_load($sel, WAIT_TIME, q{http://HOSTNAME:8000/bmo/process_bug.cgi});
$sel->title_is("Verify New Product Details...");
$sel->select_ok("component", "label=QA-Selenium-TEST");
$sel->is_element_present_ok('//input[@type="checkbox" and @name="groups" and @value="QA-Selenium-TEST"]');
ok(!$sel->is_editable('//input[@type="checkbox" and @name="groups" and @value="QA-Selenium-TEST"]'), "QA-Selenium-TEST group not editable");
$sel->is_checked_ok('//input[@type="checkbox" and @name="groups" and @value="QA-Selenium-TEST"]', "QA-Selenium-TEST group is selected");
$sel->click_ok("change_product");
-$sel->wait_for_page_to_load_ok(WAIT_TIME);
+check_page_load($sel, WAIT_TIME, qq{http://HOSTNAME:8000/bmo/show_bug.cgi?id=$bug1_id});
$sel->is_text_present_ok("Changes submitted for bug $bug1_id");
$sel->click_ok("link=bug $bug1_id");
-$sel->wait_for_page_to_load_ok(WAIT_TIME);
+check_page_load($sel, WAIT_TIME, qq{http://HOSTNAME:8000/bmo/show_bug.cgi?id=$bug1_id});
$sel->title_like(qr/^$bug1_id /);
$sel->select_ok("bug_severity", "label=normal");
$sel->select_ok("priority", "label=High");
@@ -101,14 +101,14 @@ $sel->type_ok("comment", "Unchecking the reporter_accessible checkbox");
$sel->click_ok("reporter_accessible");
$sel->select_ok("bug_status", "label=VERIFIED");
$sel->click_ok("commit");
-$sel->wait_for_page_to_load_ok(WAIT_TIME);
+check_page_load($sel, WAIT_TIME, qq{http://HOSTNAME:8000/bmo/show_bug.cgi?id=$bug1_id});
$sel->is_text_present_ok("Changes submitted for bug $bug1_id");
$sel->click_ok("link=bug $bug1_id");
-$sel->wait_for_page_to_load_ok(WAIT_TIME);
+check_page_load($sel, WAIT_TIME, qq{http://HOSTNAME:8000/bmo/show_bug.cgi?id=$bug1_id});
$sel->title_like(qr/^$bug1_id /);
$sel->type_ok("comment", "I am the reporter, but I can see the bug anyway as I belong to the mandatory group");
$sel->click_ok("commit");
-$sel->wait_for_page_to_load_ok(WAIT_TIME);
+check_page_load($sel, WAIT_TIME, qq{http://HOSTNAME:8000/bmo/show_bug.cgi?id=$bug1_id});
$sel->is_text_present_ok("Changes submitted for bug $bug1_id");
logout($sel);
@@ -125,16 +125,16 @@ $sel->click_ok("bz_assignee_edit_action");
$sel->type_ok("assigned_to", $config->{admin_user_login});
$sel->type_ok("comment", "I have editbugs privs. Taking!");
$sel->click_ok("commit");
-$sel->wait_for_page_to_load_ok(WAIT_TIME);
+check_page_load($sel, WAIT_TIME, qq{http://HOSTNAME:8000/bmo/show_bug.cgi?id=$bug1_id});
$sel->is_text_present_ok("Changes submitted for bug $bug1_id");
$sel->click_ok("link=bug $bug1_id");
-$sel->wait_for_page_to_load_ok(WAIT_TIME);
+check_page_load($sel, WAIT_TIME, qq{http://HOSTNAME:8000/bmo/show_bug.cgi?id=$bug1_id});
$sel->title_like(qr/^$bug1_id /);
$sel->click_ok("cc_edit_area_showhide");
$sel->type_ok("newcc", $config->{unprivileged_user_login});
$sel->click_ok("commit");
-$sel->wait_for_page_to_load_ok(WAIT_TIME);
+check_page_load($sel, WAIT_TIME, qq{http://HOSTNAME:8000/bmo/show_bug.cgi?id=$bug1_id});
$sel->is_text_present_ok("Changes submitted for bug $bug1_id");
logout($sel);
@@ -153,7 +153,7 @@ go_to_bug($sel, $bug1_id);
$sel->click_ok("cclist_accessible");
$sel->type_ok("comment", "I am allowed to turn off cclist_accessible despite not being in the mandatory group");
$sel->click_ok("commit");
-$sel->wait_for_page_to_load_ok(WAIT_TIME);
+check_page_load($sel, WAIT_TIME, qq{http://HOSTNAME:8000/bmo/show_bug.cgi?id=$bug1_id});
$sel->is_text_present_ok("Changes submitted for bug $bug1_id");
logout($sel);
@@ -162,7 +162,7 @@ logout($sel);
log_in($sel, $config, 'unprivileged');
$sel->type_ok("quicksearch_top", $bug1_id);
$sel->submit("header-search");
-$sel->wait_for_page_to_load_ok(WAIT_TIME);
+check_page_load($sel, WAIT_TIME, qq{http://HOSTNAME:8000/bmo/show_bug.cgi?id=$bug1_id});
$sel->title_is("Access Denied");
$sel->is_text_present_ok("You are not authorized to access bug $bug1_id");
logout($sel);
@@ -178,7 +178,7 @@ $sel->click_ok("set_default_assignee");
$sel->uncheck_ok("set_default_assignee");
$sel->type_ok("comment", "-> Moving back to Testproduct.");
$sel->click_ok("commit");
-$sel->wait_for_page_to_load_ok(WAIT_TIME);
+check_page_load($sel, WAIT_TIME, q{http://HOSTNAME:8000/bmo/process_bug.cgi});
$sel->title_is("Verify New Product Details...");
$sel->select_ok("component", "label=TestComponent");
$sel->is_text_present_ok("These groups are not legal for the 'TestProduct' product or you are not allowed to restrict bugs to these groups");
@@ -189,15 +189,15 @@ $sel->is_element_present_ok('//input[@type="checkbox" and @name="groups" and @va
$sel->is_editable_ok('//input[@type="checkbox" and @name="groups" and @value="Master"]', "Master group is editable");
ok(!$sel->is_checked('//input[@type="checkbox" and @name="groups" and @value="Master"]'), "Master group not selected by default");
$sel->click_ok("change_product");
-$sel->wait_for_page_to_load_ok(WAIT_TIME);
+check_page_load($sel, WAIT_TIME, qq{http://HOSTNAME:8000/bmo/show_bug.cgi?id=$bug1_id});
$sel->is_text_present_ok("Changes submitted for bug $bug1_id");
$sel->click_ok("link=bug $bug1_id");
-$sel->wait_for_page_to_load_ok(WAIT_TIME);
+check_page_load($sel, WAIT_TIME, qq{http://HOSTNAME:8000/bmo/show_bug.cgi?id=$bug1_id});
$sel->title_like(qr/^$bug1_id /);
$sel->click_ok("cclist_accessible");
$sel->type_ok("comment", "I am allowed to turn off cclist_accessible despite not being in the mandatory group");
$sel->click_ok("commit");
-$sel->wait_for_page_to_load_ok(WAIT_TIME);
+check_page_load($sel, WAIT_TIME, qq{http://HOSTNAME:8000/bmo/show_bug.cgi?id=$bug1_id});
$sel->is_text_present_ok("Changes submitted for bug $bug1_id");
logout($sel);
@@ -216,7 +216,7 @@ $sel->click_ok("cc_edit_area_showhide");
$sel->add_selection_ok("cc", "label=" . $config->{admin_user_login});
$sel->click_ok("removecc");
$sel->click_ok("commit");
-$sel->wait_for_page_to_load_ok(WAIT_TIME);
+check_page_load($sel, WAIT_TIME, qq{http://HOSTNAME:8000/bmo/show_bug.cgi?id=$bug1_id});
$sel->is_text_present_ok("Changes submitted for bug $bug1_id");
logout($sel);
@@ -225,11 +225,11 @@ logout($sel);
log_in($sel, $config, 'admin');
edit_product($sel, "TestProduct");
$sel->click_ok("link=Edit Group Access Controls:");
-$sel->wait_for_page_to_load_ok(WAIT_TIME);
+check_page_load($sel, WAIT_TIME, q{http://HOSTNAME:8000/bmo/editproducts.cgi?action=editgroupcontrols&product=TestProduct});
$sel->title_is("Edit Group Controls for TestProduct");
$sel->check_ok("canedit_$master_gid");
$sel->click_ok("submit");
-$sel->wait_for_page_to_load_ok(WAIT_TIME);
+check_page_load($sel, WAIT_TIME, q{http://HOSTNAME:8000/bmo/editproducts.cgi});
$sel->title_is("Update group access controls for TestProduct");
# The user is in the master group, so he can comment.
@@ -237,7 +237,7 @@ $sel->title_is("Update group access controls for TestProduct");
go_to_bug($sel, $bug1_id);
$sel->type_ok("comment", "Do nothing except adding a comment...");
$sel->click_ok("commit");
-$sel->wait_for_page_to_load_ok(WAIT_TIME);
+check_page_load($sel, WAIT_TIME, qq{http://HOSTNAME:8000/bmo/show_bug.cgi?id=$bug1_id});
$sel->is_text_present_ok("Changes submitted for bug $bug1_id");
logout($sel);
@@ -247,7 +247,7 @@ log_in($sel, $config, 'QA_Selenium_TEST');
go_to_bug($sel, $bug1_id);
$sel->type_ok("comment", "Just a comment too...");
$sel->click_ok("commit");
-$sel->wait_for_page_to_load_ok(WAIT_TIME);
+check_page_load($sel, WAIT_TIME, q{http://HOSTNAME:8000/bmo/process_bug.cgi});
$sel->title_is("Product Edit Access Denied");
$sel->is_text_present_ok("You are not permitted to edit bugs in product TestProduct.");
logout($sel);
@@ -256,10 +256,12 @@ logout($sel);
log_in($sel, $config, 'admin');
open_advanced_search_page($sel);
+screenshot_page($sel, '/app/artifacts/line259.png');
$sel->remove_all_selections_ok("product");
$sel->add_selection_ok("product", "TestProduct");
$sel->remove_all_selections_ok("bug_status");
$sel->remove_all_selections_ok("resolution");
+screenshot_page($sel, '/app/artifacts/line264.png');
$sel->is_checked_ok("emailassigned_to1");
$sel->select_ok("emailtype1", "label=is");
$sel->type_ok("email1", $config->{admin_user_login});
@@ -268,21 +270,22 @@ $sel->check_ok("emailqa_contact2");
$sel->check_ok("emailcc2");
$sel->select_ok("emailtype2", "label=is");
$sel->type_ok("email2", $config->{QA_Selenium_TEST_user_login});
+screenshot_page($sel, '/app/artifacts/line271.png');
$sel->click_ok("Search");
-$sel->wait_for_page_to_load_ok(WAIT_TIME);
+check_page_load($sel, WAIT_TIME, q{http://HOSTNAME:8000/bmo/buglist.cgi?emailreporter2=1&emailtype2=exact&order=Importance&list_id=15&emailtype1=exact&emailcc2=1&query_format=advanced&emailassigned_to1=1&emailqa_contact2=1&email2=QA-Selenium-TEST%40mozilla.test&email1=admin%40mozilla.test&emailassigned_to2=1&product=TestProduct});
$sel->title_is("Bug List");
-
+screenshot_page($sel, '/app/artifacts/line275.png');
$sel->is_text_present_ok("One bug found.");
$sel->type_ok("save_newqueryname", "My bugs from QA_Selenium");
$sel->click_ok("remember");
-$sel->wait_for_page_to_load_ok(WAIT_TIME);
+check_page_load($sel, WAIT_TIME, q{http://HOSTNAME:8000/bmo/buglist.cgi?newquery=email1%3Dadmin%2540mozilla.test%26email2%3DQA-Selenium-TEST%2540mozilla.test%26emailassigned_to1%3D1%26emailassigned_to2%3D1%26emailcc2%3D1%26emailqa_contact2%3D1%26emailreporter2%3D1%26emailtype1%3Dexact%26emailtype2%3Dexact%26list_id%3D15%26product%3DTestProduct%26query_format%3Dadvanced%26order%3Dpriority%252Cbug_severity&cmdtype=doit&remtype=asnamed&token=1531926552-dc69995d79c786af046436ec6717000b&newqueryname=My%20bugs%20from%20QA_Selenium&list_id=16});
$sel->title_is("Search created");
$sel->is_text_present_ok("OK, you have a new search named My bugs from QA_Selenium.");
$sel->click_ok("link=My bugs from QA_Selenium");
-$sel->wait_for_page_to_load_ok(WAIT_TIME);
+check_page_load($sel, WAIT_TIME, q{http://HOSTNAME:8000/bmo/buglist.cgi?cmdtype=runnamed&namedcmd=My%20bugs%20from%20QA_Selenium&list_id=17});
$sel->title_is("Bug List: My bugs from QA_Selenium");
$sel->click_ok("long_format");
-$sel->wait_for_page_to_load_ok(WAIT_TIME);
+check_page_load($sel, WAIT_TIME, q{http://HOSTNAME:8000/bmo/show_bug.cgi});
$sel->title_is("Full Text Bug Listing");
$sel->is_text_present_ok("Bug $bug1_id");
$sel->is_text_present_ok("Status: CONFIRMED");
@@ -303,25 +306,25 @@ $sel->type_ok("short_desc", "New bug from me");
# We turned on the CANEDIT bit for TestProduct.
$sel->type_ok("comment", "I can enter a new bug, but not edit it, right?");
$sel->click_ok("commit");
-$sel->wait_for_page_to_load_ok(WAIT_TIME);
+check_page_load($sel, WAIT_TIME, qq{http://HOSTNAME:8000/bmo/show_bug.cgi?id=__BUG_ID__});
my $bug2_id = $sel->get_value('//input[@name="id" and @type="hidden"]');
$sel->is_text_present_ok('has been added to the database', "Bug $bug2_id created");
# Clicking the "Back" button and resubmitting the form again should trigger a suspicous action error.
$sel->go_back_ok();
-$sel->wait_for_page_to_load_ok(WAIT_TIME);
+check_page_load($sel, WAIT_TIME, q{http://HOSTNAME:8000/bmo/enter_bug.cgi?product=TestProduct&format=__default__});
$sel->title_is("Enter Bug: TestProduct");
$sel->click_ok("commit");
-$sel->wait_for_page_to_load_ok(WAIT_TIME);
+check_page_load($sel, WAIT_TIME, q{http://HOSTNAME:8000/bmo/post_bug.cgi});
$sel->title_is("Suspicious Action");
$sel->is_text_present_ok("you have no valid token for the create_bug action");
$sel->click_ok('//input[@value="Confirm Changes"]');
-$sel->wait_for_page_to_load_ok(WAIT_TIME);
+check_page_load($sel, WAIT_TIME, q{http://HOSTNAME:8000/bmo/show_bug.cgi?id=15});
$sel->is_text_present_ok('has been added to the database', 'Bug created');
$sel->type_ok("comment", "New comment not allowed");
$sel->click_ok("commit");
-$sel->wait_for_page_to_load_ok(WAIT_TIME);
+check_page_load($sel, WAIT_TIME, q{http://HOSTNAME:8000/bmo/process_bug.cgi});
$sel->title_is("Product Edit Access Denied");
$sel->is_text_present_ok("You are not permitted to edit bugs in product TestProduct.");
logout($sel);
@@ -334,42 +337,46 @@ $sel->click_ok("bz_assignee_edit_action");
$sel->type_ok("assigned_to", $config->{admin_user_login});
$sel->type_ok("comment", "Taking!");
$sel->click_ok("commit");
-$sel->wait_for_page_to_load_ok(WAIT_TIME);
+check_page_load($sel, WAIT_TIME, qq{http://HOSTNAME:8000/bmo/show_bug.cgi?id=$bug2_id});
$sel->is_text_present_ok("Changes submitted for bug $bug2_id");
# Test mass-change.
$sel->click_ok("link=My bugs from QA_Selenium");
-$sel->wait_for_page_to_load_ok(WAIT_TIME);
+screenshot_page($sel, '/app/artifacts/line344.png');
+check_page_load($sel, WAIT_TIME, q{http://HOSTNAME:8000/bmo/buglist.cgi?cmdtype=runnamed&namedcmd=My%20bugs%20from%20QA_Selenium&list_id=19});
+screenshot_page($sel, '/app/artifacts/line346.png');
$sel->title_is("Bug List: My bugs from QA_Selenium");
+screenshot_page($sel, '/app/artifacts/line348.png');
$sel->is_text_present_ok("2 bugs found");
+screenshot_page($sel, '/app/artifacts/line350.png');
$sel->click_ok("link=Change Several Bugs at Once");
-$sel->wait_for_page_to_load_ok(WAIT_TIME);
+check_page_load($sel, WAIT_TIME, q{http://HOSTNAME:8000/bmo/buglist.cgi?email1=admin%40mozilla.test&email2=QA-Selenium-TEST%40mozilla.test&emailassigned_to1=1&emailassigned_to2=1&emailcc2=1&emailqa_contact2=1&emailreporter2=1&emailtype1=exact&emailtype2=exact&product=TestProduct&query_format=advanced&order=priority%2Cbug_severity&tweak=1&list_id=20});
$sel->title_is("Bug List");
$sel->click_ok("check_all");
$sel->type_ok("comment", 'Mass change"');
$sel->select_ok("bug_status", "label=RESOLVED");
$sel->select_ok("resolution", "label=WORKSFORME");
$sel->click_ok("commit");
-$sel->wait_for_page_to_load_ok(WAIT_TIME);
+check_page_load($sel, WAIT_TIME, q{http://HOSTNAME:8000/bmo/process_bug.cgi});
$sel->title_is("Bugs processed");
$sel->click_ok("link=bug $bug1_id");
-$sel->wait_for_page_to_load_ok(WAIT_TIME);
+check_page_load($sel, WAIT_TIME, qq{http://HOSTNAME:8000/bmo/show_bug.cgi?id=$bug1_id});
$sel->title_like(qr/$bug1_id /);
$sel->selected_label_is("resolution", "WORKSFORME");
$sel->select_ok("resolution", "label=INVALID");
$sel->click_ok("commit");
-$sel->wait_for_page_to_load_ok(WAIT_TIME);
+check_page_load($sel, WAIT_TIME, qq{http://HOSTNAME:8000/bmo/show_bug.cgi?id=$bug1_id});
$sel->is_text_present_ok("Changes submitted for bug $bug1_id");
$sel->click_ok("link=bug $bug1_id");
-$sel->wait_for_page_to_load_ok(WAIT_TIME);
+check_page_load($sel, WAIT_TIME, qq{http://HOSTNAME:8000/bmo/show_bug.cgi?id=$bug1_id});
$sel->title_like(qr/$bug1_id /);
$sel->selected_label_is("resolution", "INVALID");
$sel->click_ok("link=History");
-$sel->wait_for_page_to_load_ok(WAIT_TIME);
+check_page_load($sel, WAIT_TIME, qq{http://HOSTNAME:8000/bmo/show_activity.cgi?id=$bug1_id});
$sel->title_is("Changes made to bug $bug1_id");
$sel->is_text_present_ok("URL foo.cgi?action=bar");
$sel->is_text_present_ok("Severity critical blocker");
@@ -431,10 +438,10 @@ foreach my $params (["no_token_single_bug", ""], ["invalid_token_single_bug", "&
$sel->title_is("Suspicious Action");
$sel->is_text_present_ok($token ? "an invalid token" : "web browser directly");
$sel->click_ok("confirm");
- $sel->wait_for_page_to_load_ok(WAIT_TIME);
+ check_page_load($sel, WAIT_TIME, qq{http://HOSTNAME:8000/bmo/show_bug.cgi?id=$bug1_id});
$sel->is_text_present_ok("Changes submitted for bug $bug1_id");
$sel->click_ok("link=bug $bug1_id");
- $sel->wait_for_page_to_load_ok(WAIT_TIME);
+ check_page_load($sel, WAIT_TIME, qq{http://HOSTNAME:8000/bmo/show_bug.cgi?id=$bug1_id});
$sel->title_like(qr/^$bug1_id /);
$sel->is_text_present_ok($comment);
}
@@ -446,16 +453,16 @@ foreach my $params (["no_token_mass_change", ""], ["invalid_token_mass_change",
$sel->title_is("Suspicious Action");
$sel->is_text_present_ok("no valid token for the buglist_mass_change action");
$sel->click_ok("confirm");
- $sel->wait_for_page_to_load_ok(WAIT_TIME);
+ check_page_load($sel, WAIT_TIME, q{http://HOSTNAME:8000/bmo/process_bug.cgi});
$sel->title_is("Bugs processed");
foreach my $bug_id ($bug1_id, $bug2_id) {
$sel->click_ok("link=bug $bug_id");
- $sel->wait_for_page_to_load_ok(WAIT_TIME);
+ check_page_load($sel, WAIT_TIME, qq{http://HOSTNAME:8000/bmo/show_bug.cgi?id=$bug_id});
$sel->title_like(qr/^$bug_id /);
$sel->is_text_present_ok($comment);
next if $bug_id == $bug2_id;
$sel->go_back_ok();
- $sel->wait_for_page_to_load_ok(WAIT_TIME);
+ check_page_load($sel, WAIT_TIME, q{http://HOSTNAME:8000/bmo/process_bug.cgi});
$sel->title_is("Bugs processed");
}
}
@@ -463,26 +470,26 @@ foreach my $params (["no_token_mass_change", ""], ["invalid_token_mass_change",
# Now move these bugs out of our radar.
$sel->click_ok("link=My bugs from QA_Selenium");
-$sel->wait_for_page_to_load_ok(WAIT_TIME);
+check_page_load($sel, WAIT_TIME, q{http://HOSTNAME:8000/bmo/buglist.cgi?cmdtype=runnamed&namedcmd=My%20bugs%20from%20QA_Selenium&list_id=21});
$sel->title_is("Bug List: My bugs from QA_Selenium");
$sel->is_text_present_ok("2 bugs found");
$sel->click_ok("link=Change Several Bugs at Once");
-$sel->wait_for_page_to_load_ok(WAIT_TIME);
+check_page_load($sel, WAIT_TIME, q{http://HOSTNAME:8000/bmo/buglist.cgi?email1=admin%40mozilla.test&email2=QA-Selenium-TEST%40mozilla.test&emailassigned_to1=1&emailassigned_to2=1&emailcc2=1&emailqa_contact2=1&emailreporter2=1&emailtype1=exact&emailtype2=exact&product=TestProduct&query_format=advanced&order=priority%2Cbug_severity&tweak=1&list_id=22});
$sel->title_is("Bug List");
$sel->click_ok("check_all");
$sel->type_ok("comment", "Reassigning to the reporter");
$sel->type_ok("assigned_to", $config->{QA_Selenium_TEST_user_login});
$sel->click_ok("commit");
-$sel->wait_for_page_to_load_ok(WAIT_TIME);
+check_page_load($sel, WAIT_TIME, q{http://HOSTNAME:8000/bmo/process_bug.cgi});
$sel->title_is("Bugs processed");
# Now delete the saved search.
$sel->click_ok("link=My bugs from QA_Selenium");
-$sel->wait_for_page_to_load_ok(WAIT_TIME);
+check_page_load($sel, WAIT_TIME, q{http://HOSTNAME:8000/bmo/buglist.cgi?cmdtype=runnamed&namedcmd=My%20bugs%20from%20QA_Selenium&list_id=23});
$sel->title_is("Bug List: My bugs from QA_Selenium");
$sel->click_ok("link=Forget Search 'My bugs from QA_Selenium'");
-$sel->wait_for_page_to_load_ok(WAIT_TIME);
+check_page_load($sel, WAIT_TIME, q{http://HOSTNAME:8000/bmo/buglist.cgi?cmdtype=dorem&remaction=forget&namedcmd=My%20bugs%20from%20QA_Selenium&token=1531926582-f228fa8ebc2f2b3970f2a791e54534ec&list_id=24});
$sel->title_is("Search is gone");
$sel->is_text_present_ok("OK, the My bugs from QA_Selenium search is gone");
@@ -495,10 +502,10 @@ sub clear_canedit_on_testproduct {
edit_product($sel, "TestProduct");
$sel->click_ok("link=Edit Group Access Controls:");
- $sel->wait_for_page_to_load_ok(WAIT_TIME);
+check_page_load($sel, WAIT_TIME, q{http://HOSTNAME:8000/bmo/editproducts.cgi?action=editgroupcontrols&product=TestProduct});
$sel->title_is("Edit Group Controls for TestProduct");
$sel->uncheck_ok("canedit_$master_gid");
$sel->click_ok("submit");
- $sel->wait_for_page_to_load_ok(WAIT_TIME);
+check_page_load($sel, WAIT_TIME, q{http://HOSTNAME:8000/bmo/editproducts.cgi});
$sel->title_is("Update group access controls for TestProduct");
}
diff --git a/qa/t/test_shutdown.t b/qa/t/test_shutdown.t
deleted file mode 100644
index dc5cabd4a..000000000
--- a/qa/t/test_shutdown.t
+++ /dev/null
@@ -1,72 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-#
-# This Source Code Form is "Incompatible With Secondary Licenses", as
-# defined by the Mozilla Public License, v. 2.0.
-
-use strict;
-use warnings;
-use lib qw(lib ../../lib ../../local/lib/perl5);
-
-use Test::More "no_plan";
-
-use QA::Util;
-
-my ($sel, $config) = get_selenium();
-
-log_in($sel, $config, 'admin');
-set_parameters($sel, { "General" => {shutdownhtml => {type => "text",
- value => "I'm down (set by test_shutdown.t)" }
- } });
-
-# None of the following pages should be accessible when Bugzilla is down.
-
-my @pages = qw(admin attachment buglist chart colchange config createaccount
- describecomponents describekeywords duplicates
- editclassifications editcomponents editfields editflagtypes
- editgroups editkeywords editmilestones editproducts editsettings
- editusers editvalues editversions editwhines editworkflow
- enter_bug index long_list page post_bug process_bug query quips
- relogin report reports request sanitycheck search_plugin
- show_activity show_bug showattachment showdependencygraph
- showdependencytree sidebar summarize_time token userprefs votes
- xml xmlrpc);
-
-foreach my $page (@pages) {
- $sel->open_ok("/$config->{bugzilla_installation}/${page}.cgi");
- $sel->title_is("Bugzilla is Down");
-}
-
-# Those have parameters passed to the page, so we put them here separately.
-
-@pages = ("query.cgi?format=report-table", "query.cgi?format=report-graph",
- "votes.cgi?action=show_user", "votes.cgi?action=show_bug");
-
-foreach my $page (@pages) {
- $sel->open_ok("/$config->{bugzilla_installation}/$page");
- $sel->title_is("Bugzilla is Down");
-}
-
-# Clear 'shutdownhtml', to re-enable Bugzilla.
-# At this point, the admin has been logged out. We cannot use log_in(),
-# nor set_parameters(), due to shutdownhtml being active.
-
-$sel->open_ok("/$config->{bugzilla_installation}/editparams.cgi");
-$sel->title_is("Log in to Bugzilla");
-$sel->type_ok("Bugzilla_login", $config->{admin_user_login}, "Enter admin login name");
-$sel->type_ok("Bugzilla_password", $config->{admin_user_passwd}, "Enter admin password");
-$sel->click_ok("log_in");
-$sel->wait_for_page_to_load_ok(WAIT_TIME);
-$sel->title_is("Configuration: General");
-$sel->type_ok("shutdownhtml", "");
-$sel->click_ok('//input[@type="submit" and @value="Save Changes"]', undef, "Save Changes");
-$sel->wait_for_page_to_load_ok(WAIT_TIME);
-$sel->title_is("Parameters Updated");
-
-# Accessing index.cgi should work again now.
-
-$sel->click_ok('//*[@id="header-title"]//a');
-$sel->wait_for_page_to_load_ok(WAIT_TIME);
-$sel->title_is("Bugzilla Main Page");
-logout($sel);
diff --git a/scripts/block-ip.pl b/scripts/block-ip.pl
index b767a1fd5..3fa66d336 100755
--- a/scripts/block-ip.pl
+++ b/scripts/block-ip.pl
@@ -12,8 +12,8 @@ use warnings;
use lib qw(. lib local/lib/perl5);
use Bugzilla;
+use Bugzilla::Quantum;
use Bugzilla::Constants;
-use Bugzilla::ModPerl::BlockIP;
use Getopt::Long;
Bugzilla->usage_mode(USAGE_MODE_CMDLINE);
@@ -23,10 +23,12 @@ GetOptions('unblock' => \$unblock);
pod2usage("No IPs given") unless @ARGV;
+my $app = Bugzilla::Quantum->new;
+
if ($unblock) {
- Bugzilla::ModPerl::BlockIP->unblock_ip($_) for @ARGV;
+ $app->unblock_ip($_) for @ARGV;
} else {
- Bugzilla::ModPerl::BlockIP->block_ip($_) for @ARGV;
+ $app->block_ip($_) for @ARGV;
}
=head1 NAME
@@ -52,4 +54,4 @@ If passed, the IPs will be unblocked instead of blocked. Use this to remove IPs
=head1 DESCRIPTION
-This is just a simple CLI inteface to L<Bugzilla::ModPerl::BlockIP>.
+This is just a simple CLI inteface to L<Bugzilla::Quantum::Plugin::BlockIP>.
diff --git a/scripts/entrypoint.pl b/scripts/entrypoint.pl
index ce1cc795b..21d9aebb1 100755
--- a/scripts/entrypoint.pl
+++ b/scripts/entrypoint.pl
@@ -83,7 +83,6 @@ sub cmd_demo {
sub cmd_httpd {
check_data_dir();
wait_for_db();
- check_httpd_env();
my $httpd_exit_f = run_cereal_and_httpd();
assert_httpd()->get();
@@ -156,6 +155,7 @@ sub cmd_test_webservices {
sub cmd_test_selenium {
my $conf = require $ENV{BZ_QA_CONF_FILE};
+ $ENV{HTTP_BACKEND} = 'simple';
check_data_dir();
copy_qa_extension();
@@ -207,8 +207,6 @@ sub cmd_test_bmo {
sub run_prove {
my (%param) = @_;
- check_httpd_env();
-
my $prove_cmd = $param{prove_cmd};
my $prove_dir = $param{prove_dir};
assert_httpd()->then(sub {
@@ -268,16 +266,6 @@ sub check_env {
die 'Missing required environmental variables: ', join(', ', @missing_env), "\n";
}
}
-sub check_httpd_env {
- check_env(qw(
- HTTPD_StartServers
- HTTPD_MinSpareServers
- HTTPD_MaxSpareServers
- HTTPD_ServerLimit
- HTTPD_MaxClients
- HTTPD_MaxRequestsPerChild
- ))
-}
sub fix_path {
$ENV{PATH} = "/app/local/bin:$ENV{PATH}";
diff --git a/scripts/undo.pl b/scripts/undo.pl
index 24d6f594b..24d6f594b 100644..100755
--- a/scripts/undo.pl
+++ b/scripts/undo.pl
diff --git a/t/001compile.t b/t/001compile.t
index e81162056..3d8d82bf4 100644
--- a/t/001compile.t
+++ b/t/001compile.t
@@ -35,7 +35,7 @@ sub compile_file {
my ($file) = @_;
# Don't allow CPAN.pm to modify the global @INC, which the version
- # shipped with Perl 5.8.8 does. (It gets loaded by
+ # shipped with Perl 5.8.8 does. (It gets loaded by
# Bugzilla::Install::CPAN.)
local @INC = @INC;
@@ -43,10 +43,6 @@ sub compile_file {
skip "$file: extensions not tested", 1;
return;
}
- if ($file =~ /ModPerl/) {
- skip "$file: ModPerl stuff not tested", 1;
- return;
- }
if ($file =~ s/\.pm$//) {
$file =~ s{/}{::}g;
@@ -82,7 +78,7 @@ my $file_features = map_files_to_features();
# Test the scripts by compiling them
foreach my $file (@testitems) {
# These were already compiled, above.
- next if ($file eq 'Bugzilla.pm'
+ next if ($file eq 'Bugzilla.pm'
or $file eq 'Bugzilla/Constants.pm'
or $file eq 'Bugzilla/Install/Requirements.pm');
SKIP: {
@@ -94,10 +90,10 @@ foreach my $file (@testitems) {
skip "$file: $feature not enabled", 1;
}
- # Check that we have a DBI module to support the DB, if this
+ # Check that we have a DBI module to support the DB, if this
# is a database module (but not Schema)
if ($file =~ m{Bugzilla/DB/([^/]+)\.pm$}
- and $file ne "Bugzilla/DB/Schema.pm")
+ and $file ne "Bugzilla/DB/Schema.pm")
{
my $module = lc($1);
Bugzilla->feature($module) or skip "$file: Driver for $module not installed", 1;
@@ -105,4 +101,4 @@ foreach my $file (@testitems) {
compile_file($file);
}
-}
+}
diff --git a/t/002goodperl.t b/t/002goodperl.t
index 5f201160b..80d7cf2b9 100644
--- a/t/002goodperl.t
+++ b/t/002goodperl.t
@@ -83,6 +83,7 @@ foreach my $file (@testitems) {
my $found_use_strict = 0;
my $found_use_warnings = 0;
my $found_modern_perl = 0;
+ my $found_mojo = 0;
$file =~ s/\s.*$//; # nuke everything after the first space (#comment)
next if (!$file); # skip null entries
@@ -92,13 +93,17 @@ foreach my $file (@testitems) {
}
while (my $file_line = <FILE>) {
$found_modern_perl = 1 if $file_line =~ m/^use\s*(?:Moo|Role::Tiny)/;
+ $found_mojo = 1 if $file_line =~ m/^use\s(?:Mojo(?:licious::Lite|::Base)\b)/;
$found_use_perl = 1 if $file_line =~ m/^\s*use 5.10.1/;
$found_use_strict = 1 if $file_line =~ m/^\s*use strict/;
$found_use_warnings = 1 if $file_line =~ m/^\s*use warnings/;
- if ($found_modern_perl) {
+ if ($found_modern_perl || $found_mojo) {
$found_use_strict = 1;
$found_use_warnings = 1;
}
+ if ($found_mojo) {
+ $found_use_perl = 1;
+ }
last if ($found_use_perl && $found_use_strict && $found_use_warnings);
}
close (FILE);
diff --git a/template/en/default/admin/params/editparams.html.tmpl b/template/en/default/admin/params/editparams.html.tmpl
index 838bff7ef..6e8bc2257 100644
--- a/template/en/default/admin/params/editparams.html.tmpl
+++ b/template/en/default/admin/params/editparams.html.tmpl
@@ -21,7 +21,6 @@
[%# INTERFACE:
# panels: array of hashes representing the panels available.
# param_changed: array of parameters which have been changed.
- # shutdown_is_active: boolean; is true when 'shutdownhtml' has been turned on.
#%]
[% PROCESS global/variables.none.tmpl %]
diff --git a/template/en/default/admin/params/general.html.tmpl b/template/en/default/admin/params/general.html.tmpl
index f1b86e19f..05e8f09a2 100644
--- a/template/en/default/admin/params/general.html.tmpl
+++ b/template/en/default/admin/params/general.html.tmpl
@@ -48,11 +48,6 @@
_ " &quot;on&quot;, you must re-run <kbd>checksetup.pl</kbd> immediately"
_ " afterward.</p>",
- shutdownhtml =>
- "If this field is non-empty, then $terms.Bugzilla will be completely"
- _ " disabled and this text will be displayed instead of all the"
- _ " $terms.Bugzilla pages.",
-
announcehtml =>
"If this field is non-empty, then $terms.Bugzilla will"
_ " display whatever is in this field at the top of every"
diff --git a/template/en/default/global/field-descs.none.tmpl b/template/en/default/global/field-descs.none.tmpl
index 3e0a528dc..cb6240c29 100644
--- a/template/en/default/global/field-descs.none.tmpl
+++ b/template/en/default/global/field-descs.none.tmpl
@@ -162,13 +162,11 @@ if ( $stash->get("in_template_var") ) {
# database. If you want to override this for your language
# or your installation, just use a hook. %]
my $bug_fields = $stash->get("bug_fields");
- unless ( Bugzilla->params->{shutdownhtml} ) {
- foreach my $bz_field ( values %$bug_fields ) {
- $vars->{field_descs}{$bz_field->name} //= $bz_field->description;
- }
-
- $context->process("bug/field-help.none.tmpl");
+ foreach my $bz_field ( values %$bug_fields ) {
+ $vars->{field_descs}{$bz_field->name} //= $bz_field->description;
}
+
+ $context->process("bug/field-help.none.tmpl");
}
[% END %]
diff --git a/template/en/default/global/header.html.tmpl b/template/en/default/global/header.html.tmpl
index bd9ec8bcb..9db9a1404 100644
--- a/template/en/default/global/header.html.tmpl
+++ b/template/en/default/global/header.html.tmpl
@@ -97,6 +97,8 @@
[% IF Param('utf8') %]
<meta charset="UTF-8">
[% END %]
+ [% USE Bugzilla %]
+ <base href="[% urlbase FILTER html %]">
[% IF Bugzilla.cgi.should_block_referrer %]
<meta name="referrer" content="origin">
diff --git a/template/en/default/global/messages.html.tmpl b/template/en/default/global/messages.html.tmpl
index 591617f3e..278b0f161 100644
--- a/template/en/default/global/messages.html.tmpl
+++ b/template/en/default/global/messages.html.tmpl
@@ -140,7 +140,7 @@
[% ELSIF message_tag == "buglist_updated_named_query" %]
[% title = "Search updated" %]
- Your search named <code><a
+ Your search named <code><a
href="buglist.cgi?cmdtype=runnamed&amp;namedcmd=[% queryname FILTER uri %]"
>[% queryname FILTER html %]</a></code> has been updated.
@@ -298,22 +298,22 @@
[% ELSIF message_tag == "email_change_canceled_reinstated" %]
[% title = "Cancel Request to Change Email Address" %]
The request to change the email address for the
- account [%+ old_email FILTER html %] to
+ account [%+ old_email FILTER html %] to
[%+ new_email FILTER html %] has been canceled.
Your old account settings have been reinstated.
[% ELSIF message_tag == "extension_created" %]
An extension named [% name FILTER html %] has been created
- in [% path FILTER html %]. Make sure you change "YOUR NAME" and
+ in [% path FILTER html %]. Make sure you change "YOUR NAME" and
"YOUR EMAIL ADDRESS" in the code to your name and your email address.
[% ELSIF message_tag == "field_value_created" %]
[% title = "New Field Value Created" %]
- The value <em>[% value.name FILTER html %]</em> has been added as a
+ The value <em>[% value.name FILTER html %]</em> has been added as a
valid choice for the <em>[% field.description FILTER html %]</em>
(<em>[% field.name FILTER html %]</em>) field.
[% IF field.name == "bug_status" %]
- You should now visit the <a href="editworkflow.cgi">status workflow
+ You should now visit the <a href="editworkflow.cgi">status workflow
page</a> to include your new [% terms.bug %] status.
[% END %]
@@ -331,7 +331,7 @@
(<em>[% field.name FILTER html %]</em>) field has been changed:
<ul>
[% IF changes.value %]
- <li>Field value updated to
+ <li>Field value updated to
<em>[% changes.value.1 FILTER html %]</em>.
[% IF value.is_default %]
(Note that this value is the default for this field. All
@@ -340,16 +340,16 @@
</li>
[% END %]
[% IF changes.sortkey %]
- <li>Sortkey updated to
+ <li>Sortkey updated to
<em>[% changes.sortkey.1 FILTER html %]</em>.</li>
[% END %]
[% IF changes.visibility_value_id %]
[% IF value.visibility_value.defined %]
- <li>It only appears when
+ <li>It only appears when
[%+ value.field.value_field.description FILTER html %] is set to
'[%+ value.visibility_value.name FILTER html %]'.</li>
[% ELSE %]
- <li>It now always appears, no matter what
+ <li>It now always appears, no matter what
[%+ value.field.value_field.description FILTER html %] is set to.
</li>
[% END %]
@@ -535,7 +535,7 @@
Reading users...
[% ELSIF message_tag == "migrate_translating_bugs" %]
- Converting [% terms.bug %] values to be appropriate for
+ Converting [% terms.bug %] values to be appropriate for
[%+ terms.Bugzilla %]...
[% ELSIF message_tag == "migrate_user_created" %]
@@ -594,12 +594,6 @@
No changes made.
[% END %]
- [% IF shutdown_is_active == 1 %]
- <hr>
- [% terms.Bugzilla %] has now been shut down. To re-enable the system,
- clear the <em>shutdownhtml</em> field.
- [% END%]
-
[% ELSIF message_tag == "password_change_canceled" %]
[% title = "Cancel Request to Change Password" %]
Your request has been canceled.
@@ -731,7 +725,7 @@
[% ELSIF message_tag == "install_fk_invalid" %]
ERROR: There are invalid values for the [% column FILTER html %] column in the [% table FILTER html %]
- table. (These values do not exist in the [% foreign_table FILTER html %] table, in the
+ table. (These values do not exist in the [% foreign_table FILTER html %] table, in the
[%+ foreign_column FILTER html %] column.)
Before continuing with checksetup, you will need to fix these values,
@@ -789,8 +783,8 @@
to be editable by both you and the web server must be world writable, and
other files (including the localconfig file which stores your database
password) must be world readable. This means that _anyone_ who can obtain
- local access to this machine can do whatever they want to your
- [%+ terms.Bugzilla %] installation, and is probably also able to run
+ local access to this machine can do whatever they want to your
+ [%+ terms.Bugzilla %] installation, and is probably also able to run
arbitrary Perl code as the user that the web server runs as.
You really, really, really need to change this setting.
@@ -798,10 +792,10 @@
[% ELSIF message_tag == "install_webservergroup_not_in" %]
Warning: you have entered a value for the "webservergroup" parameter in
- localconfig, but you are not either a) running this script as [% constants.ROOT_USER FILTER html %];
- or b) a member of this group. This can cause permissions problems and
+ localconfig, but you are not either a) running this script as [% constants.ROOT_USER FILTER html %];
+ or b) a member of this group. This can cause permissions problems and
decreased security. If you experience problems running [% terms.Bugzilla %]
- scripts, log in as [% constants.ROOT_USER FILTER html %] and re-run this script, become a
+ scripts, log in as [% constants.ROOT_USER FILTER html %] and re-run this script, become a
member of the group, or remove the value of the "webservergroup" parameter.
[% ELSIF message_tag == "install_webservergroup_windows" %]
@@ -836,7 +830,7 @@
products you can choose from.
[% ELSIF message_tag == "remaining_time_zeroed" %]
- The [% field_descs.remaining_time FILTER html %] field has been
+ The [% field_descs.remaining_time FILTER html %] field has been
set to zero automatically as part of closing this [% terms.bug %]
or moving it from one closed state to another.
@@ -856,21 +850,21 @@
[% ELSIF message_tag == "sudo_started" %]
[% title = "Sudo session started" %]
- The sudo session has been started. For the next 6 hours, or until you
- end the session, everything you do you do as the user you are
+ The sudo session has been started. For the next 6 hours, or until you
+ end the session, everything you do you do as the user you are
impersonating ([% target FILTER html %]).
-
+
[% ELSIF message_tag == "sudo_ended" %]
[% title = "Sudo session complete" %]
- The sudo session has been ended. From this point forward, everything you
+ The sudo session has been ended. From this point forward, everything you
do you do as yourself.
[% ELSIF message_tag == "series_created" %]
[% title = "Series Created" %]
The series <em>[% series.category FILTER html %] /
- [%+ series.subcategory FILTER html %] /
+ [%+ series.subcategory FILTER html %] /
[%+ series.name FILTER html %]</em>
- has been created. Note that you may need to wait up to
+ has been created. Note that you may need to wait up to
[%+ series.frequency * 2 %] days before there will be enough data for a
chart of this series to be produced.
@@ -881,14 +875,6 @@
[%+ series.name FILTER html %]</em>
has been deleted.
- [% ELSIF message_tag == "shutdown" %]
- [% title = "$terms.Bugzilla is Down" %]
- [% Param("shutdownhtml") %]
- [% IF userid %]
- <p>For security reasons, you have been logged out automatically.
- The cookie that was remembering your login is now gone.
- [% END %]
-
[% ELSIF message_tag == "tag_updated" %]
[% title = "Tag Updated" %]
The '<a href="buglist.cgi?tag=[% tag FILTER uri %]">[% tag FILTER html %]</a>'
@@ -908,7 +894,7 @@
Some flags could not be set. Please check your changes.
[% ELSIF message_tag == "user_match_failed" %]
- You entered a username that did not match any known
+ You entered a username that did not match any known
[% terms.Bugzilla %] users, so we have instead left
the [% match_field FILTER html %] field blank.
diff --git a/vagrant_support/apache.yml b/vagrant_support/apache.yml
index 5031187e3..2d65965ab 100644
--- a/vagrant_support/apache.yml
+++ b/vagrant_support/apache.yml
@@ -6,8 +6,8 @@
mode: 0644
when: LAZY == 0
-- name: enable httpd
- service: name=httpd enabled=yes
+- name: disable httpd
+ service: name=httpd enabled=no
when: LAZY == 0
- name: ensure bugzilla.log has right permissions
@@ -16,5 +16,5 @@
- name: ensure bugzilla-json.log has right permissions
file: path=/vagrant/logs/bugzilla-json.log state=touch owner=vagrant group=apache mode=0660
-- name: restart httpd
- service: name=httpd state=restarted \ No newline at end of file
+- name: stop httpd
+ service: name=httpd state=stopped
diff --git a/vagrant_support/hypnotoad b/vagrant_support/hypnotoad
new file mode 100755
index 000000000..5e8dc910e
--- /dev/null
+++ b/vagrant_support/hypnotoad
@@ -0,0 +1,122 @@
+#!/bin/bash
+#
+# bugzilla-push This starts, stops, and restarts the Bugzilla push
+# daemon, which manages syncronising bugzilla.mozilla.org and
+# third party bugzilla installs.
+#
+# chkconfig: 345 85 15
+# description: Bugzilla push daemon
+#
+### BEGIN INIT INFO
+# Provides: bugzilla-push
+# Required-Start: $local_fs $syslog MTA mysqld
+# Required-Stop: $local_fs $syslog MTA mysqld
+# Default-Start: 3 5
+# Default-Stop: 0 1 2 6
+# Short-Description: Start and stop the Bugzilla push daemon.
+# Description: The Bugzilla push daemon (bugzilla-pushd.pl)
+#
+#
+#
+### END INIT INFO
+
+NAME=`basename $0`
+
+#################
+# Configuration #
+#################
+
+# This should be the path to your Bugzilla
+BUGZILLA=/vagrant
+# Who owns the Bugzilla directory and files?
+USER=vagrant
+
+PERL5LIB="$BUGZILLA:$BUGZILLA/lib:$BUGZILLA/local/lib/perl5"
+export PERL5LIB
+export MOJO_MODE
+
+if [[ x$PORT == x ]]; then
+ PORT=80
+ export PORT
+fi
+
+# If you want to pass any options to the daemon (like -d for debugging)
+# specify it here.
+OPTIONS=""
+
+# You can also override the configuration by creating a
+# /etc/sysconfig/bugzilla-queue file so that you don't
+# have to edit this script.
+if [ -r /etc/sysconfig/$NAME ]; then
+ . /etc/sysconfig/$NAME
+fi
+
+##########
+# Script #
+##########
+
+RETVAL=0
+BIN="$BUGZILLA/local/bin/hypnotoad"
+PIDFILE="$BUGZILLA/hypnotoad.pid"
+
+# Source function library.
+. /etc/rc.d/init.d/functions
+
+usage ()
+{
+ echo "Usage: service $NAME {start|stop|status|restart|condrestart}"
+ RETVAL=1
+}
+
+
+start ()
+{
+ if [[ -f $PIDFILE ]]; then
+ checkpid "$(cat $PIDFILE)" && return 0
+ fi
+ echo -n "Starting $NAME: "
+ daemon --pidfile=$PIDFILE --user=$USER "cd $BUGZILLA && $BIN bugzilla.pl >/dev/null"
+ ret=$?
+ [ $ret -eq "0" ] && touch /var/lock/subsys/$NAME
+ echo
+ return $ret
+}
+
+stop ()
+{
+ cd $BUGZILLA && $BIN bugzilla.pl --stop
+ rm -f /var/lock/subsys/$NAME
+}
+
+restart ()
+{
+ stop
+ start
+}
+
+condrestart ()
+{
+ [ -e /var/lock/subsys/$NAME ] && restart || return 0
+}
+
+status ()
+{
+ if [[ -f $PIDFILE ]] && checkpid "$(cat $PIDFILE)"; then
+ echo hypnotoad is amazing
+ return 0
+ else
+ echo hypnotoad is not running
+ return 1
+ fi
+}
+
+case "$1" in
+ start) start; RETVAL=$? ;;
+ stop) stop; RETVAL=$? ;;
+ status) status; RETVAL=$?;;
+ restart) restart; RETVAL=$? ;;
+ condrestart) condrestart; RETVAL=$? ;;
+ *) usage ; RETVAL=2 ;;
+esac
+
+exit $RETVAL
diff --git a/vagrant_support/hypnotoad.yml b/vagrant_support/hypnotoad.yml
new file mode 100644
index 000000000..a66f9ba04
--- /dev/null
+++ b/vagrant_support/hypnotoad.yml
@@ -0,0 +1,27 @@
+- name: grant perl ability to listen to privledged ports
+ command: setcap 'cap_net_bind_service=+ep' /usr/bin/perl
+
+- name: hypnotoad daemon sysconfig
+ copy:
+ dest: /etc/sysconfig/hypnotoad
+ mode: 0644
+ content: |
+ BUGZILLA=/vagrant
+ USER=vagrant
+ MOJO_MODE=development
+
+- name: hypnotoad daemon init file
+ template:
+ dest: /etc/init.d/hypnotoad
+ src: hypnotoad
+ owner: root
+ group: root
+ mode: 0755
+
+- name: enable hypnotoad
+ service: name=hypnotoad enabled=yes
+ when: LAZY == 0
+
+- name: restart hypnotoad
+ service: name=hypnotoad state=restarted
+
diff --git a/vagrant_support/playbook.yml b/vagrant_support/playbook.yml
index c067eab05..3dd320f0b 100644
--- a/vagrant_support/playbook.yml
+++ b/vagrant_support/playbook.yml
@@ -170,9 +170,6 @@
dest: /usr/local/bin/cpanm
mode: '0755'
- - name: install more recent Apache2::SizeLimit
- cpanm: name=Apache2::SizeLimit executable=/usr/local/bin/cpanm
-
- name: 'check /opt/bmo (failure is ok)'
shell: test -d /opt/bmo && test -f /opt/bmo/local/lib/perl5/Plack.pm
register: opt_bmo
@@ -222,5 +219,8 @@
- include_tasks: apache.yml
vars:
LAZY: 0
+ - include_tasks: hypnotoad.yml
+ vars:
+ LAZY: 0
- import_tasks: devtools.yml
diff --git a/vagrant_support/update.yml b/vagrant_support/update.yml
index c53a0554e..533da5b5e 100644
--- a/vagrant_support/update.yml
+++ b/vagrant_support/update.yml
@@ -20,4 +20,7 @@
LAZY: 1
- include_tasks: apache.yml
vars:
- LAZY: 1 \ No newline at end of file
+ LAZY: 1
+ - include_tasks: hypnotoad.yml
+ vars:
+ LAZY: 1