summaryrefslogtreecommitdiffstats
path: root/Bugzilla.pm
diff options
context:
space:
mode:
Diffstat (limited to 'Bugzilla.pm')
-rw-r--r--Bugzilla.pm227
1 files changed, 87 insertions, 140 deletions
diff --git a/Bugzilla.pm b/Bugzilla.pm
index f5e64c371..3d7cb50d5 100644
--- a/Bugzilla.pm
+++ b/Bugzilla.pm
@@ -22,7 +22,7 @@ BEGIN {
}
}
-our $VERSION = '20180330.1';
+our $VERSION = '20180703.1';
use Bugzilla::Auth;
use Bugzilla::Auth::Persist::Cookie;
@@ -38,6 +38,8 @@ use Bugzilla::Flag;
use Bugzilla::Hook;
use Bugzilla::Install::Localconfig qw(read_localconfig);
use Bugzilla::Install::Util qw(init_console include_languages);
+use Bugzilla::Markdown::GFM;
+use Bugzilla::Markdown::GFM::Parser;
use Bugzilla::Memcached;
use Bugzilla::Template;
use Bugzilla::Token;
@@ -46,17 +48,12 @@ use Bugzilla::Util;
use Bugzilla::CPAN;
use Bugzilla::Bloomfilter;
-use Bugzilla::Metrics::Collector;
-use Bugzilla::Metrics::Template;
-use Bugzilla::Metrics::Memcached;
-
use Date::Parse;
use DateTime::TimeZone;
use Encode;
use File::Basename;
use File::Spec::Functions;
use Safe;
-use Sys::Syslog qw(:DEFAULT);
use JSON::XS qw(decode_json);
use URI;
@@ -83,6 +80,11 @@ use constant SHUTDOWNHTML_EXIT_SILENTLY => qw(
# should search engines attempt to index the page again?
use constant SHUTDOWNHTML_RETRY_AFTER => 3600;
+# This is identical to Install::Util::_cache so that things loaded
+# into Install::Util::_cache during installation can be read out
+# of request_cache later in installation.
+use constant request_cache => Bugzilla::Install::Util::_cache();
+
#####################################################################
# Global Code
#####################################################################
@@ -101,7 +103,7 @@ sub init_page {
}
if (i_am_cgi()) {
- Log::Log4perl::MDC->put(remote_ip => remote_ip());
+ Bugzilla::Logging->fields->{remote_ip} = remote_ip();
}
if (${^TAINT}) {
@@ -120,30 +122,6 @@ sub init_page {
my $script = basename($0);
- # BMO - init metrics collection if required
- if (i_am_cgi() && $script eq 'show_bug.cgi') {
- # we need to measure loading the params, so default to on
- Bugzilla->metrics_enabled(1);
- Bugzilla->metrics($script);
- # we can now hit params to check if we really should be enabled.
- # note - we can't use anything which uses templates or the database, as
- # that would initialise those modules with metrics enabled.
- if (!Bugzilla->params->{metrics_enabled}) {
- Bugzilla->metrics_enabled(0);
- }
- else {
- # to avoid generating massive amounts of data, we're only interested in
- # a small subset of users
- my $user_id = Bugzilla->cgi->cookie('Bugzilla_login');
- if (!$user_id
- || !grep { $user_id == $_ }
- split(/\s*,\s*/, Bugzilla->params->{metrics_user_ids}))
- {
- Bugzilla->metrics_enabled(0);
- }
- }
- }
-
# Because of attachment_base, attachment.cgi handles this itself.
if ($script ne 'attachment.cgi') {
do_ssl_redirect_if_required();
@@ -212,28 +190,21 @@ sub init_page {
#####################################################################
sub template {
- # BMO - use metrics subclass if required
- if (Bugzilla->metrics_enabled) {
- $_[0]->request_cache->{template} ||= Bugzilla::Metrics::Template->create();
- } else {
- $_[0]->request_cache->{template} ||= Bugzilla::Template->create();
- }
- $_[0]->request_cache->{template}->{_is_main} = 1;
+ request_cache->{template} ||= Bugzilla::Template->create();
+ request_cache->{template}->{_is_main} = 1;
- return $_[0]->request_cache->{template};
+ return request_cache->{template};
}
sub template_inner {
- my ($class, $lang) = @_;
- my $cache = $class->request_cache;
+ my (undef, $lang) = @_;
+ my $cache = request_cache;
my $current_lang = $cache->{template_current_lang}->[0];
$lang ||= $current_lang || '';
return $cache->{"template_inner_$lang"} ||= Bugzilla::Template->create(language => $lang);
}
sub extensions {
- my ($class) = @_;
-
# Guard against extensions querying the extension list during initialization
# (through this method or has_extension).
# The extension list is not fully populated at that point,
@@ -242,7 +213,7 @@ sub extensions {
die "Recursive attempt to load/query extensions" if $recursive;
$recursive = 1;
- my $cache = $class->request_cache;
+ my $cache = request_cache;
if (!$cache->{extensions}) {
my $extension_packages = Bugzilla::Extension->load_all();
my @extensions;
@@ -269,12 +240,12 @@ sub has_extension {
}
sub cgi {
- return $_[0]->request_cache->{cgi} ||= new Bugzilla::CGI();
+ return request_cache->{cgi} ||= new Bugzilla::CGI();
}
sub input_params {
my ($class, $params) = @_;
- my $cache = $class->request_cache;
+ my $cache = request_cache;
# This is how the WebService and other places set input_params.
if (defined $params) {
$cache->{input_params} = $params;
@@ -300,7 +271,7 @@ sub urlbase {
}
sub params {
- return $_[0]->request_cache->{params} ||= Bugzilla::Config::read_param_file();
+ return request_cache->{params} ||= Bugzilla::Config::read_param_file();
}
sub get_param_with_override {
@@ -309,32 +280,32 @@ sub get_param_with_override {
}
sub user {
- return $_[0]->request_cache->{user} ||= new Bugzilla::User;
+ return request_cache->{user} ||= new Bugzilla::User;
}
sub set_user {
- my ($class, $user) = @_;
- $class->request_cache->{user} = $user;
+ my (undef, $user) = @_;
+ request_cache->{user} = $user;
}
sub sudoer {
- return $_[0]->request_cache->{sudoer};
+ return request_cache->{sudoer};
}
sub sudo_request {
- my ($class, $new_user, $new_sudoer) = @_;
- $class->request_cache->{user} = $new_user;
- $class->request_cache->{sudoer} = $new_sudoer;
+ my (undef, $new_user, $new_sudoer) = @_;
+ request_cache->{user} = $new_user;
+ request_cache->{sudoer} = $new_sudoer;
# NOTE: If you want to log the start of an sudo session, do it here.
}
sub page_requires_login {
- return $_[0]->request_cache->{page_requires_login};
+ return request_cache->{page_requires_login};
}
sub github_secret {
my ($class) = @_;
- my $cache = $class->request_cache;
+ my $cache = request_cache;
my $cgi = $class->cgi;
$cache->{github_secret} //= $cgi->cookie('github_secret') // generate_random_password(256);
@@ -346,7 +317,7 @@ sub passwdqc {
my ($class) = @_;
require Data::Password::passwdqc;
- my $cache = $class->request_cache;
+ my $cache = request_cache;
my $params = $class->params;
return $cache->{passwdqc} if $cache->{passwdqc};
@@ -395,13 +366,13 @@ sub login {
# Allow templates to know that we're in a page that always requires
# login.
if ($type == LOGIN_REQUIRED) {
- $class->request_cache->{page_requires_login} = 1;
+ request_cache->{page_requires_login} = 1;
}
my $authenticated_user = $authorizer->login($type);
- if (i_am_cgi()) {
- Log::Log4perl::MDC->put(user_id => $authenticated_user->id);
+ if (i_am_cgi() && $authenticated_user->id) {
+ Bugzilla::Logging->fields->{user_id} = $authenticated_user->id;
}
# At this point, we now know if a real person is logged in.
@@ -484,7 +455,7 @@ sub login {
&& !$sudo_target->in_group('bz_sudo_protect'))
{
$class->set_user($sudo_target);
- $class->request_cache->{sudoer} = $authenticated_user;
+ request_cache->{sudoer} = $authenticated_user;
# And make sure that both users have the same Auth object,
# since we never call Auth::login for the sudo target.
$sudo_target->set_authorizer($authenticated_user->authorizer);
@@ -539,24 +510,25 @@ sub logout_user_by_id {
# hack that invalidates credentials for a single request
sub logout_request {
my $class = shift;
- delete $class->request_cache->{user};
- delete $class->request_cache->{sudoer};
+ delete request_cache->{user};
+ delete request_cache->{sudoer};
# We can't delete from $cgi->cookie, so logincookie data will remain
# there. Don't rely on it: use Bugzilla->user->login instead!
}
sub job_queue {
require Bugzilla::JobQueue;
- return $_[0]->request_cache->{job_queue} ||= Bugzilla::JobQueue->new();
+ return request_cache->{job_queue} ||= Bugzilla::JobQueue->new();
}
sub dbh {
+ my ($class) = @_;
# If we're not connected, then we must want the main db
- return $_[0]->request_cache->{dbh} ||= $_[0]->dbh_main;
+ return request_cache->{dbh} ||= $class->dbh_main;
}
sub dbh_main {
- return $_[0]->request_cache->{dbh_main} ||= Bugzilla::DB::connect_main();
+ return request_cache->{dbh_main} ||= Bugzilla::DB::connect_main();
}
sub languages {
@@ -564,25 +536,25 @@ sub languages {
}
sub current_language {
- return $_[0]->request_cache->{current_language} ||= (include_languages())[0];
+ return request_cache->{current_language} ||= (include_languages())[0];
}
sub error_mode {
- my ($class, $newval) = @_;
+ my (undef, $newval) = @_;
if (defined $newval) {
- $class->request_cache->{error_mode} = $newval;
+ request_cache->{error_mode} = $newval;
}
- return $class->request_cache->{error_mode}
+ return request_cache->{error_mode}
|| (i_am_cgi() ? ERROR_MODE_WEBPAGE : ERROR_MODE_DIE);
}
# This is used only by Bugzilla::Error to throw errors.
sub _json_server {
- my ($class, $newval) = @_;
+ my (undef, $newval) = @_;
if (defined $newval) {
- $class->request_cache->{_json_server} = $newval;
+ request_cache->{_json_server} = $newval;
}
- return $class->request_cache->{_json_server};
+ return request_cache->{_json_server};
}
sub usage_mode {
@@ -613,21 +585,21 @@ sub usage_mode {
ThrowCodeError('usage_mode_invalid',
{'invalid_usage_mode', $newval});
}
- $class->request_cache->{usage_mode} = $newval;
+ request_cache->{usage_mode} = $newval;
}
- return $class->request_cache->{usage_mode}
+ return request_cache->{usage_mode}
|| (i_am_cgi()? USAGE_MODE_BROWSER : USAGE_MODE_CMDLINE);
}
sub installation_mode {
- my ($class, $newval) = @_;
- ($class->request_cache->{installation_mode} = $newval) if defined $newval;
- return $class->request_cache->{installation_mode}
+ my (undef, $newval) = @_;
+ (request_cache->{installation_mode} = $newval) if defined $newval;
+ return request_cache->{installation_mode}
|| INSTALLATION_MODE_INTERACTIVE;
}
sub installation_answers {
- my ($class, $filename) = @_;
+ my (undef, $filename) = @_;
if ($filename) {
my $s = new Safe;
$s->rdo($filename);
@@ -636,23 +608,23 @@ sub installation_answers {
die "Error evaluating $filename: $@" if $@;
# Now read the param back out from the sandbox
- $class->request_cache->{installation_answers} = $s->varglob('answer');
+ request_cache->{installation_answers} = $s->varglob('answer');
}
- return $class->request_cache->{installation_answers} || {};
+ return request_cache->{installation_answers} || {};
}
sub switch_to_shadow_db {
my $class = shift;
- if (!$class->request_cache->{dbh_shadow}) {
+ if (!request_cache->{dbh_shadow}) {
if ($class->get_param_with_override('shadowdb')) {
- $class->request_cache->{dbh_shadow} = Bugzilla::DB::connect_shadow();
+ request_cache->{dbh_shadow} = Bugzilla::DB::connect_shadow();
} else {
- $class->request_cache->{dbh_shadow} = $class->dbh_main;
+ request_cache->{dbh_shadow} = $class->dbh_main;
}
}
- $class->request_cache->{dbh} = $class->request_cache->{dbh_shadow};
+ request_cache->{dbh} = request_cache->{dbh_shadow};
# we have to return $class->dbh instead of {dbh} as
# {dbh_shadow} may be undefined if no shadow DB is used
# and no connection to the main DB has been established yet.
@@ -662,7 +634,7 @@ sub switch_to_shadow_db {
sub switch_to_main_db {
my $class = shift;
- $class->request_cache->{dbh} = $class->dbh_main;
+ request_cache->{dbh} = $class->dbh_main;
return $class->dbh_main;
}
@@ -696,7 +668,7 @@ sub log_user_request {
}
eval {
- local $class->request_cache->{dbh};
+ local request_cache->{dbh};
$class->switch_to_main_db();
$class->dbh->do("INSERT INTO user_request_log
(user_id, ip_address, user_agent, request_url,
@@ -708,13 +680,13 @@ sub log_user_request {
sub is_shadow_db {
my $class = shift;
- return $class->request_cache->{dbh} != $class->dbh_main;
+ return request_cache->{dbh} != $class->dbh_main;
}
sub fields {
- my ($class, $criteria) = @_;
+ my (undef, $criteria) = @_;
$criteria ||= {};
- my $cache = $class->request_cache;
+ my $cache = request_cache;
# We create an advanced cache for fields by type, so that we
# can avoid going back to the database for every fields() call.
@@ -761,29 +733,28 @@ sub fields {
}
sub active_custom_fields {
- my ($class, $params) = @_;
+ my (undef, $params) = @_;
my $cache_id = 'active_custom_fields';
if ($params) {
$cache_id .= ($params->{product} ? '_p' . $params->{product}->id : '') .
($params->{component} ? '_c' . $params->{component}->id : '');
$cache_id .= ':noext' if $params->{skip_extensions};
}
- if (!exists $class->request_cache->{$cache_id}) {
+ if (!exists request_cache->{$cache_id}) {
my $fields = Bugzilla::Field->match({ custom => 1, obsolete => 0, skip_extensions => 1 });
Bugzilla::Hook::process('active_custom_fields',
{ fields => \$fields, params => $params });
- $class->request_cache->{$cache_id} = $fields;
+ request_cache->{$cache_id} = $fields;
}
- return @{$class->request_cache->{$cache_id}};
+ return @{request_cache->{$cache_id}};
}
sub has_flags {
- my $class = shift;
- if (!defined $class->request_cache->{has_flags}) {
- $class->request_cache->{has_flags} = Bugzilla::Flag->any_exist;
+ if (!defined request_cache->{has_flags}) {
+ request_cache->{has_flags} = Bugzilla::Flag->any_exist;
}
- return $class->request_cache->{has_flags};
+ return request_cache->{has_flags};
}
sub local_timezone {
@@ -793,19 +764,13 @@ sub local_timezone {
# Send messages to syslog for the auditing systems (eg. mozdef) to pick up.
sub audit {
- my ($class, $message) = @_;
+ my (undef, $message) = @_;
state $logger = Log::Log4perl->get_logger("audit");
$logger->notice(encode_utf8($message));
}
-# This creates the request cache for non-mod_perl installations.
-# This is identical to Install::Util::_cache so that things loaded
-# into Install::Util::_cache during installation can be read out
-# of request_cache later in installation.
-use constant request_cache => Bugzilla::Install::Util::_cache();
-
sub clear_request_cache {
- my ($class, %option) = @_;
+ my (undef, %option) = @_;
my $request_cache = request_cache();
my @except = $option{except} ? @{ $option{except} } : ();
@@ -821,37 +786,10 @@ sub process_cache {
return $_process_cache;
}
-# BMO - Instrumentation
-
-sub metrics_enabled {
- if (defined $_[1]) {
- if (!$_[1]
- && $_[0]->request_cache->{metrics_enabled}
- && $_[0]->request_cache->{metrics})
- {
- $_[0]->request_cache->{metrics}->cancel();
- delete $_[0]->request_cache->{metrics};
- }
- $_[0]->request_cache->{metrics_enabled} = $_[1];
- }
- else {
- return $_[0]->request_cache->{metrics_enabled};
- }
-}
-
-sub metrics {
- return $_[0]->request_cache->{metrics} ||= Bugzilla::Metrics::Collector->new($_[1]);
-}
-
# This is a memcached wrapper, which provides cross-process and cross-system
# caching.
sub memcached {
- # BMO - use metrics subclass if required
- if (Bugzilla->metrics_enabled) {
- return $_[0]->request_cache->{memcached} ||= Bugzilla::Metrics::Memcached->_new();
- } else {
- return $_[0]->request_cache->{memcached} ||= Bugzilla::Memcached->_new();
- }
+ return request_cache->{memcached} ||= Bugzilla::Memcached->_new();
}
sub elastic {
@@ -877,20 +815,25 @@ sub check_rate_limit {
}
my $limit = join("/", @$limit);
Bugzilla->audit("[rate_limit] action=$action, ip=$ip, limit=$limit, name=$name");
- ThrowUserError("rate_limit") if $action eq 'block';
+ if ($action eq 'block') {
+ Bugzilla::ModPerl::BlockIP->block_ip($ip);
+ ThrowUserError("rate_limit");
+ }
}
}
}
+sub markdown_parser {
+ return request_cache->{markdown_parser}
+ ||= Bugzilla::Markdown::GFM::Parser->new( {extensions => [qw( autolink tagfilter table strikethrough)] } );
+}
+
# Private methods
# Per-process cleanup. Note that this is a plain subroutine, not a method,
# so we don't have $class available.
sub _cleanup {
- # BMO - finalise and report on metrics
- if (Bugzilla->metrics_enabled) {
- Bugzilla->metrics->finish();
- }
+ return if $^C;
# BMO - allow "end of request" processing
Bugzilla::Hook::process('request_cleanup');
@@ -901,7 +844,6 @@ sub _cleanup {
foreach my $dbh ($main, $shadow) {
next if !$dbh;
$dbh->bz_rollback_transaction() if $dbh->bz_in_transaction;
- $dbh->disconnect;
}
clear_request_cache();
@@ -1205,6 +1147,11 @@ of features, see C<OPTIONAL_MODULES> in C<Bugzilla::Install::Requirements>.
Feeds the provided message into our centralised auditing system.
+=item C<markdown_parser>
+
+Returns a L<Bugzilla::Markdown::GFM::Parser> with the default extensions
+loaded (autolink, tagfilter, table, and strikethrough).
+
=back
=head1 B<CACHING>