summaryrefslogtreecommitdiffstats
path: root/Bugzilla
diff options
context:
space:
mode:
authorDylan William Hardison <dylan@hardison.net>2018-05-21 20:14:53 +0200
committerDylan William Hardison <dylan@hardison.net>2018-06-28 22:41:56 +0200
commit3d8dc32afa0131e2ac0cd121b492aed8ad59fc11 (patch)
tree2d3489acbaa726ff7daaee0758c2bbd50c8fe13a /Bugzilla
parent15661bf793105352c3cf0d84d6c7e790be838a78 (diff)
downloadbugzilla-3d8dc32afa0131e2ac0cd121b492aed8ad59fc11.tar.gz
bugzilla-3d8dc32afa0131e2ac0cd121b492aed8ad59fc11.tar.xz
working more
Diffstat (limited to 'Bugzilla')
-rw-r--r--Bugzilla/CGI.pm4
-rw-r--r--Bugzilla/CPAN.pm2
-rw-r--r--Bugzilla/PSGI.pm43
-rw-r--r--Bugzilla/Quantum.pm10
-rw-r--r--Bugzilla/Quantum/CGI.pm136
-rw-r--r--Bugzilla/Quantum/Plugin/Glue.pm93
-rw-r--r--Bugzilla/WebService/Util.pm8
7 files changed, 126 insertions, 170 deletions
diff --git a/Bugzilla/CGI.pm b/Bugzilla/CGI.pm
index 495cb4769..1e070290e 100644
--- a/Bugzilla/CGI.pm
+++ b/Bugzilla/CGI.pm
@@ -600,7 +600,7 @@ sub header {
}
}
my $headers = $self->SUPER::header(%headers) || '';
- if ($self->server_software eq 'Bugzilla::Quantum::Plugin::Glue') {
+ if ($self->server_software eq 'Bugzilla::Quantum::CGI') {
my $c = Bugzilla->request_cache->{mojo_controller};
$c->res->headers->parse($headers);
return '';
@@ -711,7 +711,7 @@ sub redirect {
$self->{bz_redirecting} = 1;
use Carp;
carp "redirect @_\n";
- if ($self->server_software eq 'Bugzilla::Quantum::Plugin::Glue') {
+ if ($self->server_software eq 'Bugzilla::Quantum::CGI') {
my $c = Bugzilla->request_cache->{mojo_controller};
$self->SUPER::redirect(@_);
$c->redirect_to($c->res->headers->location);
diff --git a/Bugzilla/CPAN.pm b/Bugzilla/CPAN.pm
index d765d2901..1b6fb93b9 100644
--- a/Bugzilla/CPAN.pm
+++ b/Bugzilla/CPAN.pm
@@ -103,7 +103,7 @@ sub feature {
my $meta = $class->cpan_meta;
my $feature = $meta->feature($feature_name);
my @modules = $feature->prereqs->merged_requirements(['runtime'], ['requires'])->required_modules;
- Module::Runtime::require_module($_) foreach @modules;
+ Module::Runtime::require_module($_) foreach grep { !/^Test::Taint$/ } @modules;
return $FEATURE_LOADED{$feature_name} = 1;
}
diff --git a/Bugzilla/PSGI.pm b/Bugzilla/PSGI.pm
deleted file mode 100644
index e2963ff7a..000000000
--- a/Bugzilla/PSGI.pm
+++ /dev/null
@@ -1,43 +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::PSGI;
-use 5.10.1;
-use strict;
-use warnings;
-
-use base qw(Exporter);
-
-use Bugzilla::Logging;
-our @EXPORT_OK = qw(compile_cgi);
-
-sub compile_cgi {
- my ($script) = @_;
- require CGI::Compile;
- require CGI::Emulate::PSGI;
-
- my $cgi = CGI::Compile->compile($script);
- my $app = CGI::Emulate::PSGI->handler(
- sub {
- Bugzilla::init_page();
- $ENV{PATH_INFO} = '' if $ENV{PATH_INFO} eq '/';
- $cgi->();
- }
- );
- return sub {
- my $env = shift;
- if ($env->{'psgix.cleanup'}) {
- push @{ $env->{'psgix.cleanup.handler'} }, \&Bugzilla::_cleanup;
- }
- my $res = $app->($env);
- Bugzilla::_cleanup() if not $env->{'psgix.cleanup'};
- return $res;
- };
-}
-
-
-1;
diff --git a/Bugzilla/Quantum.pm b/Bugzilla/Quantum.pm
index 9b98bffa2..f40348653 100644
--- a/Bugzilla/Quantum.pm
+++ b/Bugzilla/Quantum.pm
@@ -12,7 +12,6 @@ use CGI::Compile; # Primarily for its exit overload.
use Bugzilla::Quantum::Template;
use Bugzilla::Quantum::CGI;
use Bugzilla::Quantum::Static;
-use Bugzilla::PSGI qw(compile_cgi);
use Bugzilla ();
use Bugzilla::Constants qw(bz_locations);
@@ -34,15 +33,14 @@ sub startup {
Bugzilla->template;
$self->secrets([Bugzilla->localconfig->{side_wide_secret}]);
- my $rest = compile_cgi('rest.cgi');
$self->plugin('Bugzilla::Quantum::Plugin::Glue');
my $r = $self->routes;
- Bugzilla::Quantum::CGI->expose_routes($r);
+ Bugzilla::Quantum::CGI->load_all($r);
- $r->any('/')->to('CGI#handle_index');
- $r->any('/rest')->to('CGI#handle_rest');
- $r->any('/rest/*path_info')->to('CGI#handle_rest');
+ $r->any('/')->to('CGI#index_cgi');
+ $r->any('/rest')->to('CGI#rest_cgi');
+ $r->any('/rest/*path_info')->to('CGI#rest_cgi');
$r->get(
'/__lbheartbeat__' => sub {
diff --git a/Bugzilla/Quantum/CGI.pm b/Bugzilla/Quantum/CGI.pm
index fab2b145d..9b9af51de 100644
--- a/Bugzilla/Quantum/CGI.pm
+++ b/Bugzilla/Quantum/CGI.pm
@@ -12,44 +12,136 @@ use CGI::Compile;
use Bugzilla::Constants qw(bz_locations);
use File::Slurper qw(read_text);
use File::Spec::Functions qw(catfile);
+use Sub::Name;
use Sub::Quote 2.005000;
+use Try::Tiny;
use Taint::Util qw(untaint);
+use Socket qw(AF_INET inet_aton);
+use Capture::Tiny qw(capture_stdout);
+use Sys::Hostname;
-my %CGIS;
-
-_load_all();
-
-sub expose_routes {
+sub load_all {
my ($class, $r) = @_;
- foreach my $cgi (keys %CGIS) {
- $r->any("/$cgi")->to("CGI#$CGIS{$cgi}");
- }
-}
+ my $stash = Package::Stash->new(__PACKAGE__);
-sub _load_all {
foreach my $script (glob '*.cgi') {
- my $name = _load_cgi($script);
- $CGIS{ $script } = $name;
+ my ($name, $method) = $class->_load_cgi($script);
+ $stash->add_symbol("&$name" => $method);
+ $r->any("/$script")->to("CGI#$name");
}
}
-sub _load_cgi {
- my ($file) = @_;
- my $name = $file;
- $name =~ s/\.cgi$//s;
+sub _file_to_method {
+ my ($name) = @_;
+ $name =~ s/\./_/s;
$name =~ s/\W+/_/gs;
- my $subname = "handle_$name";
- my $content = read_text(catfile(bz_locations->{cgi_path}, $file));
+ return $name;
+}
+
+my %SEEN;
+
+sub _load_cgi {
+ my ($class, $file) = @_;
+ my $name = _file_to_method($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);
- $content = 'my ($self) = @_; ' . $content;
my %options = (
- package => __PACKAGE__ . "::$name",
+ package => $package,
file => $file,
line => 1,
no_defer => 1,
);
- quote_sub $subname, $content, {}, \%options;
- return $subname;
+ 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;
+ my $stdout = '';
+ local %ENV = $c->_ENV;
+ local *STDIN; ## no critic (local)
+ local $CGI::Compile::USE_REAL_EXIT = 0;
+ open STDIN, '<', $stdin->path or die "STDIN @{[$stdin->path]}: $!" if -s $stdin->path;
+ try {
+ Bugzilla->init_page();
+ Bugzilla->request_cache->{mojo_controller} = $c;
+ $stdout = capture_stdout \&$inner;
+ }
+ catch {
+ die $_ unless ref $_ eq 'ARRAY' && $_->[0] eq "EXIT\n" || /\bModPerl::Util::exit\b/;
+ }
+ finally {
+ if ( length $stdout ) {
+ warn "setting body\n";
+ $c->res->body($stdout);
+ $c->rendered;
+ }
+ Bugzilla->_cleanup; ## no critic (private)
+ CGI::initialize_globals();
+ };
+ };
+ return ($name, subname($name, $wrapper));
+}
+
+sub _ENV {
+ my ($c) = @_;
+ 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 = $c->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 : '';
+ }
+
+ return (
+ CONTENT_LENGTH => $content_length || 0,
+ CONTENT_TYPE => $headers->content_type || '',
+ GATEWAY_INTERFACE => 'CGI/1.1',
+ HTTPS => $req->is_secure ? 'YES' : 'NO',
+ %env_headers,
+ QUERY_STRING => $c->stash('cgi.query_string') || $req->url->query->to_string,
+ REMOTE_ADDR => $tx->remote_address,
+ REMOTE_HOST => gethostbyaddr( inet_aton( $tx->remote_address || '127.0.0.1' ), AF_INET ) || '',
+ REMOTE_PORT => $tx->remote_port,
+ REMOTE_USER => $remote_user || '',
+ REQUEST_METHOD => $req->method,
+ SCRIPT_NAME => $req->env->{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 );
}
1; \ No newline at end of file
diff --git a/Bugzilla/Quantum/Plugin/Glue.pm b/Bugzilla/Quantum/Plugin/Glue.pm
index 17dc443c6..822987ad8 100644
--- a/Bugzilla/Quantum/Plugin/Glue.pm
+++ b/Bugzilla/Quantum/Plugin/Glue.pm
@@ -11,9 +11,6 @@ use Mojo::Base 'Mojolicious::Plugin';
use Try::Tiny;
use Bugzilla::Constants;
use Bugzilla::Quantum::Template;
-use Socket qw(AF_INET inet_aton);
-use Sys::Hostname;
-use IO::String;
sub register {
my ( $self, $app, $conf ) = @_;
@@ -44,99 +41,9 @@ sub register {
or die $template->error;
}
);
-
- $app->hook(
- around_dispatch => sub {
- my ($next, $c) = @_;
- local %ENV = _ENV($c);
- my $stdin = _STDIN($c);
- my $stdout = '';
- try {
- local $CGI::Compile::USE_REAL_EXIT = 0;
- local *STDIN; ## no critic (local)
- local *STDOUT;
- open STDIN, '<', $stdin->path or die "STDIN @{[$stdin->path]}: $!" if -s $stdin->path;
- open STDOUT, '>', \$stdout or die "STDOUT capture: $!";
-
- Bugzilla::init_page();
- Bugzilla->request_cache->{mojo_controller} = $c;
- Bugzilla->template( Bugzilla::Quantum::Template->new( controller => $c, template => $template ) );
- $next->();
- }
- catch {
- die $_ unless ref $_ eq 'ARRAY' && $_->[0] eq "EXIT\n" || /\bModPerl::Util::exit\b/;
- }
- finally {
- if (length $stdout) {
- warn "setting body\n";
- $c->res->body($stdout);
- $c->rendered;
- }
- Bugzilla::_cleanup; ## no critic (private)
- CGI::initialize_globals();
- };
- }
- );
-}
-
-sub _ENV {
- my ($c) = @_;
- 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 = $c->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 : '';
- }
-
- return (
- CONTENT_LENGTH => $content_length || 0,
- CONTENT_TYPE => $headers->content_type || '',
- GATEWAY_INTERFACE => 'CGI/1.1',
- HTTPS => $req->is_secure ? 'YES' : 'NO',
- %env_headers,
- QUERY_STRING => $c->stash('cgi.query_string') || $req->url->query->to_string,
- REMOTE_ADDR => $tx->remote_address,
- REMOTE_HOST => gethostbyaddr( inet_aton( $tx->remote_address || '127.0.0.1' ), AF_INET ) || '',
- REMOTE_PORT => $tx->remote_port,
- REMOTE_USER => $remote_user || '',
- REQUEST_METHOD => $req->method,
- SCRIPT_NAME => $req->env->{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 );
-}
1; \ No newline at end of file
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 {