From 3d8dc32afa0131e2ac0cd121b492aed8ad59fc11 Mon Sep 17 00:00:00 2001 From: Dylan William Hardison Date: Mon, 21 May 2018 14:14:53 -0400 Subject: working more --- Bugzilla/CGI.pm | 4 +- Bugzilla/CPAN.pm | 2 +- Bugzilla/PSGI.pm | 43 ------------- Bugzilla/Quantum.pm | 10 ++- Bugzilla/Quantum/CGI.pm | 136 +++++++++++++++++++++++++++++++++------- Bugzilla/Quantum/Plugin/Glue.pm | 93 --------------------------- Bugzilla/WebService/Util.pm | 8 ++- 7 files changed, 126 insertions(+), 170 deletions(-) delete mode 100644 Bugzilla/PSGI.pm (limited to 'Bugzilla') 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 { -- cgit v1.2.3-24-g4f1b