diff options
author | mkanat%bugzilla.org <> | 2009-01-09 08:44:05 +0100 |
---|---|---|
committer | mkanat%bugzilla.org <> | 2009-01-09 08:44:05 +0100 |
commit | 9b0a78fbcc3a3c5763e216da6dda8420379701a9 (patch) | |
tree | dd2af36481bf78282a78e307b17dbe435621de1c | |
parent | 6c6de869047f9febda54cfb8121b636d35f9dc97 (diff) | |
download | bugzilla-9b0a78fbcc3a3c5763e216da6dda8420379701a9.tar.gz bugzilla-9b0a78fbcc3a3c5763e216da6dda8420379701a9.tar.xz |
Bug 471942: Make the WebService validate and properly convert input parameters
Patch By Max Kanat-Alexander <mkanat@bugzilla.org> r=dkl, a=mkanat
-rwxr-xr-x | Bugzilla/WebService.pm | 86 | ||||
-rwxr-xr-x | Bugzilla/WebService/Constants.pm | 3 | ||||
-rw-r--r-- | template/en/default/global/user-error.html.tmpl | 5 |
3 files changed, 93 insertions, 1 deletions
diff --git a/Bugzilla/WebService.pm b/Bugzilla/WebService.pm index 615abf68c..3152ef04f 100755 --- a/Bugzilla/WebService.pm +++ b/Bugzilla/WebService.pm @@ -97,6 +97,7 @@ sub initialize { my $self = shift; my %retval = $self->SUPER::initialize(@_); $retval{'serializer'} = Bugzilla::WebService::XMLRPC::Serializer->new; + $retval{'deserializer'} = Bugzilla::WebService::XMLRPC::Deserializer->new; return %retval; } @@ -114,6 +115,74 @@ sub make_response { 1; +# This exists to validate input parameters (which XMLRPC::Lite doesn't do) +# and also, in some cases, to more-usefully decode them. +package Bugzilla::WebService::XMLRPC::Deserializer; +use strict; +# We can't use "use base" because XMLRPC::Serializer doesn't return +# a true value. +eval { require XMLRPC::Lite; }; +our @ISA = qw(XMLRPC::Deserializer); + +use Bugzilla::Error; + +# Some method arguments need to be converted in some way, when they are input. +sub decode_value { + my $self = shift; + my ($type) = @{ $_[0] }; + my $value = $self->SUPER::decode_value(@_); + + # We only validate/convert certain types here. + return $value if $type !~ /^(?:int|i4|boolean|double|dateTime\.iso8601)$/; + + # Though the XML-RPC standard doesn't allow an empty <int>, + # <double>,or <dateTime.iso8601>, we do, and we just say + # "that's undef". + if (grep($type eq $_, qw(int double dateTime))) { + return undef if $value eq ''; + } + + my $validator = $self->_validation_subs->{$type}; + if (!$validator->($value)) { + ThrowUserError('xmlrpc_invalid_value', + { type => $type, value => $value }); + } + + # We convert dateTimes to a DB-friendly date format. + if ($type eq 'dateTime.iso8601') { + # We leave off the $ from the end of this regex to allow for possible + # extensions to the XML-RPC date standard. + $value =~ /^(\d{4})(\d{2})(\d{2})T(\d{2}):(\d{2}):(\d{2})/; + $value = "$1-$2-$3 $4:$5:$6"; + } + + return $value; +} + +sub _validation_subs { + my $self = shift; + return $self->{_validation_subs} if $self->{_validation_subs}; + # The only place that XMLRPC::Lite stores any sort of validation + # regex is in XMLRPC::Serializer. We want to re-use those regexes here. + my $lookup = Bugzilla::WebService::XMLRPC::Serializer->new->typelookup; + + # $lookup is a hash whose values are arrayrefs, and whose keys are the + # names of types. The second item of each arrayref is a subroutine + # that will do our validation for us. + my %validators = map { $_ => $lookup->{$_}->[1] } (keys %$lookup); + # Add a boolean validator + $validators{'boolean'} = sub {$_[0] =~ /^[01]$/}; + # Some types have multiple names, or have a different name in + # XMLRPC::Serializer than their standard XML-RPC name. + $validators{'dateTime.iso8601'} = $validators{'dateTime'}; + $validators{'i4'} = $validators{'int'}; + + $self->{_validation_subs} = \%validators; + return \%validators; +} + +1; + # This package exists to fix a UTF-8 bug in SOAP::Lite. # See http://rt.cpan.org/Public/Bug/Display.html?id=32952. package Bugzilla::WebService::XMLRPC::Serializer; @@ -356,3 +425,20 @@ would return something like: =back + +=head1 EXTENSIONS TO THE XML-RPC STANDARD + +=head2 Undefined Values + +Normally, XML-RPC does not allow empty values for C<int>, C<double>, or +C<dateTime.iso8601> fields. Bugzilla does--it treats empty values as +C<undef> (called C<NULL> or C<None> in some programming languages). + +Bugzilla also accepts a type called C<< <nil> >>, which is always considered +to be C<undef>, no matter what it contains. + +=begin private + +nil is implemented by XMLRPC::Lite, in XMLRPC::Deserializer::decode_value. + +=end private diff --git a/Bugzilla/WebService/Constants.pm b/Bugzilla/WebService/Constants.pm index 07b51e5f1..4f98cd11a 100755 --- a/Bugzilla/WebService/Constants.pm +++ b/Bugzilla/WebService/Constants.pm @@ -48,11 +48,12 @@ use base qw(Exporter); # comment that it was retired. Also, if an error changes its name, you'll # have to fix it here. use constant WS_ERROR_CODE => { - # Generic Bugzilla::Object errors are 50-99. + # Generic errors (Bugzilla::Object and others) are 50-99. object_not_specified => 50, param_required => 50, params_required => 50, object_does_not_exist => 51, + xmlrpc_invalid_value => 52, # Bug errors usually occupy the 100-200 range. improper_bug_id_field_value => 100, bug_id_does_not_exist => 101, diff --git a/template/en/default/global/user-error.html.tmpl b/template/en/default/global/user-error.html.tmpl index d92b04622..39077c542 100644 --- a/template/en/default/global/user-error.html.tmpl +++ b/template/en/default/global/user-error.html.tmpl @@ -1618,6 +1618,11 @@ [% title = "Wrong Token" %] That token cannot be used to create a user account. + [% ELSIF error == "xmlrpc_invalid_value" %] + "[% value FILTER html %]" is not a valid value for a + <[% type FILTER html %]> field. (See the XML-RPC specification + for details.) + [% ELSIF error == "zero_length_file" %] [% title = "File Is Empty" %] The file you are trying to attach is empty, does not exist, or you don't |