summaryrefslogtreecommitdiffstats
path: root/Bugzilla/WebService
diff options
context:
space:
mode:
authorDylan William Hardison <dylan@hardison.net>2018-10-09 23:06:18 +0200
committerGitHub <noreply@github.com>2018-10-09 23:06:18 +0200
commit37d767c50d5ae69b13c47b71ba16b93c6b450730 (patch)
tree8d91a217f7350b68ea391b345b1a1a362a2ad2d6 /Bugzilla/WebService
parent34fd0c3db18f7f5da558d8a8294e7fea61224186 (diff)
downloadbugzilla-37d767c50d5ae69b13c47b71ba16b93c6b450730.tar.gz
bugzilla-37d767c50d5ae69b13c47b71ba16b93c6b450730.tar.xz
Bug 1497343 - Add some rudimentary type checking to Bugzilla::WebServe::Util::validate()
Diffstat (limited to 'Bugzilla/WebService')
-rw-r--r--Bugzilla/WebService/Bug.pm3
-rw-r--r--Bugzilla/WebService/Util.pm24
2 files changed, 20 insertions, 7 deletions
diff --git a/Bugzilla/WebService/Bug.pm b/Bugzilla/WebService/Bug.pm
index 9003f3480..61a95e07d 100644
--- a/Bugzilla/WebService/Bug.pm
+++ b/Bugzilla/WebService/Bug.pm
@@ -1462,7 +1462,8 @@ sub _bug_to_hash {
elsif ($field->type == FIELD_TYPE_DATETIME
|| $field->type == FIELD_TYPE_DATE)
{
- $item{$name} = $self->type('dateTime', $bug->$name);
+ my $value = $bug->$name;
+ $item{$name} = defined($value) ? $self->type('dateTime', $value) : undef;
}
elsif ($field->type == FIELD_TYPE_MULTI_SELECT) {
my @values = map { $self->type('string', $_) } @{ $bug->$name };
diff --git a/Bugzilla/WebService/Util.pm b/Bugzilla/WebService/Util.pm
index d462c884a..ce5586911 100644
--- a/Bugzilla/WebService/Util.pm
+++ b/Bugzilla/WebService/Util.pm
@@ -11,6 +11,7 @@ use 5.10.1;
use strict;
use warnings;
+use Bugzilla::Logging;
use Bugzilla::Flag;
use Bugzilla::FlagType;
use Bugzilla::Error;
@@ -18,6 +19,8 @@ use Bugzilla::WebService::Constants;
use Storable qw(dclone);
use URI::Escape qw(uri_unescape);
+use Type::Params qw( compile );
+use Types::Standard -all;
use base qw(Exporter);
@@ -217,6 +220,17 @@ sub _delete_bad_keys {
sub validate {
my ($self, $params, @keys) = @_;
+ my $cache_key = join('|', (caller(1))[3], sort @keys);
+ # Type->of() is the same as Type[], used here because it is easier
+ # to chain with plus_coercions.
+ state $array_of_nonrefs = ArrayRef->of(Maybe[Value])->plus_coercions(
+ Maybe[Value], q{ [ $_ ] },
+ );
+ state $type_cache = {};
+ my $params_type = $type_cache->{$cache_key} //= do {
+ my %fields = map { $_ => Optional[$array_of_nonrefs] } @keys;
+ Maybe[ Dict[%fields, slurpy Any] ];
+ };
# If $params is defined but not a reference, then we weren't
# sent any parameters at all, and we're getting @keys where
@@ -226,12 +240,10 @@ sub validate {
# If @keys is not empty then we convert any named
# parameters that have scalar values to arrayrefs
# that match.
- foreach my $key (@keys) {
- if (exists $params->{$key}) {
- $params->{$key} = ref $params->{$key}
- ? $params->{$key}
- : [ $params->{$key} ];
- }
+ $params = $params_type->coerce($params);
+ if (my $type_error = $params_type->validate($params)) {
+ FATAL("validate() found type error: $type_error");
+ ThrowUserError('invalid_params', { type_error => $type_error } ) if $type_error;
}
return ($self, $params);