Commit de18a0d1 authored by Per Cederqvist's avatar Per Cederqvist

Imported Bugzilla 4.3.2.

parent 757c98d3
No preview for this file type
......@@ -445,8 +445,14 @@ sub error_mode {
if (defined $newval) {
$class->request_cache->{error_mode} = $newval;
}
return $class->request_cache->{error_mode}
|| (i_am_cgi() ? ERROR_MODE_WEBPAGE : ERROR_MODE_DIE);
# XXX - Once we require Perl 5.10.1, this test can be replaced by //.
if (exists $class->request_cache->{error_mode}) {
return $class->request_cache->{error_mode};
}
else {
return (i_am_cgi() ? ERROR_MODE_WEBPAGE : ERROR_MODE_DIE);
}
}
# This is used only by Bugzilla::Error to throw errors.
......@@ -485,8 +491,14 @@ sub usage_mode {
}
$class->request_cache->{usage_mode} = $newval;
}
return $class->request_cache->{usage_mode}
|| (i_am_cgi()? USAGE_MODE_BROWSER : USAGE_MODE_CMDLINE);
# XXX - Once we require Perl 5.10.1, this test can be replaced by //.
if (exists $class->request_cache->{usage_mode}) {
return $class->request_cache->{usage_mode};
}
else {
return (i_am_cgi()? USAGE_MODE_BROWSER : USAGE_MODE_CMDLINE);
}
}
sub installation_mode {
......
......@@ -513,6 +513,52 @@ sub _check_content_type {
}
trick_taint($content_type);
# $ENV{HOME} must be defined when using File::MimeInfo::Magic,
# see https://rt.cpan.org/Public/Bug/Display.html?id=41744.
local $ENV{HOME} = $ENV{HOME} || File::Spec->rootdir();
# If we have autodetected application/octet-stream from the Content-Type
# header, let's have a better go using a sniffer if available.
if (defined Bugzilla->input_params->{contenttypemethod}
&& Bugzilla->input_params->{contenttypemethod} eq 'autodetect'
&& $content_type eq 'application/octet-stream'
&& Bugzilla->feature('typesniffer'))
{
import File::MimeInfo::Magic qw(mimetype);
require IO::Scalar;
# data is either a filehandle, or the data itself.
my $fh = $params->{data};
if (!ref($fh)) {
$fh = new IO::Scalar \$fh;
}
elsif (!$fh->isa('IO::Handle')) {
# CGI.pm sends us an Fh that isn't actually an IO::Handle, but
# has a method for getting an actual handle out of it.
$fh = $fh->handle;
# ->handle returns an literal IO::Handle, even though the
# underlying object is a file. So we rebless it to be a proper
# IO::File object so that we can call ->seek on it and so on.
# Just in case CGI.pm fixes this some day, we check ->isa first.
if (!$fh->isa('IO::File')) {
bless $fh, 'IO::File';
}
}
my $mimetype = mimetype($fh);
$content_type = $mimetype if $mimetype;
}
# Make sure patches are viewable in the browser
if (!ref($invocant)
&& defined Bugzilla->input_params->{contenttypemethod}
&& Bugzilla->input_params->{contenttypemethod} eq 'autodetect'
&& $content_type =~ m{text/x-(?:diff|patch)})
{
$params->{ispatch} = 1;
$content_type = 'text/plain';
}
return $content_type;
}
......@@ -926,13 +972,6 @@ sub get_content_type {
$cgi->uploadInfo($cgi->param('data'))->{'Content-Type'};
$content_type || ThrowUserError("missing_content_type");
# Set the ispatch flag to 1 if the content type
# is text/x-diff or text/x-patch
if ($content_type =~ m{text/x-(?:diff|patch)}) {
$cgi->param('ispatch', 1);
$content_type = 'text/plain';
}
# Internet Explorer sends image/x-png for PNG images,
# so convert that to image/png to match other browsers.
if ($content_type eq 'image/x-png') {
......
......@@ -27,7 +27,6 @@ sub process_diff {
$last_reader->sends_data_to(new PatchReader::DiffPrinter::raw());
# Actually print out the patch.
print $cgi->header(-type => 'text/plain',
-x_content_type_options => "nosniff",
-expires => '+3M');
disable_utf8();
$reader->iterate_string('Attachment ' . $attachment->id, $attachment->data);
......@@ -109,7 +108,6 @@ sub process_interdiff {
$last_reader->sends_data_to(new PatchReader::DiffPrinter::raw());
# Actually print out the patch.
print $cgi->header(-type => 'text/plain',
-x_content_type_options => "nosniff",
-expires => '+3M');
disable_utf8();
}
......@@ -200,7 +198,9 @@ sub warn_if_interdiff_might_fail {
# Verify that the revisions in the files are the same.
foreach my $file (keys %{$old_file_list}) {
if ($old_file_list->{$file}{old_revision} ne
if (exists $old_file_list->{$file}{old_revision}
&& exists $new_file_list->{$file}{old_revision}
&& $old_file_list->{$file}{old_revision} ne
$new_file_list->{$file}{old_revision})
{
return 'interdiff2';
......
......@@ -22,6 +22,7 @@ use Bugzilla::User::Setting ();
use Bugzilla::Auth::Login::Stack;
use Bugzilla::Auth::Verify::Stack;
use Bugzilla::Auth::Persist::Cookie;
use Socket;
sub new {
my ($class, $params) = @_;
......@@ -199,10 +200,18 @@ sub _handle_login_result {
my $default_settings = Bugzilla::User::Setting::get_defaults();
my $template = Bugzilla->template_inner(
$default_settings->{lang}->{default_value});
my $address = $attempts->[0]->{ip_addr};
# Note: inet_aton will only resolve IPv4 addresses.
# For IPv6 we'll need to use inet_pton which requires Perl 5.12.
my $n = inet_aton($address);
if ($n) {
$address = gethostbyaddr($n, AF_INET) . " ($address)"
}
my $vars = {
locked_user => $user,
attempts => $attempts,
unlock_at => $unlock_at,
address => $address,
};
my $message;
$template->process('email/lockout.txt.tmpl', $vars, \$message)
......
......@@ -1236,6 +1236,7 @@ sub _check_assigned_to {
sub _check_bug_file_loc {
my ($invocant, $url) = @_;
$url = '' if !defined($url);
$url = trim($url);
# On bug entry, if bug_file_loc is "http://", the default, use an
# empty value instead. However, on bug editing people can set that
# back if they *really* want to.
......@@ -1920,6 +1921,12 @@ sub _check_field_is_mandatory {
return if !$field->is_visible_on_bug($params || $invocant);
return if ($field->type == FIELD_TYPE_SINGLE_SELECT
&& scalar @{ get_legal_field_values($field->name) } == 1);
return if ($field->type == FIELD_TYPE_MULTI_SELECT
&& !scalar @{ get_legal_field_values($field->name) });
if (ref($value) eq 'ARRAY') {
$value = join('', @$value);
}
......@@ -3608,23 +3615,23 @@ sub user {
return {} if $self->{'error'};
my $user = Bugzilla->user;
my $prod_id = $self->{'product_id'};
my $unknown_privileges = $user->in_group('editbugs', $prod_id);
my $canedit = $unknown_privileges
|| $user->id == $self->{'assigned_to'}
|| (Bugzilla->params->{'useqacontact'}
&& $self->{'qa_contact'}
&& $user->id == $self->{'qa_contact'});
my $canconfirm = $unknown_privileges
|| $user->in_group('canconfirm', $prod_id);
my $isreporter = $user->id
&& $user->id == $self->{reporter_id};
my $editbugs = $user->in_group('editbugs', $prod_id);
my $is_reporter = $user->id == $self->{reporter_id} ? 1 : 0;
my $is_assignee = $user->id == $self->{'assigned_to'} ? 1 : 0;
my $is_qa_contact = Bugzilla->params->{'useqacontact'}
&& $self->{'qa_contact'}
&& $user->id == $self->{'qa_contact'} ? 1 : 0;
my $canedit = $editbugs || $is_assignee || $is_qa_contact;
my $canconfirm = $editbugs || $user->in_group('canconfirm', $prod_id);
my $has_any_role = $is_reporter || $is_assignee || $is_qa_contact;
$self->{'user'} = {canconfirm => $canconfirm,
canedit => $canedit,
isreporter => $isreporter};
isreporter => $is_reporter,
has_any_role => $has_any_role};
return $self->{'user'};
}
......
......@@ -133,8 +133,7 @@ sub class_for {
if $subclass->should_handle($uri);
}
ThrowUserError('bug_url_invalid', { url => $value,
reason => 'show_bug' });
ThrowUserError('bug_url_invalid', { url => $value });
}
sub _check_class {
......
......@@ -9,16 +9,20 @@ package Bugzilla::BugUrl::Debian;
use strict;
use base qw(Bugzilla::BugUrl);
use Bugzilla::Error;
use Bugzilla::Util;
###############################
#### Methods ####
###############################
sub should_handle {
my ($class, $uri) = @_;
return ($uri->authority =~ /^bugs.debian.org$/i) ? 1 : 0;
# Debian BTS URLs can look like various things:
# http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1234
# http://bugs.debian.org/1234
return ($uri->authority =~ /^bugs.debian.org$/i
and (($uri->path =~ /bugreport\.cgi$/
and $uri->query_param('bug') =~ m|^\d+$|)
or $uri->path =~ m|^/\d+$|)) ? 1 : 0;
}
sub _check_value {
......@@ -26,24 +30,12 @@ sub _check_value {
my $uri = $class->SUPER::_check_value(@_);
# Debian BTS URLs can look like various things:
# http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1234
# http://bugs.debian.org/1234
my $bug_id;
if ($uri->path =~ m|^/(\d+)$|) {
$bug_id = $1;
}
elsif ($uri->path =~ /bugreport\.cgi$/) {
$bug_id = $uri->query_param('bug');
detaint_natural($bug_id);
}
if (!$bug_id) {
ThrowUserError('bug_url_invalid',
{ url => $uri->path, reason => 'id' });
}
# This is the shortest standard URL form for Debian BTS URLs,
# and so we reduce all URLs to this.
return new URI("http://bugs.debian.org/" . $bug_id);
$uri->path =~ m|^/(\d+)$| || $uri->query_param('bug') =~ m|^(\d+)$|;
$uri = new URI("http://bugs.debian.org/$1");
return $uri;
}
1;
......@@ -9,16 +9,18 @@ package Bugzilla::BugUrl::Google;
use strict;
use base qw(Bugzilla::BugUrl);
use Bugzilla::Error;
use Bugzilla::Util;
###############################
#### Methods ####
###############################
sub should_handle {
my ($class, $uri) = @_;
return ($uri->authority =~ /^code.google.com$/i) ? 1 : 0;
# Google Code URLs only have one form:
# http(s)://code.google.com/p/PROJECT_NAME/issues/detail?id=1234
return ($uri->authority =~ /^code.google.com$/i
and $uri->path =~ m|^/p/[^/]+/issues/detail$|
and $uri->query_param('id') =~ /^\d+$/) ? 1 : 0;
}
sub _check_value {
......@@ -26,26 +28,13 @@ sub _check_value {
$uri = $class->SUPER::_check_value($uri);
my $value = $uri->as_string;
# Google Code URLs only have one form:
# http(s)://code.google.com/p/PROJECT_NAME/issues/detail?id=1234
my $project_name;
if ($uri->path =~ m|^/p/([^/]+)/issues/detail$|) {
$project_name = $1;
} else {
ThrowUserError('bug_url_invalid', { url => $value });
}
my $bug_id = $uri->query_param('id');
detaint_natural($bug_id);
if (!$bug_id) {
ThrowUserError('bug_url_invalid', { url => $value, reason => 'id' });
}
# While Google Code URLs can be either HTTP or HTTPS,
# always go with the HTTP scheme, as that's the default.
$value = "http://code.google.com/p/" . $project_name .
"/issues/detail?id=" . $bug_id;
if ($uri->scheme eq 'https') {
$uri->scheme('http');
}
return new URI($value);
return $uri;
}
1;
......@@ -9,15 +9,16 @@ package Bugzilla::BugUrl::JIRA;
use strict;
use base qw(Bugzilla::BugUrl);
use Bugzilla::Error;
use Bugzilla::Util;
###############################
#### Methods ####
###############################
sub should_handle {
my ($class, $uri) = @_;
# JIRA URLs have only one basic form (but the jira is optional):
# https://issues.apache.org/jira/browse/KEY-1234
# http://issues.example.com/browse/KEY-1234
return ($uri->path =~ m|/browse/[A-Z][A-Z]+-\d+$|) ? 1 : 0;
}
......@@ -26,10 +27,6 @@ sub _check_value {
my $uri = $class->SUPER::_check_value(@_);
# JIRA URLs have only one basic form (but the jira is optional):
# https://issues.apache.org/jira/browse/KEY-1234
# http://issues.example.com/browse/KEY-1234
# Make sure there are no query parameters.
$uri->query(undef);
# And remove any # part if there is one.
......
......@@ -9,15 +9,19 @@ package Bugzilla::BugUrl::Launchpad;
use strict;
use base qw(Bugzilla::BugUrl);
use Bugzilla::Error;
###############################
#### Methods ####
###############################
sub should_handle {
my ($class, $uri) = @_;
return ($uri->authority =~ /launchpad.net$/) ? 1 : 0;
# Launchpad bug URLs can look like various things:
# https://bugs.launchpad.net/ubuntu/+bug/1234
# https://launchpad.net/bugs/1234
# All variations end with either "/bugs/1234" or "/+bug/1234"
return ($uri->authority =~ /launchpad.net$/
and $uri->path =~ m|bugs?/\d+$|) ? 1 : 0;
}
sub _check_value {
......@@ -25,21 +29,12 @@ sub _check_value {
$uri = $class->SUPER::_check_value($uri);
my $value = $uri->as_string;
# Launchpad bug URLs can look like various things:
# https://bugs.launchpad.net/ubuntu/+bug/1234
# https://launchpad.net/bugs/1234
# All variations end with either "/bugs/1234" or "/+bug/1234"
if ($uri->path =~ m|bugs?/(\d+)$|) {
# This is the shortest standard URL form for Launchpad bugs,
# and so we reduce all URLs to this.
$value = "https://launchpad.net/bugs/$1";
}
else {
ThrowUserError('bug_url_invalid', { url => $value, reason => 'id' });
}
return new URI($value);
# This is the shortest standard URL form for Launchpad bugs,
# and so we reduce all URLs to this.
$uri->path =~ m|bugs?/(\d+)$|;
$uri = new URI("https://launchpad.net/bugs/$1");
return $uri;
}
1;
......@@ -9,15 +9,15 @@ package Bugzilla::BugUrl::MantisBT;
use strict;
use base qw(Bugzilla::BugUrl);
use Bugzilla::Error;
use Bugzilla::Util;
###############################
#### Methods ####
###############################
sub should_handle {
my ($class, $uri) = @_;
# MantisBT URLs look like the following ('bugs' directory is optional):
# http://www.mantisbt.org/bugs/view.php?id=1234
return ($uri->path_query =~ m|view\.php\?id=\d+$|) ? 1 : 0;
}
......@@ -26,9 +26,6 @@ sub _check_value {
my $uri = $class->SUPER::_check_value(@_);
# MantisBT URLs look like the following ('bugs' directory is optional):
# http://www.mantisbt.org/bugs/view.php?id=1234
# Remove any # part if there is one.
$uri->fragment(undef);
......
......@@ -9,17 +9,21 @@ package Bugzilla::BugUrl::SourceForge;
use strict;
use base qw(Bugzilla::BugUrl);
use Bugzilla::Error;
use Bugzilla::Util;
###############################
#### Methods ####
###############################
sub should_handle {
my ($class, $uri) = @_;
# SourceForge tracker URLs have only one form:
# http://sourceforge.net/tracker/?func=detail&aid=111&group_id=111&atid=111
return ($uri->authority =~ /^sourceforge.net$/i
and $uri->path =~ m|/tracker/|) ? 1 : 0;
and $uri->path =~ m|/tracker/|
and $uri->query_param('func') eq 'detail'
and $uri->query_param('aid')
and $uri->query_param('group_id')
and $uri->query_param('atid')) ? 1 : 0;
}
sub _check_value {
......@@ -27,19 +31,10 @@ sub _check_value {
my $uri = $class->SUPER::_check_value(@_);
# SourceForge tracker URLs have only one form:
# http://sourceforge.net/tracker/?func=detail&aid=111&group_id=111&atid=111
if ($uri->query_param('func') eq 'detail' and $uri->query_param('aid')
and $uri->query_param('group_id') and $uri->query_param('atid'))
{
# Remove any # part if there is one.
$uri->fragment(undef);
return $uri;
}
else {
my $value = $uri->as_string;
ThrowUserError('bug_url_invalid', { url => $value });
}
# Remove any # part if there is one.
$uri->fragment(undef);
return $uri;
}
1;
......@@ -9,15 +9,16 @@ package Bugzilla::BugUrl::Trac;
use strict;
use base qw(Bugzilla::BugUrl);
use Bugzilla::Error;
use Bugzilla::Util;
###############################
#### Methods ####
###############################
sub should_handle {
my ($class, $uri) = @_;
# Trac URLs can look like various things:
# http://dev.mutt.org/trac/ticket/1234
# http://trac.roundcube.net/ticket/1484130
return ($uri->path =~ m|/ticket/\d+$|) ? 1 : 0;
}
......@@ -26,10 +27,6 @@ sub _check_value {
my $uri = $class->SUPER::_check_value(@_);
# Trac URLs can look like various things:
# http://dev.mutt.org/trac/ticket/1234
# http://trac.roundcube.net/ticket/1484130
# Make sure there are no query parameters.
$uri->query(undef);
# And remove any # part if there is one.
......
......@@ -57,6 +57,11 @@ sub new {
# Make sure our outgoing cookie list is empty on each invocation
$self->{Bugzilla_cookie_list} = [];
# Path-Info is of no use for Bugzilla and interacts badly with IIS.
# Moreover, it causes unexpected behaviors, such as totally breaking
# the rendering of pages. Skip it!
print $self->redirect($self->url(-path => 0, -query => 1)) if $self->path_info;
# Send appropriate charset
$self->charset(Bugzilla->params->{'utf8'} ? 'UTF-8' : '');
......@@ -221,35 +226,6 @@ sub check_etag {
}
}
# Overwrite to ensure nph doesn't get set, and unset HEADERS_ONCE
sub multipart_init {
my $self = shift;
# Keys are case-insensitive, map to lowercase
my %args = @_;
my %param;
foreach my $key (keys %args) {
$param{lc $key} = $args{$key};
}
# Set the MIME boundary and content-type
my $boundary = $param{'-boundary'}
|| '------- =_' . generate_random_password(16);
delete $param{'-boundary'};
$self->{'separator'} = "\r\n--$boundary\r\n";
$self->{'final_separator'} = "\r\n--$boundary--\r\n";