line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package HTTP::Validate; |
2
|
|
|
|
|
|
|
|
3
|
7
|
|
|
7
|
|
101174
|
use strict; |
|
7
|
|
|
|
|
9
|
|
|
7
|
|
|
|
|
179
|
|
4
|
7
|
|
|
7
|
|
21
|
use warnings; |
|
7
|
|
|
|
|
8
|
|
|
7
|
|
|
|
|
159
|
|
5
|
|
|
|
|
|
|
|
6
|
7
|
|
|
7
|
|
20
|
use Exporter qw( import ); |
|
7
|
|
|
|
|
9
|
|
|
7
|
|
|
|
|
208
|
|
7
|
7
|
|
|
7
|
|
22
|
use Carp qw( carp croak ); |
|
7
|
|
|
|
|
7
|
|
|
7
|
|
|
|
|
379
|
|
8
|
7
|
|
|
7
|
|
23
|
use Scalar::Util qw( reftype weaken looks_like_number ); |
|
7
|
|
|
|
|
7
|
|
|
7
|
|
|
|
|
1735
|
|
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
# Check for the existence of the 'fc' function. If it exists, we can use it |
11
|
|
|
|
|
|
|
# for casefolding enum values. Otherwise, we default to 'lc'. |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
my $case_fold = $] >= 5.016 ? eval 'sub { return CORE::fc $_[0] }' |
14
|
|
|
|
|
|
|
: $INC{'Unicode/CaseFold.pm'} ? eval 'sub { return Unicode:CaseFold::fc $_[0] }' |
15
|
|
|
|
|
|
|
: eval 'sub { return lc $_[0] }'; |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
our $VERSION = '0.98'; |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
=head1 NAME |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
HTTP::Validate - validate and clean HTTP parameter values according to a set of rules |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
Version 0.98 |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
=head1 DESCRIPTION |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
This module provides validation of HTTP request parameters against a set of |
28
|
|
|
|
|
|
|
clearly defined rules. It is designed to work with L, L, |
29
|
|
|
|
|
|
|
L, and similar web application frameworks, both for interactive apps |
30
|
|
|
|
|
|
|
and for data services. It can also be used with L, although the use of |
31
|
|
|
|
|
|
|
L or another similar solution is recommended to avoid paying the |
32
|
|
|
|
|
|
|
penalty of loading this module and initializing all of the rulesets over again |
33
|
|
|
|
|
|
|
for each request. Both an object-oriented interface and a procedural |
34
|
|
|
|
|
|
|
interface are provided. |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
The rule definition mechanism is very flexible. A ruleset can be defined once |
37
|
|
|
|
|
|
|
and used with multiple URL paths, and rulesets can be combined using the rule |
38
|
|
|
|
|
|
|
types C and C. This allows a complex application that accepts |
39
|
|
|
|
|
|
|
many different paths to apply common rule patterns. If the parameters fail |
40
|
|
|
|
|
|
|
the validation test, an error message is provided which tells the client how |
41
|
|
|
|
|
|
|
to amend the request in order to make it valid. A suite of built-in validator |
42
|
|
|
|
|
|
|
functions is available, and you can also define your own. |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
This module also provides a mechanism for generating documentation about the |
45
|
|
|
|
|
|
|
parameter rules. The documentation is generated in Pod format, which can |
46
|
|
|
|
|
|
|
then be converted to HTML, TeX, nroff, etc. as needed. |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
=head1 SYNOPSIS |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
package MyWebApp; |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
use HTTP::Validate qw{:keywords :validators}; |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
define_ruleset( 'filters' => |
55
|
|
|
|
|
|
|
{ param => 'lat', valid => DECI_VALUE('-90.0','90.0') }, |
56
|
|
|
|
|
|
|
"Return all datasets associated with the given latitude.", |
57
|
|
|
|
|
|
|
{ param => 'lng', valid => DECI_VALUE('-180.0','180.0') }, |
58
|
|
|
|
|
|
|
"Return all datasets associated with the given longitude.", |
59
|
|
|
|
|
|
|
{ together => ['lat', 'lng'], errmsg => "you must specify 'lng' and 'lat' together" }, |
60
|
|
|
|
|
|
|
"If either 'lat' or 'lng' is given, the other must be as well.", |
61
|
|
|
|
|
|
|
{ param => 'id', valid => POS_VALUE }, |
62
|
|
|
|
|
|
|
"Return the dataset with the given identifier", |
63
|
|
|
|
|
|
|
{ param => 'name', valid => STR_VALUE }, |
64
|
|
|
|
|
|
|
"Return all datasets with the given name"); |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
define_ruleset( 'display' => |
67
|
|
|
|
|
|
|
{ optional => 'full', valid => FLAG_VALUE }, |
68
|
|
|
|
|
|
|
"If specified, then the full dataset descriptions are returned. No value is necessary", |
69
|
|
|
|
|
|
|
{ optional => 'short', valid => FLAG_VALUE }, |
70
|
|
|
|
|
|
|
"If specified, then a brief summary of the datasets is returned. No value is necessary", |
71
|
|
|
|
|
|
|
{ at_most_one => ['full', 'short'] }, |
72
|
|
|
|
|
|
|
{ optional => 'limit', valid => [POS_ZERO_VALUE, ENUM('all')], default => 'all', |
73
|
|
|
|
|
|
|
errmsg => "acceptable values for 'limit' are either 'all', 0, or a positive integer" }, |
74
|
|
|
|
|
|
|
"Limits the number of results returned. Acceptable values are 'all', 0, or a positive integer."); |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
define_ruleset( 'dataset_query' => |
77
|
|
|
|
|
|
|
"This URL queries for stored datasets. The following parameters select the datasets", |
78
|
|
|
|
|
|
|
"to be displayed, and you must specify at least one of them:", |
79
|
|
|
|
|
|
|
{ require => 'filters', |
80
|
|
|
|
|
|
|
errmsg => "you must specify at least one of the following: 'lat' and 'lng', 'id', 'name'" }, |
81
|
|
|
|
|
|
|
"The following optional parameters control how the data is returned:", |
82
|
|
|
|
|
|
|
{ allow => 'display' }); |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
# Validate the parameters found in %ARGS against the ruleset |
85
|
|
|
|
|
|
|
# 'dataset_query'. This is just one example, and in general the parameters |
86
|
|
|
|
|
|
|
# may be found in various places depending upon which module (CGI, |
87
|
|
|
|
|
|
|
# Dancer, Mojolicious, etc.) you are using to accept and process HTTP |
88
|
|
|
|
|
|
|
# requests. |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
my $result = check_params('dataset_query', \%ARGS); |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
if ( my @error_list = $result->errors ) |
93
|
|
|
|
|
|
|
{ |
94
|
|
|
|
|
|
|
# if an error message was generated, do whatever is necessary to abort the |
95
|
|
|
|
|
|
|
# request and report the error back to the end user |
96
|
|
|
|
|
|
|
} |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
# Otherwise, $result->values will return the cleaned parameter |
99
|
|
|
|
|
|
|
# values for use in processing the request. |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
=head1 THE VALIDATION PROCESS |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
The validation process starts with the definition of one or more sets of rules. |
104
|
|
|
|
|
|
|
This is done via the L keyword. For example: |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
define_ruleset 'some_params' => |
107
|
|
|
|
|
|
|
{ param => 'id', valid => POS_VALUE }; |
108
|
|
|
|
|
|
|
{ param => 'short', valid => FLAG_VALUE }, |
109
|
|
|
|
|
|
|
{ param => 'full', valid => FLAG_VALUE }, |
110
|
|
|
|
|
|
|
{ at_most_one => ['short', 'full'], |
111
|
|
|
|
|
|
|
errmsg => "the parameters 'short' and 'full' cannot be used together" }; |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
This statement defines a ruleset named 'some_params' that enforces the following |
114
|
|
|
|
|
|
|
rules: |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
=over 4 |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
=item * |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
The value of parameter 'id' must be a positive integer. |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
=item * |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
The parameter 'short' is considered to have a true value if it appears in a |
125
|
|
|
|
|
|
|
request, and false otherwise. The value, if any, is ignored. |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
=item * |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
The parameter 'full' is treated likewise. |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
=item * |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
The parameters 'short' and 'full' must not be specified together in the same |
134
|
|
|
|
|
|
|
request. |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
=back |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
You can define as many rulesets as you wish. For each URL path recognized by |
139
|
|
|
|
|
|
|
your code, you can use the L function to validate the request |
140
|
|
|
|
|
|
|
parameters against the appropriate ruleset for that path. If the given |
141
|
|
|
|
|
|
|
parameter values are not valid, one or more error messages will be returned. |
142
|
|
|
|
|
|
|
These messages should be sent back to the HTTP client, in order to instruct |
143
|
|
|
|
|
|
|
the user or programmer who originally generated the request how to amend the |
144
|
|
|
|
|
|
|
parameters so that the request will succeed. |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
During the validation process, a set of parameter values are considered to |
147
|
|
|
|
|
|
|
"pass" against a given ruleset if they are consistent with all of its rules. |
148
|
|
|
|
|
|
|
Rulesets may be included inside other rulesets by means of L and |
149
|
|
|
|
|
|
|
L rules. This allows you to define common rulesets to validate |
150
|
|
|
|
|
|
|
various groups of parameters, and then combine them together into specific |
151
|
|
|
|
|
|
|
rulesets for use with different URL paths. |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
A ruleset is considered to be "fulfilled" by a request if at least one |
154
|
|
|
|
|
|
|
parameter mentioned in a L or L rule is included in that |
155
|
|
|
|
|
|
|
request, or trivially if the ruleset does not contain any rules of those |
156
|
|
|
|
|
|
|
types. When you use L to validate a request against a |
157
|
|
|
|
|
|
|
particular ruleset, the request will be rejected unless the following are both |
158
|
|
|
|
|
|
|
true: |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
=over 4 |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
=item * |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
The request passes against the specified ruleset and all those that it |
165
|
|
|
|
|
|
|
includes. |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
=item * |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
The specified ruleset is fulfilled, along with any other rulesets included by |
170
|
|
|
|
|
|
|
L rules. Rulesets included by L rules do not have to be |
171
|
|
|
|
|
|
|
fulfilled. |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
=back |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
This provides you with a lot of flexibilty as to requiring or not requiring |
176
|
|
|
|
|
|
|
various parameters. Note that a ruleset without any L or |
177
|
|
|
|
|
|
|
L rules is automatically fulfilled, which allows you to make all |
178
|
|
|
|
|
|
|
of the paramters optional if you wish. You can augment this mechanism by |
179
|
|
|
|
|
|
|
using L and L rules to specify which parameters must |
180
|
|
|
|
|
|
|
or must not be used together. |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
=head2 Ruleset names |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
Each ruleset must have a unique name, which can be any non-empty |
185
|
|
|
|
|
|
|
string. You may name them after paths, parameters, functionality ("display", |
186
|
|
|
|
|
|
|
"filter") or whatever else makes sense to you. |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
=head2 Ordering of rules |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
The rules in a given ruleset are always checked in the order they were |
191
|
|
|
|
|
|
|
defined. Rulesets that are included via L and L rules are |
192
|
|
|
|
|
|
|
checked immediately when the including rule is evaluated. Each ruleset is |
193
|
|
|
|
|
|
|
checked at most once per validation, even if it is included multiple times. |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
You should be cautious about including multiple parameter rules that |
196
|
|
|
|
|
|
|
correspond to the same parameter name, as this can lead to situations where no |
197
|
|
|
|
|
|
|
possible value is correct. |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
=head2 Unrecognized parameters |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
By default, a request will be rejected with an appropriate error message if it |
202
|
|
|
|
|
|
|
contains any parameters not mentioned in any of the checked rulesets. This |
203
|
|
|
|
|
|
|
can be overridden (see below) to generate warnings instead. However, please |
204
|
|
|
|
|
|
|
think carefully before choosing this option. Allowing unrecognized parameters |
205
|
|
|
|
|
|
|
opens up the possibility that optional parameters will be accidentally |
206
|
|
|
|
|
|
|
misspelled and thus ignored, so that the results are mysteriously different |
207
|
|
|
|
|
|
|
from what was expected. If you override this behavior, you should make sure that |
208
|
|
|
|
|
|
|
any resulting warnings are explicitly displayed in the response that you |
209
|
|
|
|
|
|
|
generate. |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
=head2 Rule syntax |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
Every rule is represented by a hashref that contains a key indicating the rule |
214
|
|
|
|
|
|
|
type. For clarity, you should always write this key first. It is an error to |
215
|
|
|
|
|
|
|
include more than one of these keys in a single rule. You may optionally |
216
|
|
|
|
|
|
|
include additional keys to specify what are the acceptable values for this |
217
|
|
|
|
|
|
|
parameter, what error message should be returned if the parameter value is not |
218
|
|
|
|
|
|
|
acceptable, and L. |
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
=head3 parameter rules |
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
The following three types of rules define the recognized parameter names. |
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
=head4 param |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
{ param => , valid => ... } |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
If the specified parameter is present with a non-empty value, then its value |
229
|
|
|
|
|
|
|
must pass one of the specified validators. If it passes any of them, the rest |
230
|
|
|
|
|
|
|
are ignored. If it does not pass any of them, then an appropriate error |
231
|
|
|
|
|
|
|
message will be generated. If no validators are specified, then the value |
232
|
|
|
|
|
|
|
will be accepted no matter what it is. |
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
If the specified parameter is present and its value is valid, then the |
235
|
|
|
|
|
|
|
containing ruleset will be marked as "fulfilled". You could use this, for |
236
|
|
|
|
|
|
|
example, with a query URL in order to require that the query not be empty |
237
|
|
|
|
|
|
|
but instead contain at least one significant criterion. The parameters that |
238
|
|
|
|
|
|
|
count as "significant" would be declared by C rules, the others by |
239
|
|
|
|
|
|
|
C rules. |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
=head4 optional |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
{ optional => , valid => ... } |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
An C rule is identical to a C rule, except that the presence |
246
|
|
|
|
|
|
|
or absence of the parameter will have no effect on whether or not the |
247
|
|
|
|
|
|
|
containing ruleset is fulfilled. A ruleset in which all of the parameter rules |
248
|
|
|
|
|
|
|
are C will always be fulfilled. This kind of rule is useful in |
249
|
|
|
|
|
|
|
validating URL parameters, especially for GET requests. |
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
=head4 mandatory |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
{ mandatory => , valid => ... } |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
A C rule is identical to a C rule, except that this |
256
|
|
|
|
|
|
|
parameter is required to be present with a non-empty value regardless of the |
257
|
|
|
|
|
|
|
presence or absence of other parameters. If it is not, then an error message |
258
|
|
|
|
|
|
|
will be generated. This kind of rule can be useful when validating HTML form |
259
|
|
|
|
|
|
|
submissions, for use with fields such as "name" that must always be filled in. |
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
=head3 parameter constraint rules |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
The following rule types can be used to specify additional constraints on the |
264
|
|
|
|
|
|
|
presence or absence of parameter names. |
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
=head4 together |
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
{ together => [ ... ] } |
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
If one of the listed parameters is present, then all of them must be. |
271
|
|
|
|
|
|
|
This can be used with parameters such as 'longitude' and 'latitude', where |
272
|
|
|
|
|
|
|
neither one makes sense without the other. |
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
=head4 at_most_one |
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
{ at_most_one => [ ... ] } |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
At most one of the listed parameters may be present. This can be used along |
279
|
|
|
|
|
|
|
with a series of C rules to require that exactly one of a particular |
280
|
|
|
|
|
|
|
set of parameters is provided. |
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
=head4 ignore |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
{ ignore => [ ... ] } |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
The specified parameter or parameters will be ignored if present, and will not |
287
|
|
|
|
|
|
|
be included in the set of reported parameter values. This rule can be used to |
288
|
|
|
|
|
|
|
prevent requests from being rejected with "unrecognized parameter" errors in |
289
|
|
|
|
|
|
|
cases where spurious parameters may be present. If you are specifying only one |
290
|
|
|
|
|
|
|
parameter name, it does need not be in a listref. |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
=head3 inclusion rules |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
The following rule types can be used to include one ruleset inside of another. |
295
|
|
|
|
|
|
|
This allows you, for example, to define rulesets for validating different |
296
|
|
|
|
|
|
|
groups of parameters and then combine them into specific rulesets for use with |
297
|
|
|
|
|
|
|
different URL paths. |
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
It is okay for an included ruleset to itself include other rulesets. A given |
300
|
|
|
|
|
|
|
ruleset is checked at most once per validation no matter how many times it is |
301
|
|
|
|
|
|
|
included. |
302
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
=head4 allow |
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
{ allow => } |
306
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
A rule of this type is essentially an 'include' statement. If this rule is |
308
|
|
|
|
|
|
|
encountered during a validation, it causes the named ruleset to be checked |
309
|
|
|
|
|
|
|
immediately. The parameters must pass against this ruleset, but it does not |
310
|
|
|
|
|
|
|
have to be fulfilled. |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
=head4 require |
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
{ require => } |
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
This is a variant of C, with an additional constraint. The validation |
317
|
|
|
|
|
|
|
will fail unless the named ruleset not only passes but is also fulfilled by |
318
|
|
|
|
|
|
|
the parameters. You could use this, for example, with a query URL in order to |
319
|
|
|
|
|
|
|
require that the query not be empty but instead contain at least one |
320
|
|
|
|
|
|
|
significant criterion. The parameters that count as "significant" would be |
321
|
|
|
|
|
|
|
declared by L rules, the others by L rules. |
322
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
=head3 inclusion constraint rules |
324
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
The following rule types can be used to specify additional constraints on the |
326
|
|
|
|
|
|
|
inclusion of rulesets. |
327
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
=head4 require_one |
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
{ require_one => [ ... ] } |
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
You can use a rule of this type to place an additional constraint on a list of |
333
|
|
|
|
|
|
|
rulesets already included with L. Exactly |
334
|
|
|
|
|
|
|
one of the named rulesets must be fulfilled, or else the request is rejected. |
335
|
|
|
|
|
|
|
You can use this, for example, to ensure that a request includes either a |
336
|
|
|
|
|
|
|
parameter from group A or one from group B, but not both. |
337
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
=head4 require_any |
339
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
{ require_any => [ ... ] } |
341
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
This is a variant of C. At least one of the named rulesets must be |
343
|
|
|
|
|
|
|
fulfilled, or else the request will be rejected. |
344
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
=head4 allow_one |
346
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
{ allow_one => [ ... ] } |
348
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
Another variant of C. The request will be rejected if more than one |
350
|
|
|
|
|
|
|
of the listed rulesets is fulfilled, but will pass if either none of them or |
351
|
|
|
|
|
|
|
just one of them is fulfilled. This can be used to allow optional parameters |
352
|
|
|
|
|
|
|
from either group A or group B, but not from both groups. |
353
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
=head3 other rules |
355
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
=head4 content_type |
357
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
{ content_type => , valid => [ ... ] } |
359
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
You can use a rule of this type, if you wish, to direct that the value of the |
361
|
|
|
|
|
|
|
specified parameter be used to indicate the content type of the response. Only one |
362
|
|
|
|
|
|
|
of these rules should occur in any given validation. The key C gives a |
363
|
|
|
|
|
|
|
list of acceptable values and the content types they should map to. For |
364
|
|
|
|
|
|
|
example, if you are using this module with L then you could do |
365
|
|
|
|
|
|
|
something like the following: |
366
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
define_ruleset '/some/path' => |
368
|
|
|
|
|
|
|
{ require => 'some_params' }, |
369
|
|
|
|
|
|
|
{ allow => 'other_params' }, |
370
|
|
|
|
|
|
|
{ content_type => 'ct', valid => ['html', 'json', 'frob=application/frobnicate'] }; |
371
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
get '/some/path.:ct' => sub { |
373
|
|
|
|
|
|
|
|
374
|
|
|
|
|
|
|
my $valid_request = check_params('/some/path', params); |
375
|
|
|
|
|
|
|
content_type $valid_request->content_type; |
376
|
|
|
|
|
|
|
... |
377
|
|
|
|
|
|
|
} |
378
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
This code specifies that the content type of the response will be set by the |
380
|
|
|
|
|
|
|
URL path suffix, which may be either C<.html>, C<.json> or C<.frob>. |
381
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
If the value given in a request does not occur in the list, or if no value is |
383
|
|
|
|
|
|
|
found, then an error message will be generated that lists the accepted types. |
384
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
To match an empty parameter value, include a string that looks like |
386
|
|
|
|
|
|
|
'=some/type'. You need not specify the actual content type string for the |
387
|
|
|
|
|
|
|
well-known types 'html', 'json', 'xml', 'txt' or 'csv', unless you wish to |
388
|
|
|
|
|
|
|
override the default given by this module. |
389
|
|
|
|
|
|
|
|
390
|
|
|
|
|
|
|
=head2 Rule attributes |
391
|
|
|
|
|
|
|
|
392
|
|
|
|
|
|
|
Any rule definition may also include one or more of the following attributes, |
393
|
|
|
|
|
|
|
specified as key/value pairs in the rule hash: |
394
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
=head3 errmsg |
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
This attribute specifies the error message to be returned if the rule fails, |
398
|
|
|
|
|
|
|
overriding the default message. For example: |
399
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
define_ruleset( 'specifier' => |
401
|
|
|
|
|
|
|
{ param => 'name', valid => STRING_VALUE }, |
402
|
|
|
|
|
|
|
{ param => 'id', valid => POS_VALUE }); |
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
define_ruleset( 'my_route' => |
405
|
|
|
|
|
|
|
{ require => 'specifier', |
406
|
|
|
|
|
|
|
errmsg => "you must specify either of the parameters 'name' or 'id'" }); |
407
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
Error messages may include any of the following placeholders: C<{param}>, |
409
|
|
|
|
|
|
|
C<{value}>. These are replaced respectively by the relevant parameter name(s) |
410
|
|
|
|
|
|
|
and original parameter value(s), single-quoted. This feature allows you to |
411
|
|
|
|
|
|
|
define messages that quote the actual parameter values presented in the |
412
|
|
|
|
|
|
|
request, as well as to define common messages and use them with multiple |
413
|
|
|
|
|
|
|
rules. |
414
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
=head3 warn |
416
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
This attribute causes a warning to be generated rather than an error if the |
418
|
|
|
|
|
|
|
rule fails. Unlike errors, warnings do not cause a request to be rejected. |
419
|
|
|
|
|
|
|
At the end of the validation process, the list of generated warnings can be |
420
|
|
|
|
|
|
|
retrieved by using the L method of the result object. |
421
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
If the value of this key is 1, then what would otherwise be the error |
423
|
|
|
|
|
|
|
message will be used as the warning message. Otherwise, the specified string |
424
|
|
|
|
|
|
|
will be used as the warning message. |
425
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
For parameter rules, this attribute affects only errors resulting from |
427
|
|
|
|
|
|
|
validation of the parameter values. Other error conditions (i.e. multiple |
428
|
|
|
|
|
|
|
parameter values without the L attribute) continue to be reported |
429
|
|
|
|
|
|
|
as errors. |
430
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
=head3 key |
432
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
The attribute 'key' specifies the name under which any information generated by |
434
|
|
|
|
|
|
|
the rule will be saved. For a parameter rule, the cleaned value will be saved |
435
|
|
|
|
|
|
|
under this name. For all rules, any generated warnings or errors will be |
436
|
|
|
|
|
|
|
stored under the specified name instead of the parameter name or rule number. |
437
|
|
|
|
|
|
|
This allows you to easily determine after a validation which |
438
|
|
|
|
|
|
|
warnings or errors were generated. |
439
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
The following keys can be used only with rules of type |
441
|
|
|
|
|
|
|
L, L or L: |
442
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
=head3 valid |
444
|
|
|
|
|
|
|
|
445
|
|
|
|
|
|
|
This attribute specifies the domain of acceptable values for the parameter. The |
446
|
|
|
|
|
|
|
value must be either a single code reference or a list of them. You can |
447
|
|
|
|
|
|
|
either select from the list of L |
448
|
|
|
|
|
|
|
included with this module, or provide your own. |
449
|
|
|
|
|
|
|
|
450
|
|
|
|
|
|
|
If the parameter named by this rule is present, its value must pass at least |
451
|
|
|
|
|
|
|
one of the specified validators or else an error message will be generated. |
452
|
|
|
|
|
|
|
If multiple validators are given, then the error message returned will be the |
453
|
|
|
|
|
|
|
one generated by the last validator in the list. This can be overridden by |
454
|
|
|
|
|
|
|
using the L key. |
455
|
|
|
|
|
|
|
|
456
|
|
|
|
|
|
|
=head3 multiple |
457
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
This attribute specifies that the parameter may appear multiple times in the |
459
|
|
|
|
|
|
|
request. Without this directive, multiple values for the same parameter will |
460
|
|
|
|
|
|
|
generate an error. For example: |
461
|
|
|
|
|
|
|
|
462
|
|
|
|
|
|
|
define_ruleset( 'identifiers' => |
463
|
|
|
|
|
|
|
{ param => 'id', valid => POS_VALUE, multiple => 1 }); |
464
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
If this attribute is present with a true value, then the cleaned value of the |
466
|
|
|
|
|
|
|
parameter will be an array ref if at least one valid value was found and |
467
|
|
|
|
|
|
|
I otherwise. If you wish a request to be considered valid even if some |
468
|
|
|
|
|
|
|
of the values fail the validator, then either use the L attribute instead or |
469
|
|
|
|
|
|
|
include a L key as well. |
470
|
|
|
|
|
|
|
|
471
|
|
|
|
|
|
|
=head3 split |
472
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
This attribute has the same effect as L, and in addition causes |
474
|
|
|
|
|
|
|
each parameter value string to be split (L) as indicated by the |
475
|
|
|
|
|
|
|
value of the directive. If this value is a string, then it will be compiled |
476
|
|
|
|
|
|
|
into a regexp preceded and followed by C<\s*>. So in the |
477
|
|
|
|
|
|
|
following example: |
478
|
|
|
|
|
|
|
|
479
|
|
|
|
|
|
|
define_ruleset( 'identifiers' => |
480
|
|
|
|
|
|
|
{ param => 'id', valid => POS_VALUE, split => ',' }); |
481
|
|
|
|
|
|
|
|
482
|
|
|
|
|
|
|
The value string will be considered to be valid if it contains one or more |
483
|
|
|
|
|
|
|
positive integers separated by commas and optional whitespace. Empty strings |
484
|
|
|
|
|
|
|
between separators are ignored. |
485
|
|
|
|
|
|
|
|
486
|
|
|
|
|
|
|
123,456 # returns [123, 456] |
487
|
|
|
|
|
|
|
123 , ,456 # returns [123, 456] |
488
|
|
|
|
|
|
|
, 456 # returns [456] |
489
|
|
|
|
|
|
|
123 456 # not valid |
490
|
|
|
|
|
|
|
123:456 # not valid |
491
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
If you wish more precise control over the separator expression, you can pass a |
493
|
|
|
|
|
|
|
regexp quoted with L instead. |
494
|
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
=head3 list |
496
|
|
|
|
|
|
|
|
497
|
|
|
|
|
|
|
This attribute has the same effect as L, but generates warnings |
498
|
|
|
|
|
|
|
instead of error messages when invalid values are encountered (as if |
499
|
|
|
|
|
|
|
C<< warn => 1 >> was also specified). The resulting cleaned value will be a |
500
|
|
|
|
|
|
|
listref containing any values which pass the validator, or I if no |
501
|
|
|
|
|
|
|
valid values were found. See also L and L. |
502
|
|
|
|
|
|
|
|
503
|
|
|
|
|
|
|
=head3 bad_value |
504
|
|
|
|
|
|
|
|
505
|
|
|
|
|
|
|
This attribute can be useful in conjunction with L. If one or more |
506
|
|
|
|
|
|
|
values are given for the parameter but none of them are valid, this attribute |
507
|
|
|
|
|
|
|
comes into effect. If the value of this attribute is C, then the |
508
|
|
|
|
|
|
|
validation will fail with an appropriate error message. Otherwise, this will |
509
|
|
|
|
|
|
|
be used as the value of the parameter. It is recommended that you set the |
510
|
|
|
|
|
|
|
value to something outside of the valid range, i.e. C<-1> for a C |
511
|
|
|
|
|
|
|
parameter. |
512
|
|
|
|
|
|
|
|
513
|
|
|
|
|
|
|
Using this attribute allows you to easily distinguish between the case when |
514
|
|
|
|
|
|
|
the parameter appears with an empty value (or not at all, which is considered |
515
|
|
|
|
|
|
|
equivalent) vs. when the parameter appears with one or more invalid values and |
516
|
|
|
|
|
|
|
no good ones. |
517
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
=head3 alias |
519
|
|
|
|
|
|
|
|
520
|
|
|
|
|
|
|
This attribute specifies one or more aliases for the parameter name (use a |
521
|
|
|
|
|
|
|
listref for multiple aliases). These names may be used interchangeably in |
522
|
|
|
|
|
|
|
requests, but any request that contains more than one of them will be rejected |
523
|
|
|
|
|
|
|
with an appropriate error message unless L is also specified. The |
524
|
|
|
|
|
|
|
parameter value and any error or warning messages will be reported under the |
525
|
|
|
|
|
|
|
main parameter name for this rule, no matter which alias is used in the |
526
|
|
|
|
|
|
|
request. |
527
|
|
|
|
|
|
|
|
528
|
|
|
|
|
|
|
=head3 clean |
529
|
|
|
|
|
|
|
|
530
|
|
|
|
|
|
|
This attribute specifies a subroutine which will be used to modify the |
531
|
|
|
|
|
|
|
parameter values. This routine will be called with the raw value of the |
532
|
|
|
|
|
|
|
parameter as its only argument, once for each value if multiple values are |
533
|
|
|
|
|
|
|
allowed. The resulting values will be stored as the "cleaned" values. The |
534
|
|
|
|
|
|
|
value of this directive may be either a code ref or one of the strings 'uc', |
535
|
|
|
|
|
|
|
'lc' or 'fc'. These direct that the parameter values be converted to |
536
|
|
|
|
|
|
|
uppercase, lowercase, or L respectively. |
537
|
|
|
|
|
|
|
|
538
|
|
|
|
|
|
|
=head3 default |
539
|
|
|
|
|
|
|
|
540
|
|
|
|
|
|
|
This attribute specifies a default value for the parameter, which will be |
541
|
|
|
|
|
|
|
reported if the parameter is not present in the request or if it is present |
542
|
|
|
|
|
|
|
with an empty value. If the rule also includes a validator and/or a cleaner, |
543
|
|
|
|
|
|
|
the specified default value will be passed to it when the ruleset is defined. |
544
|
|
|
|
|
|
|
An exception will be thrown if the default value does not pass the validator. |
545
|
|
|
|
|
|
|
|
546
|
|
|
|
|
|
|
=head3 undocumented |
547
|
|
|
|
|
|
|
|
548
|
|
|
|
|
|
|
If this attribute is given with a true value, then this rule will be ignored |
549
|
|
|
|
|
|
|
by any calls to L. This feature allows you to include |
550
|
|
|
|
|
|
|
parameters that are recognized as valid but that are not included in any |
551
|
|
|
|
|
|
|
generated documentation. Such parameters will be invisible to users, but |
552
|
|
|
|
|
|
|
will be visible and clearly marked to anybody browsing your source code. |
553
|
|
|
|
|
|
|
|
554
|
|
|
|
|
|
|
=head2 Documentation |
555
|
|
|
|
|
|
|
|
556
|
|
|
|
|
|
|
A ruleset definition may include strings interspersed with the rule |
557
|
|
|
|
|
|
|
definitions (see the L) which can |
558
|
|
|
|
|
|
|
be turned into documentation in Pod format by means of the L |
559
|
|
|
|
|
|
|
keyword. It is recommended that you use this function to auto-generate the |
560
|
|
|
|
|
|
|
C section of the documentation pages for the various URL paths |
561
|
|
|
|
|
|
|
accepted by your web application, translating the output from Pod to whatever |
562
|
|
|
|
|
|
|
format is appropriate. This will help you to keep the documentation and the |
563
|
|
|
|
|
|
|
actual rules in synchrony with one another. |
564
|
|
|
|
|
|
|
|
565
|
|
|
|
|
|
|
The generated documentation will consist of one or more item lists, separated |
566
|
|
|
|
|
|
|
by ordinary paragraphs. Each parameter rule will generate one item, whose body |
567
|
|
|
|
|
|
|
consists of the documentation strings immediately following the rule |
568
|
|
|
|
|
|
|
definition. Ordinary paragraphs (see below) can be used to separate the |
569
|
|
|
|
|
|
|
parameters into groups for documentation purposes, or at the start or end of a |
570
|
|
|
|
|
|
|
list as introductory or concluding material. Each L or L |
571
|
|
|
|
|
|
|
rule causes the documentation for the indicated ruleset(s) to be interpolated, |
572
|
|
|
|
|
|
|
except as noted below. Note that this subsidiary documentation will not be |
573
|
|
|
|
|
|
|
nested. All of the parameters will be documented at the same list indentation |
574
|
|
|
|
|
|
|
level, whether or not they are defined in subsidiary rulesets. |
575
|
|
|
|
|
|
|
|
576
|
|
|
|
|
|
|
Documentation strings may start with one of the following special characters: |
577
|
|
|
|
|
|
|
|
578
|
|
|
|
|
|
|
=over 4 |
579
|
|
|
|
|
|
|
|
580
|
|
|
|
|
|
|
=item C<<< >> >>> |
581
|
|
|
|
|
|
|
|
582
|
|
|
|
|
|
|
The remainder of this string, plus any strings immediately following, will |
583
|
|
|
|
|
|
|
appear as an ordinary paragraph. You can use this feature to provide |
584
|
|
|
|
|
|
|
commentary paragraphs separating the documented parameters into groups. |
585
|
|
|
|
|
|
|
Any documentation strings occurring before the first parameter rule |
586
|
|
|
|
|
|
|
definition, or following an C or C rule, will always generate |
587
|
|
|
|
|
|
|
ordinary paragraphs regardless of whether they start with this special |
588
|
|
|
|
|
|
|
character. |
589
|
|
|
|
|
|
|
|
590
|
|
|
|
|
|
|
=item C<<< > >>> |
591
|
|
|
|
|
|
|
|
592
|
|
|
|
|
|
|
The remainder of this string, plus any strings immediately following, will |
593
|
|
|
|
|
|
|
appear as a new paragraph of the same type as the preceding paragraph (item |
594
|
|
|
|
|
|
|
body or ordinary paragraph). |
595
|
|
|
|
|
|
|
|
596
|
|
|
|
|
|
|
=item C |
597
|
|
|
|
|
|
|
|
598
|
|
|
|
|
|
|
The preceding rule definition will be ignored by any calls to |
599
|
|
|
|
|
|
|
L, and all documentation for this rule will be suppressed. |
600
|
|
|
|
|
|
|
This is equivalent to specifying the rule attribute L. |
601
|
|
|
|
|
|
|
|
602
|
|
|
|
|
|
|
=item C<^> |
603
|
|
|
|
|
|
|
|
604
|
|
|
|
|
|
|
Any documentation generated for the preceding rule definition will be |
605
|
|
|
|
|
|
|
suppressed. The remainder of this string plus any strings immediately |
606
|
|
|
|
|
|
|
following will appear as an ordinary paragraph in its place. You can use |
607
|
|
|
|
|
|
|
this, for example, to document a subsidiary ruleset with an explanatory note |
608
|
|
|
|
|
|
|
(i.e. a link to another documentation section or page) instead of explicitly |
609
|
|
|
|
|
|
|
listing all of the included parameters. |
610
|
|
|
|
|
|
|
|
611
|
|
|
|
|
|
|
=item C> |
612
|
|
|
|
|
|
|
|
613
|
|
|
|
|
|
|
This character is ignored at the beginning of a documentation string, and the |
614
|
|
|
|
|
|
|
next character loses any special meaning it might have had. You can use this |
615
|
|
|
|
|
|
|
in the unlikely event that you want a documentation paragraph to actually |
616
|
|
|
|
|
|
|
start with one of these special characters. |
617
|
|
|
|
|
|
|
|
618
|
|
|
|
|
|
|
=back |
619
|
|
|
|
|
|
|
|
620
|
|
|
|
|
|
|
Note that modifier rules such as C, C, etc. are |
621
|
|
|
|
|
|
|
ignored when generating documentation. Any documentation strings following |
622
|
|
|
|
|
|
|
them will be treated as if they apply to the most recently preceding parameter |
623
|
|
|
|
|
|
|
rule or inclusion rule. |
624
|
|
|
|
|
|
|
|
625
|
|
|
|
|
|
|
=cut |
626
|
|
|
|
|
|
|
|
627
|
|
|
|
|
|
|
our (@EXPORT_OK, @VALIDATORS, %EXPORT_TAGS); |
628
|
|
|
|
|
|
|
|
629
|
|
|
|
|
|
|
BEGIN { |
630
|
|
|
|
|
|
|
|
631
|
7
|
|
|
7
|
|
30
|
@EXPORT_OK = qw( |
632
|
|
|
|
|
|
|
define_ruleset check_params validation_settings ruleset_defined document_params |
633
|
|
|
|
|
|
|
list_params |
634
|
|
|
|
|
|
|
INT_VALUE POS_VALUE POS_ZERO_VALUE |
635
|
|
|
|
|
|
|
DECI_VALUE |
636
|
|
|
|
|
|
|
ENUM_VALUE |
637
|
|
|
|
|
|
|
BOOLEAN_VALUE |
638
|
|
|
|
|
|
|
MATCH_VALUE |
639
|
|
|
|
|
|
|
FLAG_VALUE ANY_VALUE |
640
|
|
|
|
|
|
|
); |
641
|
|
|
|
|
|
|
|
642
|
7
|
|
|
|
|
20
|
@VALIDATORS = qw(INT_VALUE POS_VALUE POS_ZERO_VALUE DECI_VALUE |
643
|
|
|
|
|
|
|
ENUM_VALUE MATCH_VALUE BOOLEAN_VALUE FLAG_VALUE ANY_VALUE); |
644
|
|
|
|
|
|
|
|
645
|
7
|
|
|
|
|
42729
|
%EXPORT_TAGS = ( |
646
|
|
|
|
|
|
|
keywords => [qw(define_ruleset check_params validation_settings ruleset_defined document_params |
647
|
|
|
|
|
|
|
list_params)], |
648
|
|
|
|
|
|
|
validators => \@VALIDATORS, |
649
|
|
|
|
|
|
|
); |
650
|
|
|
|
|
|
|
}; |
651
|
|
|
|
|
|
|
|
652
|
|
|
|
|
|
|
# The following defines a single global validator object, for use when this |
653
|
|
|
|
|
|
|
# module is used in the non-object-oriented manner. |
654
|
|
|
|
|
|
|
|
655
|
|
|
|
|
|
|
our ($DEFAULT_INSTANCE) = bless { RULESETS => {}, SETTINGS => {} }; |
656
|
|
|
|
|
|
|
|
657
|
|
|
|
|
|
|
|
658
|
|
|
|
|
|
|
# Known media types are defined here |
659
|
|
|
|
|
|
|
|
660
|
|
|
|
|
|
|
my (%MEDIA_TYPE) = |
661
|
|
|
|
|
|
|
('html' => 'text/html', |
662
|
|
|
|
|
|
|
'xml' => 'text/xml', |
663
|
|
|
|
|
|
|
'txt' => 'text/plain', |
664
|
|
|
|
|
|
|
'tsv' => 'text/tab-separated-values', |
665
|
|
|
|
|
|
|
'csv' => 'text/csv', |
666
|
|
|
|
|
|
|
'json' => 'application/json', |
667
|
|
|
|
|
|
|
); |
668
|
|
|
|
|
|
|
|
669
|
|
|
|
|
|
|
# Default error messages |
670
|
|
|
|
|
|
|
|
671
|
|
|
|
|
|
|
my (%ERROR_MSG) = |
672
|
|
|
|
|
|
|
('ERR_INVALID' => "the value of parameter {param} is invalid (was {value})", |
673
|
|
|
|
|
|
|
'ERR_BAD_VALUES' => "no valid values were specified for {param} (found {value})", |
674
|
|
|
|
|
|
|
'ERR_MULT_NAMES' => "you may only include one of {param}", |
675
|
|
|
|
|
|
|
'ERR_MULT_VALUES' => "you may only specify one value for {param}: found {value}", |
676
|
|
|
|
|
|
|
'ERR_MANDATORY' => "you must specify a value for {param}", |
677
|
|
|
|
|
|
|
'ERR_TOGETHER' => "you must specify {param} together or not at all", |
678
|
|
|
|
|
|
|
'ERR_AT_MOST' => "you may not specify more than one of {param}", |
679
|
|
|
|
|
|
|
'ERR_REQ_SINGLE' => "you must specify the parameter {param}", |
680
|
|
|
|
|
|
|
'ERR_REQ_MULT' => "you must specify at least one of the parameters {param}", |
681
|
|
|
|
|
|
|
'ERR_REQ_ONE' => "you may not include parameters from more than one of these groups: {param}", |
682
|
|
|
|
|
|
|
'ERR_MEDIA_TYPE' => "you must specify a media type, from the following list: {value}", |
683
|
|
|
|
|
|
|
'ERR_DEFAULT' => "parameter value error: {param}", |
684
|
|
|
|
|
|
|
); |
685
|
|
|
|
|
|
|
|
686
|
|
|
|
|
|
|
=head1 INTERFACE |
687
|
|
|
|
|
|
|
|
688
|
|
|
|
|
|
|
This module can be used in either an object-oriented or a procedural manner. |
689
|
|
|
|
|
|
|
To use the object-oriented interface, generate a new instance of |
690
|
|
|
|
|
|
|
HTTP::Validate and use any of the routines listed below as methods: |
691
|
|
|
|
|
|
|
|
692
|
|
|
|
|
|
|
use HTTP::Validate qw(:validators); |
693
|
|
|
|
|
|
|
|
694
|
|
|
|
|
|
|
my $validator = HTTP::Validate->new(); |
695
|
|
|
|
|
|
|
|
696
|
|
|
|
|
|
|
$validator->define_ruleset('my_params' => |
697
|
|
|
|
|
|
|
{ param => 'foo', valid => INT_VALUE, default => '0' }); |
698
|
|
|
|
|
|
|
|
699
|
|
|
|
|
|
|
my $result = $validator->check_params('my_params', \%ARGS); |
700
|
|
|
|
|
|
|
|
701
|
|
|
|
|
|
|
Otherwise, you can export these routines to your module and call them |
702
|
|
|
|
|
|
|
directly. In this case, a global ruleset namespace will be assumed: |
703
|
|
|
|
|
|
|
|
704
|
|
|
|
|
|
|
use HTTP::Validate qw(:keywords :validators); |
705
|
|
|
|
|
|
|
|
706
|
|
|
|
|
|
|
define_ruleset('my_params' => |
707
|
|
|
|
|
|
|
{ param => 'foo', valid => INT_VALUE, default => '0' }); |
708
|
|
|
|
|
|
|
|
709
|
|
|
|
|
|
|
my $validated = check_params('my_params', \%ARGS); |
710
|
|
|
|
|
|
|
|
711
|
|
|
|
|
|
|
Using C<:keywords> will import all of the keywords listed below, except |
712
|
|
|
|
|
|
|
'new'. Using C<:validators> will import all of the L |
713
|
|
|
|
|
|
|
listed below. |
714
|
|
|
|
|
|
|
|
715
|
|
|
|
|
|
|
The following can be called either as subroutines or as method names, |
716
|
|
|
|
|
|
|
depending upon which paradigm you prefer: |
717
|
|
|
|
|
|
|
|
718
|
|
|
|
|
|
|
=head3 new |
719
|
|
|
|
|
|
|
|
720
|
|
|
|
|
|
|
This can be called as a class method to generate a new validation instance |
721
|
|
|
|
|
|
|
(see example above) with its own ruleset namespace. Any of the arguments that |
722
|
|
|
|
|
|
|
can be passed to L can also be passed to this routine. |
723
|
|
|
|
|
|
|
|
724
|
|
|
|
|
|
|
=cut |
725
|
|
|
|
|
|
|
|
726
|
|
|
|
|
|
|
sub new { |
727
|
|
|
|
|
|
|
|
728
|
9
|
|
|
9
|
1
|
2829
|
my ($class, @settings) = @_; |
729
|
|
|
|
|
|
|
|
730
|
9
|
50
|
|
|
|
21
|
croak "You must call 'new' as a class method" unless defined $class; |
731
|
|
|
|
|
|
|
|
732
|
|
|
|
|
|
|
# Create a new object |
733
|
|
|
|
|
|
|
|
734
|
9
|
|
|
|
|
23
|
my $self = bless { RULESETS => {}, SETTINGS => {} }, $class; |
735
|
|
|
|
|
|
|
|
736
|
|
|
|
|
|
|
# Set the requested settings |
737
|
|
|
|
|
|
|
|
738
|
9
|
|
|
|
|
20
|
$self->validation_settings(@settings); |
739
|
|
|
|
|
|
|
|
740
|
|
|
|
|
|
|
# Return the new object |
741
|
|
|
|
|
|
|
|
742
|
7
|
|
|
|
|
16
|
return $self; |
743
|
|
|
|
|
|
|
} |
744
|
|
|
|
|
|
|
|
745
|
|
|
|
|
|
|
|
746
|
|
|
|
|
|
|
=head3 define_ruleset |
747
|
|
|
|
|
|
|
|
748
|
|
|
|
|
|
|
This keyword defines a set of rules to be used for validating parameters. The |
749
|
|
|
|
|
|
|
first argument is the ruleset's name, which must be unique within its |
750
|
|
|
|
|
|
|
namespace. The rest of the parameters must be a list of rules (hashrefs) interspersed |
751
|
|
|
|
|
|
|
with documentation strings. For examples, see above. |
752
|
|
|
|
|
|
|
|
753
|
|
|
|
|
|
|
=cut |
754
|
|
|
|
|
|
|
|
755
|
|
|
|
|
|
|
sub define_ruleset { |
756
|
|
|
|
|
|
|
|
757
|
|
|
|
|
|
|
# If we were called as a method, use the object on which we were called. |
758
|
|
|
|
|
|
|
# Otherwise, use the default instance. |
759
|
|
|
|
|
|
|
|
760
|
77
|
100
|
|
77
|
1
|
13247
|
my $self = ref $_[0] eq 'HTTP::Validate' ? shift : $DEFAULT_INSTANCE; |
761
|
|
|
|
|
|
|
|
762
|
77
|
|
|
|
|
106
|
my ($ruleset_name, @rules) = @_; |
763
|
|
|
|
|
|
|
|
764
|
|
|
|
|
|
|
# Next make sure we know where this is called from, for the purpose of |
765
|
|
|
|
|
|
|
# generating useful error messages. |
766
|
|
|
|
|
|
|
|
767
|
77
|
|
|
|
|
155
|
my ($package, $filename, $line) = caller; |
768
|
|
|
|
|
|
|
|
769
|
|
|
|
|
|
|
# Check the arguments, then create a new ruleset object. |
770
|
|
|
|
|
|
|
|
771
|
77
|
100
|
100
|
|
|
875
|
croak "The first argument to 'define_ruleset' must be a non-empty string" |
|
|
|
100
|
|
|
|
|
772
|
|
|
|
|
|
|
unless defined $ruleset_name && !ref $ruleset_name && $ruleset_name ne ''; |
773
|
|
|
|
|
|
|
|
774
|
74
|
|
|
|
|
165
|
my $rs = $self->create_ruleset($ruleset_name, $filename, $line); |
775
|
|
|
|
|
|
|
|
776
|
|
|
|
|
|
|
# Then add the rules. |
777
|
|
|
|
|
|
|
|
778
|
72
|
|
|
|
|
117
|
$self->add_rules($rs, @rules); |
779
|
|
|
|
|
|
|
|
780
|
|
|
|
|
|
|
# If we get here without any errors, install the ruleset and return. |
781
|
|
|
|
|
|
|
|
782
|
61
|
|
|
|
|
94
|
$self->{RULESETS}{$ruleset_name} = $rs; |
783
|
61
|
|
|
|
|
107
|
return 1; |
784
|
|
|
|
|
|
|
}; |
785
|
|
|
|
|
|
|
|
786
|
|
|
|
|
|
|
|
787
|
|
|
|
|
|
|
=head3 check_params |
788
|
|
|
|
|
|
|
|
789
|
|
|
|
|
|
|
my $result = check_params('my_ruleset', undef, params('query')); |
790
|
|
|
|
|
|
|
|
791
|
|
|
|
|
|
|
if ( $result->passed ) |
792
|
|
|
|
|
|
|
{ |
793
|
|
|
|
|
|
|
# process the request using the keys and values returned by |
794
|
|
|
|
|
|
|
# $result->values |
795
|
|
|
|
|
|
|
} |
796
|
|
|
|
|
|
|
|
797
|
|
|
|
|
|
|
else |
798
|
|
|
|
|
|
|
{ |
799
|
|
|
|
|
|
|
# redisplay the form, send an error response, or otherwise handle the |
800
|
|
|
|
|
|
|
# error condition using the error messages returned by $result->errors |
801
|
|
|
|
|
|
|
} |
802
|
|
|
|
|
|
|
|
803
|
|
|
|
|
|
|
This function validates a set of parameters and values (which may be provided |
804
|
|
|
|
|
|
|
either as one or more hashrefs or as a flattened list of keys and values or a |
805
|
|
|
|
|
|
|
combination of the two) against the named ruleset with the specified context. It |
806
|
|
|
|
|
|
|
returns a response object from which you can get the cleaned parameter values |
807
|
|
|
|
|
|
|
along with any errors or warnings that may have been generated. |
808
|
|
|
|
|
|
|
|
809
|
|
|
|
|
|
|
The second parameter must be either a hashref or undefined. If it is defined, |
810
|
|
|
|
|
|
|
it is passed to each of the validator functions as "context". This allows you |
811
|
|
|
|
|
|
|
to provide attributes such as a database handle to the validator functions. |
812
|
|
|
|
|
|
|
The third parameter must be either a hashref or a listref containing parameter |
813
|
|
|
|
|
|
|
names and values. If it is a listref, any items at the beginning of the list |
814
|
|
|
|
|
|
|
which are themselves hashrefs will be expanded before the list is processed |
815
|
|
|
|
|
|
|
(this allows you, for example, to pass in a hashref plus some additional names |
816
|
|
|
|
|
|
|
and values without having to modify the hashref in place). |
817
|
|
|
|
|
|
|
|
818
|
|
|
|
|
|
|
You can use the L method on the returned object to determine if the |
819
|
|
|
|
|
|
|
validation passed or failed. In the latter case, you can return an HTTP error |
820
|
|
|
|
|
|
|
response to the user, or perhaps redisplay a submitted form. |
821
|
|
|
|
|
|
|
|
822
|
|
|
|
|
|
|
Note that you can validate against multiple rulesets at once by defining a new |
823
|
|
|
|
|
|
|
ruleset with inclusion rules referring to all of the rulesets |
824
|
|
|
|
|
|
|
you wish to validate against. |
825
|
|
|
|
|
|
|
|
826
|
|
|
|
|
|
|
=cut |
827
|
|
|
|
|
|
|
|
828
|
|
|
|
|
|
|
sub check_params { |
829
|
|
|
|
|
|
|
|
830
|
|
|
|
|
|
|
# If we were called as a method, use the object on which we were called. |
831
|
|
|
|
|
|
|
# Otherwise, use the globally defined one. |
832
|
|
|
|
|
|
|
|
833
|
60
|
100
|
|
60
|
1
|
18464
|
my $self = ref $_[0] eq 'HTTP::Validate' ? shift : $DEFAULT_INSTANCE; |
834
|
|
|
|
|
|
|
|
835
|
60
|
|
|
|
|
93
|
my ($ruleset_name, $context, $parameters) = @_; |
836
|
|
|
|
|
|
|
|
837
|
|
|
|
|
|
|
# Create a new validation-execution object using the specified context |
838
|
|
|
|
|
|
|
# and parameters. |
839
|
|
|
|
|
|
|
|
840
|
60
|
|
|
|
|
110
|
my $vr = $self->new_execution($context, $parameters); |
841
|
|
|
|
|
|
|
|
842
|
|
|
|
|
|
|
# Now execute that validation using the specified ruleset, and return the |
843
|
|
|
|
|
|
|
# result. |
844
|
|
|
|
|
|
|
|
845
|
60
|
|
|
|
|
107
|
return $self->execute_validation($vr, $ruleset_name); |
846
|
|
|
|
|
|
|
}; |
847
|
|
|
|
|
|
|
|
848
|
|
|
|
|
|
|
|
849
|
|
|
|
|
|
|
=head3 validation_settings |
850
|
|
|
|
|
|
|
|
851
|
|
|
|
|
|
|
This function allows you to change the settings on the validation routine. |
852
|
|
|
|
|
|
|
For example: |
853
|
|
|
|
|
|
|
|
854
|
|
|
|
|
|
|
validation_settings( allow_unrecognized => 1 ); |
855
|
|
|
|
|
|
|
|
856
|
|
|
|
|
|
|
If you are using this module in an object-oriented way, then you can also pass |
857
|
|
|
|
|
|
|
any of these settings as parameters to the constructor method. Available |
858
|
|
|
|
|
|
|
settings include: |
859
|
|
|
|
|
|
|
|
860
|
|
|
|
|
|
|
=over 4 |
861
|
|
|
|
|
|
|
|
862
|
|
|
|
|
|
|
=item allow_unrecognized |
863
|
|
|
|
|
|
|
|
864
|
|
|
|
|
|
|
If specified, then unrecognized parameters will generate warnings instead of errors. |
865
|
|
|
|
|
|
|
|
866
|
|
|
|
|
|
|
=item ignore_unrecognized |
867
|
|
|
|
|
|
|
|
868
|
|
|
|
|
|
|
If specified, then unrecognized parameters will be ignored entirely. |
869
|
|
|
|
|
|
|
|
870
|
|
|
|
|
|
|
=back |
871
|
|
|
|
|
|
|
|
872
|
|
|
|
|
|
|
You may also specify one or more of the following keys, each followed by a string. These |
873
|
|
|
|
|
|
|
allow you to redefine the messages that are generated when parameter errors are detected: |
874
|
|
|
|
|
|
|
|
875
|
|
|
|
|
|
|
ERR_INVALID, ERR_BAD_VALUES, ERR_MULT_NAMES, ERR_MULT_VALUES, ERR_MANDATORY, ERR_TOGETHER, |
876
|
|
|
|
|
|
|
ERR_AT_MOST, ERR_REQ_SINGLE, ERR_REQ_MULT, ERR_REQ_ONE, ERR_MEDIA_TYPE, ERR_DEFAULT |
877
|
|
|
|
|
|
|
|
878
|
|
|
|
|
|
|
For example: |
879
|
|
|
|
|
|
|
|
880
|
|
|
|
|
|
|
validation_settings( ERR_MANDATORY => 'Missing mandatory parameter {param}', |
881
|
|
|
|
|
|
|
ERR_REQ_SINGLE => 'Found {value} for {param}: only one value is allowed' ); |
882
|
|
|
|
|
|
|
|
883
|
|
|
|
|
|
|
=cut |
884
|
|
|
|
|
|
|
|
885
|
|
|
|
|
|
|
sub validation_settings { |
886
|
|
|
|
|
|
|
|
887
|
|
|
|
|
|
|
# If we were called as a method, use the object on which we were called. |
888
|
|
|
|
|
|
|
# Otherwise, use the globally defined one. |
889
|
|
|
|
|
|
|
|
890
|
15
|
100
|
|
15
|
1
|
1758
|
my $self = ref $_[0] eq 'HTTP::Validate' ? shift : $DEFAULT_INSTANCE; |
891
|
|
|
|
|
|
|
|
892
|
15
|
|
|
|
|
30
|
while (@_) |
893
|
|
|
|
|
|
|
{ |
894
|
34
|
|
|
|
|
28
|
my $key = shift; |
895
|
34
|
|
|
|
|
23
|
my $value = shift; |
896
|
|
|
|
|
|
|
|
897
|
34
|
100
|
|
|
|
66
|
if ( $key eq 'allow_unrecognized' ) |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
898
|
|
|
|
|
|
|
{ |
899
|
5
|
50
|
|
|
|
22
|
$self->{SETTINGS}{permissive} = $value ? 1 : 0; |
900
|
|
|
|
|
|
|
} |
901
|
|
|
|
|
|
|
|
902
|
|
|
|
|
|
|
elsif ( $key eq 'ignore_unrecognized' ) |
903
|
|
|
|
|
|
|
{ |
904
|
2
|
50
|
|
|
|
6
|
$self->{SETTINGS}{ignore_unrecognized} = $value ? 1 : 0; |
905
|
|
|
|
|
|
|
} |
906
|
|
|
|
|
|
|
|
907
|
|
|
|
|
|
|
elsif ( $ERROR_MSG{$key} ) |
908
|
|
|
|
|
|
|
{ |
909
|
24
|
|
|
|
|
50
|
$self->{SETTINGS}{$key} = $value; |
910
|
|
|
|
|
|
|
} |
911
|
|
|
|
|
|
|
|
912
|
|
|
|
|
|
|
else |
913
|
|
|
|
|
|
|
{ |
914
|
3
|
|
|
|
|
404
|
croak "unrecognized setting: '$key'"; |
915
|
|
|
|
|
|
|
} |
916
|
|
|
|
|
|
|
} |
917
|
|
|
|
|
|
|
|
918
|
12
|
|
|
|
|
14
|
return 1; |
919
|
|
|
|
|
|
|
} |
920
|
|
|
|
|
|
|
|
921
|
|
|
|
|
|
|
|
922
|
|
|
|
|
|
|
=head3 ruleset_defined |
923
|
|
|
|
|
|
|
|
924
|
|
|
|
|
|
|
if ( ruleset_defined($ruleset_name) ) { |
925
|
|
|
|
|
|
|
# then do something |
926
|
|
|
|
|
|
|
} |
927
|
|
|
|
|
|
|
|
928
|
|
|
|
|
|
|
This function returns true if a ruleset has been defined with the given name, |
929
|
|
|
|
|
|
|
false otherwise. |
930
|
|
|
|
|
|
|
|
931
|
|
|
|
|
|
|
=cut |
932
|
|
|
|
|
|
|
|
933
|
|
|
|
|
|
|
sub ruleset_defined { |
934
|
|
|
|
|
|
|
|
935
|
|
|
|
|
|
|
# If we were called as a method, use the object on which we were called. |
936
|
|
|
|
|
|
|
# Otherwise, use the globally defined one. |
937
|
|
|
|
|
|
|
|
938
|
2
|
50
|
|
2
|
1
|
753
|
my $self = ref $_[0] eq 'HTTP::Validate' ? shift : $DEFAULT_INSTANCE; |
939
|
|
|
|
|
|
|
|
940
|
2
|
|
|
|
|
3
|
my ($ruleset_name) = @_; |
941
|
|
|
|
|
|
|
|
942
|
|
|
|
|
|
|
# Return the requested result |
943
|
|
|
|
|
|
|
|
944
|
2
|
|
|
|
|
6
|
return defined $self->{RULESETS}{$ruleset_name}; |
945
|
|
|
|
|
|
|
} |
946
|
|
|
|
|
|
|
|
947
|
|
|
|
|
|
|
|
948
|
|
|
|
|
|
|
=head3 document_params |
949
|
|
|
|
|
|
|
|
950
|
|
|
|
|
|
|
This function generates L for the given |
951
|
|
|
|
|
|
|
ruleset, in L format. This only works if you have included |
952
|
|
|
|
|
|
|
documentation strings in your calls to L. The method returns |
953
|
|
|
|
|
|
|
I if the specified ruleset is not found. |
954
|
|
|
|
|
|
|
|
955
|
|
|
|
|
|
|
$my_doc = document_params($ruleset_name); |
956
|
|
|
|
|
|
|
|
957
|
|
|
|
|
|
|
This capability has been included in order to simplify the process of |
958
|
|
|
|
|
|
|
documenting web services implemented using this module. The author has |
959
|
|
|
|
|
|
|
noticed that documentation is much easier to maintain and more likely to be |
960
|
|
|
|
|
|
|
kept up-to-date if the documentation strings are located right next to the |
961
|
|
|
|
|
|
|
relevant definitions. |
962
|
|
|
|
|
|
|
|
963
|
|
|
|
|
|
|
Any parameter rules that you wish to leave undocumented should either be given |
964
|
|
|
|
|
|
|
the attribute 'undocumented' or be immediately followed by a string starting |
965
|
|
|
|
|
|
|
with "!". All others will automatically generate list items in the resulting |
966
|
|
|
|
|
|
|
documentation, even if no documentation string is provided (in this case, the |
967
|
|
|
|
|
|
|
item body will be empty). |
968
|
|
|
|
|
|
|
|
969
|
|
|
|
|
|
|
=cut |
970
|
|
|
|
|
|
|
|
971
|
|
|
|
|
|
|
sub document_params { |
972
|
|
|
|
|
|
|
|
973
|
|
|
|
|
|
|
# If we were called as a method, use the object on which we were called. |
974
|
|
|
|
|
|
|
# Otherwise, use the globally defined instance. |
975
|
|
|
|
|
|
|
|
976
|
4
|
50
|
|
4
|
1
|
632
|
my $self = ref $_[0] eq 'HTTP::Validate' ? shift : $DEFAULT_INSTANCE; |
977
|
|
|
|
|
|
|
|
978
|
4
|
|
|
|
|
5
|
my ($ruleset_name) = @_; |
979
|
|
|
|
|
|
|
|
980
|
|
|
|
|
|
|
# Make sure we have a valid ruleset, or else return false. |
981
|
|
|
|
|
|
|
|
982
|
4
|
50
|
|
|
|
10
|
return unless defined $ruleset_name; |
983
|
|
|
|
|
|
|
|
984
|
4
|
|
|
|
|
4
|
my $rs = $self->{RULESETS}{$ruleset_name}; |
985
|
4
|
50
|
|
|
|
7
|
return unless $rs; |
986
|
|
|
|
|
|
|
|
987
|
|
|
|
|
|
|
# Now generate the requested documentation. |
988
|
|
|
|
|
|
|
|
989
|
4
|
|
|
|
|
17
|
return $self->generate_docstring($rs, { in_list => 0, level => 0, processed => {} }); |
990
|
|
|
|
|
|
|
} |
991
|
|
|
|
|
|
|
|
992
|
|
|
|
|
|
|
|
993
|
|
|
|
|
|
|
=head3 list_params |
994
|
|
|
|
|
|
|
|
995
|
|
|
|
|
|
|
This function returns a list of the names of all parameters accepted by the |
996
|
|
|
|
|
|
|
specified ruleset, including those accepted by included rulesets. |
997
|
|
|
|
|
|
|
|
998
|
|
|
|
|
|
|
my @parameter_names = list_ruleset_params($ruleset_name); |
999
|
|
|
|
|
|
|
|
1000
|
|
|
|
|
|
|
This may be useful if your validations allow unrecognized parameters, as it |
1001
|
|
|
|
|
|
|
enables you to determine which of the parameters in a given request are |
1002
|
|
|
|
|
|
|
significant to that request. |
1003
|
|
|
|
|
|
|
|
1004
|
|
|
|
|
|
|
=cut |
1005
|
|
|
|
|
|
|
|
1006
|
|
|
|
|
|
|
sub list_params { |
1007
|
|
|
|
|
|
|
|
1008
|
|
|
|
|
|
|
# If we were called as a method, use the object on which we were called. |
1009
|
|
|
|
|
|
|
# Otherwise, use the globally defined instance. |
1010
|
|
|
|
|
|
|
|
1011
|
1
|
50
|
|
1
|
1
|
5
|
my $self = ref $_[0] eq 'HTTP::Validate' ? shift : $DEFAULT_INSTANCE; |
1012
|
|
|
|
|
|
|
|
1013
|
1
|
|
|
|
|
2
|
my ($ruleset_name) = @_; |
1014
|
|
|
|
|
|
|
|
1015
|
|
|
|
|
|
|
# Make sure we have a valid ruleset, or else return false. |
1016
|
|
|
|
|
|
|
|
1017
|
1
|
50
|
|
|
|
3
|
return unless defined $ruleset_name; |
1018
|
|
|
|
|
|
|
|
1019
|
1
|
|
|
|
|
2
|
my $rs = $self->{RULESETS}{$ruleset_name}; |
1020
|
1
|
50
|
|
|
|
3
|
return unless $rs; |
1021
|
|
|
|
|
|
|
|
1022
|
|
|
|
|
|
|
# Now generate the requested list. |
1023
|
|
|
|
|
|
|
|
1024
|
1
|
|
|
|
|
3
|
return $self->generate_param_list($ruleset_name); |
1025
|
|
|
|
|
|
|
} |
1026
|
|
|
|
|
|
|
|
1027
|
|
|
|
|
|
|
|
1028
|
|
|
|
|
|
|
# Here are the implementing functions: |
1029
|
|
|
|
|
|
|
# ==================================== |
1030
|
|
|
|
|
|
|
|
1031
|
|
|
|
|
|
|
# create_ruleset ( ruleset_name, filename, line ) |
1032
|
|
|
|
|
|
|
# |
1033
|
|
|
|
|
|
|
# Create a new ruleset with the given name, noting that it was defined in the |
1034
|
|
|
|
|
|
|
# given filename at the given line number. |
1035
|
|
|
|
|
|
|
|
1036
|
|
|
|
|
|
|
sub create_ruleset { |
1037
|
|
|
|
|
|
|
|
1038
|
74
|
|
|
74
|
0
|
77
|
my ($validator, $ruleset_name, $filename, $line_no) = @_; |
1039
|
|
|
|
|
|
|
|
1040
|
|
|
|
|
|
|
# Make sure that a non-empty name was given, and that no ruleset has |
1041
|
|
|
|
|
|
|
# already been defined under that name. |
1042
|
|
|
|
|
|
|
|
1043
|
74
|
50
|
|
|
|
110
|
croak "you must provide a non-empty name for the ruleset" if $ruleset_name eq ''; |
1044
|
|
|
|
|
|
|
|
1045
|
74
|
100
|
|
|
|
142
|
if ( exists $validator->{RULESETS}{$ruleset_name} ) |
1046
|
|
|
|
|
|
|
{ |
1047
|
2
|
|
|
|
|
3
|
my $filename = $validator->{RULESETS}{$ruleset_name}{filename}; |
1048
|
2
|
|
|
|
|
2
|
my $line_no = $validator->{RULESETS}{$ruleset_name}{line_no}; |
1049
|
2
|
|
|
|
|
166
|
croak "ruleset '$ruleset_name' was already defined at line $line_no of $filename\n"; |
1050
|
|
|
|
|
|
|
} |
1051
|
|
|
|
|
|
|
|
1052
|
|
|
|
|
|
|
# Create the new ruleset. |
1053
|
|
|
|
|
|
|
|
1054
|
72
|
|
|
|
|
361
|
my $rs = { name => $ruleset_name, |
1055
|
|
|
|
|
|
|
filename => $filename, |
1056
|
|
|
|
|
|
|
line_no => $line_no, |
1057
|
|
|
|
|
|
|
doc_items => [], |
1058
|
|
|
|
|
|
|
fulfill_order => [], |
1059
|
|
|
|
|
|
|
params => {}, |
1060
|
|
|
|
|
|
|
includes => {}, |
1061
|
|
|
|
|
|
|
rules => [] }; |
1062
|
|
|
|
|
|
|
|
1063
|
72
|
|
|
|
|
158
|
return bless $rs, 'HTTP::Validate::Ruleset'; |
1064
|
|
|
|
|
|
|
} |
1065
|
|
|
|
|
|
|
|
1066
|
|
|
|
|
|
|
|
1067
|
|
|
|
|
|
|
# List all of the keys that are allowed in rule specifications. Those whose |
1068
|
|
|
|
|
|
|
# value is 2 indicate the rule type, and at most one of these may be included |
1069
|
|
|
|
|
|
|
# per rule. The others are optional. |
1070
|
|
|
|
|
|
|
|
1071
|
|
|
|
|
|
|
my %DIRECTIVE = ( 'param' => 2, 'optional' => 2, 'mandatory' => 2, |
1072
|
|
|
|
|
|
|
'together' => 2, 'at_most_one' => 2, 'ignore' => 2, |
1073
|
|
|
|
|
|
|
'require' => 2, 'allow' => 2, 'require_one' => 2, |
1074
|
|
|
|
|
|
|
'require_any' => 2, 'allow_one' => 2, 'content_type' => 2, |
1075
|
|
|
|
|
|
|
'valid' => 1, 'clean' => 1, |
1076
|
|
|
|
|
|
|
'multiple' => 1, 'split' => 1, 'list' => 1, 'bad_value' => 1, |
1077
|
|
|
|
|
|
|
'error' => 1, 'errmsg' => 1, 'warn' => 1, 'undocumented' => 1, |
1078
|
|
|
|
|
|
|
'alias' => 1, 'key' => 1, 'default' => 1); |
1079
|
|
|
|
|
|
|
|
1080
|
|
|
|
|
|
|
# Categorize the rule types |
1081
|
|
|
|
|
|
|
|
1082
|
|
|
|
|
|
|
my %CATEGORY = ( 'param' => 'param', |
1083
|
|
|
|
|
|
|
'optional' => 'param', |
1084
|
|
|
|
|
|
|
'mandatory' => 'param', |
1085
|
|
|
|
|
|
|
'together' => 'modifier', |
1086
|
|
|
|
|
|
|
'at_most_one' => 'modifier', |
1087
|
|
|
|
|
|
|
'ignore' => 'modifier', |
1088
|
|
|
|
|
|
|
'require' => 'include', |
1089
|
|
|
|
|
|
|
'allow' => 'include', |
1090
|
|
|
|
|
|
|
'require_one' => 'constraint', |
1091
|
|
|
|
|
|
|
'allow_one' => 'constraint', |
1092
|
|
|
|
|
|
|
'require_any' => 'constraint', |
1093
|
|
|
|
|
|
|
'content_type' => 'content' ); |
1094
|
|
|
|
|
|
|
|
1095
|
|
|
|
|
|
|
# List the special validators. |
1096
|
|
|
|
|
|
|
|
1097
|
|
|
|
|
|
|
my (%VALIDATOR_DEF) = ( 'FLAG_VALUE' => 1, 'ANY_VALUE' => 1 ); |
1098
|
|
|
|
|
|
|
|
1099
|
|
|
|
|
|
|
my (%CLEANER_DEF) = ( 'uc' => eval 'sub { return uc $_[0] }', |
1100
|
|
|
|
|
|
|
'lc' => eval 'sub { return lc $_[0] }', |
1101
|
|
|
|
|
|
|
'fc' => $case_fold ); |
1102
|
|
|
|
|
|
|
|
1103
|
|
|
|
|
|
|
# add_rules ( ruleset, rule ... ) |
1104
|
|
|
|
|
|
|
# |
1105
|
|
|
|
|
|
|
# Add rules to the specified ruleset. The rules may be optionally |
1106
|
|
|
|
|
|
|
# interspersed with documentation strings. |
1107
|
|
|
|
|
|
|
|
1108
|
|
|
|
|
|
|
sub add_rules { |
1109
|
|
|
|
|
|
|
|
1110
|
72
|
|
|
72
|
0
|
65
|
my ($self) = shift; |
1111
|
72
|
|
|
|
|
77
|
my ($rs) = shift; |
1112
|
|
|
|
|
|
|
|
1113
|
72
|
|
|
|
|
73
|
my @doc_lines; # collect up documentation strings until we know how to apply them |
1114
|
|
|
|
|
|
|
my $doc_rule; # the rule to which all new documentation strings should be added |
1115
|
|
|
|
|
|
|
|
1116
|
|
|
|
|
|
|
# Go through the items in @_, one by one. |
1117
|
|
|
|
|
|
|
|
1118
|
|
|
|
|
|
|
RULE: |
1119
|
72
|
|
|
|
|
98
|
foreach my $rule (@_) |
1120
|
|
|
|
|
|
|
{ |
1121
|
|
|
|
|
|
|
# If the item is a scalar, then it is a documentation string. |
1122
|
|
|
|
|
|
|
|
1123
|
200
|
100
|
|
|
|
516
|
unless ( ref $rule ) |
|
|
50
|
|
|
|
|
|
1124
|
|
|
|
|
|
|
{ |
1125
|
|
|
|
|
|
|
# If the string starts with >, !, ^, or ? then treat it specially. |
1126
|
|
|
|
|
|
|
|
1127
|
16
|
100
|
|
|
|
74
|
if ( $rule =~ qr{ ^ ([!^?] | >>?) (.*) }xs ) |
1128
|
|
|
|
|
|
|
{ |
1129
|
|
|
|
|
|
|
# If >>, then close the active documentation section (if any) |
1130
|
|
|
|
|
|
|
# and start a new one that is not tied to any rule. This will |
1131
|
|
|
|
|
|
|
# generate an ordinary paragraph starting with the remainder |
1132
|
|
|
|
|
|
|
# of the line. |
1133
|
|
|
|
|
|
|
|
1134
|
5
|
100
|
|
|
|
17
|
if ( $1 eq '>>' ) |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
1135
|
|
|
|
|
|
|
{ |
1136
|
1
|
50
|
33
|
|
|
8
|
$self->add_doc($rs, $doc_rule, @doc_lines) if $doc_rule || @doc_lines; |
1137
|
1
|
|
|
|
|
4
|
@doc_lines = $2; |
1138
|
1
|
|
|
|
|
1
|
$doc_rule = undef; |
1139
|
|
|
|
|
|
|
} |
1140
|
|
|
|
|
|
|
|
1141
|
|
|
|
|
|
|
# If >, then add to the current documentation a blank line |
1142
|
|
|
|
|
|
|
# (which will cause a new paragraph) followed by the remainder |
1143
|
|
|
|
|
|
|
# of this line. |
1144
|
|
|
|
|
|
|
|
1145
|
|
|
|
|
|
|
elsif ( $1 eq '>' ) |
1146
|
|
|
|
|
|
|
{ |
1147
|
1
|
|
|
|
|
1
|
push @doc_lines, "", $2; |
1148
|
|
|
|
|
|
|
} |
1149
|
|
|
|
|
|
|
|
1150
|
|
|
|
|
|
|
# If !, then discard the contents of the current documentation |
1151
|
|
|
|
|
|
|
# section and replace them with this line (including the ! |
1152
|
|
|
|
|
|
|
# character). This will cause add_doc to later discard them. |
1153
|
|
|
|
|
|
|
|
1154
|
|
|
|
|
|
|
elsif ( $1 eq '!' ) |
1155
|
|
|
|
|
|
|
{ |
1156
|
1
|
|
|
|
|
2
|
@doc_lines = $rule; |
1157
|
|
|
|
|
|
|
} |
1158
|
|
|
|
|
|
|
|
1159
|
|
|
|
|
|
|
# If ^, then discard the contents of the current documentation |
1160
|
|
|
|
|
|
|
# section and replace them with the remainder of the line. |
1161
|
|
|
|
|
|
|
# Set $doc_rule to undef, which will cause the rule currently |
1162
|
|
|
|
|
|
|
# being documented to be forgotten and the documentation to be |
1163
|
|
|
|
|
|
|
# added as an ordinary paragraph instead. |
1164
|
|
|
|
|
|
|
|
1165
|
|
|
|
|
|
|
elsif ( $1 eq '^' ) |
1166
|
|
|
|
|
|
|
{ |
1167
|
1
|
|
|
|
|
2
|
@doc_lines = $2; |
1168
|
1
|
|
|
|
|
2
|
$doc_rule = undef; |
1169
|
|
|
|
|
|
|
} |
1170
|
|
|
|
|
|
|
|
1171
|
|
|
|
|
|
|
# If ?, then add the remainder of the line to the current |
1172
|
|
|
|
|
|
|
# documentation section. This will prevent the next character |
1173
|
|
|
|
|
|
|
# from being interpreted specially. |
1174
|
|
|
|
|
|
|
|
1175
|
|
|
|
|
|
|
else |
1176
|
|
|
|
|
|
|
{ |
1177
|
1
|
|
|
|
|
2
|
push @doc_lines, $2; |
1178
|
|
|
|
|
|
|
} |
1179
|
|
|
|
|
|
|
} |
1180
|
|
|
|
|
|
|
|
1181
|
|
|
|
|
|
|
# Otherwise, just add this string to the current documentation section. |
1182
|
|
|
|
|
|
|
|
1183
|
|
|
|
|
|
|
else |
1184
|
|
|
|
|
|
|
{ |
1185
|
11
|
|
|
|
|
13
|
push @doc_lines, $rule; |
1186
|
|
|
|
|
|
|
} |
1187
|
|
|
|
|
|
|
|
1188
|
16
|
|
|
|
|
21
|
next RULE; |
1189
|
|
|
|
|
|
|
} |
1190
|
|
|
|
|
|
|
|
1191
|
|
|
|
|
|
|
# All other items must be hashrefs, otherwise throw an exception. |
1192
|
|
|
|
|
|
|
|
1193
|
|
|
|
|
|
|
elsif ( reftype $rule ne 'HASH' ) |
1194
|
|
|
|
|
|
|
{ |
1195
|
0
|
|
|
|
|
0
|
croak "The arguments to 'define_ruleset' must all be hashrefs and/or strings"; |
1196
|
|
|
|
|
|
|
} |
1197
|
|
|
|
|
|
|
|
1198
|
|
|
|
|
|
|
# If we get here, assume the item represents a rule and create a new record to |
1199
|
|
|
|
|
|
|
# represent it. |
1200
|
|
|
|
|
|
|
|
1201
|
184
|
|
|
|
|
129
|
my $rr = { rs => $rs, rn => scalar(@{$rs->{rules}}) + 1 }; |
|
184
|
|
|
|
|
363
|
|
1202
|
184
|
|
|
|
|
123
|
push @{$rs->{rules}}, $rr; |
|
184
|
|
|
|
|
208
|
|
1203
|
|
|
|
|
|
|
|
1204
|
184
|
|
|
|
|
281
|
weaken($rr->{rs}); |
1205
|
|
|
|
|
|
|
|
1206
|
|
|
|
|
|
|
# Check all of the keys in the rule definition, making sure that all |
1207
|
|
|
|
|
|
|
# are valid, and determine the rule type. |
1208
|
|
|
|
|
|
|
|
1209
|
184
|
|
|
|
|
113
|
my $type; |
1210
|
|
|
|
|
|
|
|
1211
|
|
|
|
|
|
|
KEY: |
1212
|
184
|
|
|
|
|
333
|
foreach my $key (keys %$rule) |
1213
|
|
|
|
|
|
|
{ |
1214
|
325
|
100
|
66
|
|
|
588
|
croak "unknown attribute '$key' found in rule" unless $DIRECTIVE{$key} || $ERROR_MSG{$key}; |
1215
|
|
|
|
|
|
|
|
1216
|
323
|
100
|
100
|
|
|
885
|
if ( defined $DIRECTIVE{$key} && $DIRECTIVE{$key} == 2 ) |
1217
|
|
|
|
|
|
|
{ |
1218
|
184
|
100
|
|
|
|
309
|
croak "a rule definition cannot contain the attributes '$key' and '$type' together, because they indicate different rule types" |
1219
|
|
|
|
|
|
|
if $type; |
1220
|
183
|
|
|
|
|
146
|
$type = $key; |
1221
|
183
|
|
|
|
|
179
|
$rr->{$type} = $rule->{$type}; |
1222
|
183
|
|
|
|
|
202
|
next KEY; |
1223
|
|
|
|
|
|
|
} |
1224
|
|
|
|
|
|
|
} |
1225
|
|
|
|
|
|
|
|
1226
|
|
|
|
|
|
|
# Then process the other keys. |
1227
|
|
|
|
|
|
|
|
1228
|
181
|
|
|
|
|
243
|
foreach my $key (keys %$rule) |
1229
|
|
|
|
|
|
|
{ |
1230
|
320
|
|
|
|
|
244
|
my $value = $rule->{$key}; |
1231
|
|
|
|
|
|
|
|
1232
|
320
|
100
|
100
|
|
|
1520
|
if ( $key eq 'valid' ) |
|
|
100
|
66
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
1233
|
|
|
|
|
|
|
{ |
1234
|
|
|
|
|
|
|
croak "the attribute 'valid' is only allowed with parameter rules" |
1235
|
95
|
50
|
66
|
|
|
205
|
unless $CATEGORY{$type} eq 'param' || $type eq 'content_type'; |
1236
|
|
|
|
|
|
|
} |
1237
|
|
|
|
|
|
|
|
1238
|
|
|
|
|
|
|
elsif ( $key eq 'alias' ) |
1239
|
|
|
|
|
|
|
{ |
1240
|
|
|
|
|
|
|
croak "the attribute 'alias' is only allowed with parameter rules" |
1241
|
3
|
50
|
|
|
|
9
|
unless $CATEGORY{$type} eq 'param'; |
1242
|
|
|
|
|
|
|
|
1243
|
3
|
50
|
66
|
|
|
15
|
croak "the value of 'alias' must be a string or a list ref" |
1244
|
|
|
|
|
|
|
if ref $value and ref $value ne 'ARRAY'; |
1245
|
|
|
|
|
|
|
|
1246
|
3
|
100
|
|
|
|
9
|
$rr->{alias} = ref $value ? $value : [ $value ]; |
1247
|
|
|
|
|
|
|
} |
1248
|
|
|
|
|
|
|
|
1249
|
|
|
|
|
|
|
elsif ( $key eq 'clean' ) |
1250
|
|
|
|
|
|
|
{ |
1251
|
|
|
|
|
|
|
croak "they attribute 'clean' is only allowed with parameter rules" |
1252
|
4
|
50
|
|
|
|
7
|
unless $CATEGORY{$type} eq 'param'; |
1253
|
|
|
|
|
|
|
|
1254
|
4
|
|
66
|
|
|
12
|
$rr->{cleaner} = $CLEANER_DEF{$value} || $value; |
1255
|
|
|
|
|
|
|
|
1256
|
|
|
|
|
|
|
croak "invalid value '$value' for 'clean'" |
1257
|
4
|
50
|
|
|
|
9
|
unless ref $rr->{cleaner} eq 'CODE'; |
1258
|
|
|
|
|
|
|
} |
1259
|
|
|
|
|
|
|
|
1260
|
|
|
|
|
|
|
elsif ( $key eq 'default' ) |
1261
|
|
|
|
|
|
|
{ |
1262
|
|
|
|
|
|
|
croak "the attribute 'default' is only allowed with parameter rules" |
1263
|
3
|
50
|
|
|
|
13
|
unless $CATEGORY{$type} eq 'param'; |
1264
|
|
|
|
|
|
|
|
1265
|
3
|
|
|
|
|
8
|
$rr->{default} = $value; |
1266
|
|
|
|
|
|
|
} |
1267
|
|
|
|
|
|
|
|
1268
|
|
|
|
|
|
|
elsif ( $key eq 'split' || $key eq 'list' ) |
1269
|
|
|
|
|
|
|
{ |
1270
|
|
|
|
|
|
|
croak "the attribute '$key' is only allowed with parameter rules" |
1271
|
8
|
50
|
|
|
|
13
|
unless $CATEGORY{$type} eq 'param'; |
1272
|
|
|
|
|
|
|
|
1273
|
8
|
50
|
66
|
|
|
23
|
croak "the value of '$key' must be a string or a regexp" |
1274
|
|
|
|
|
|
|
if ref $value and ref $value ne 'Regexp'; |
1275
|
|
|
|
|
|
|
|
1276
|
8
|
|
|
|
|
9
|
$rr->{multiple} = 1; |
1277
|
|
|
|
|
|
|
|
1278
|
|
|
|
|
|
|
# Make sure that we have a proper regular expression. If 'split' |
1279
|
|
|
|
|
|
|
# was given with a string, surround it by \s* to ignore |
1280
|
|
|
|
|
|
|
# whitespace. |
1281
|
|
|
|
|
|
|
|
1282
|
8
|
100
|
|
|
|
15
|
unless ( ref $value ) |
1283
|
|
|
|
|
|
|
{ |
1284
|
7
|
|
|
|
|
80
|
$value = qr{ \s* $value \s* }oxs; |
1285
|
|
|
|
|
|
|
} |
1286
|
|
|
|
|
|
|
|
1287
|
8
|
|
|
|
|
11
|
$rr->{split} = $value; |
1288
|
8
|
100
|
|
|
|
26
|
$rr->{warn} = 1 if $key eq 'list'; |
1289
|
|
|
|
|
|
|
} |
1290
|
|
|
|
|
|
|
|
1291
|
|
|
|
|
|
|
elsif ( $key eq 'error' || $key eq 'errmsg' ) |
1292
|
|
|
|
|
|
|
{ |
1293
|
7
|
|
|
|
|
7
|
$rr->{errmsg} = $value; |
1294
|
|
|
|
|
|
|
} |
1295
|
|
|
|
|
|
|
|
1296
|
|
|
|
|
|
|
elsif ( $key ne $type ) |
1297
|
|
|
|
|
|
|
{ |
1298
|
19
|
50
|
|
|
|
28
|
croak "the value of '$key' must be a string" if ref $value; |
1299
|
|
|
|
|
|
|
|
1300
|
19
|
|
|
|
|
32
|
$rr->{$key} = $value; |
1301
|
|
|
|
|
|
|
} |
1302
|
|
|
|
|
|
|
} |
1303
|
|
|
|
|
|
|
|
1304
|
181
|
50
|
|
|
|
232
|
croak "each record must include a key that specifies the rule type, e.g. 'param' or 'allow'" |
1305
|
|
|
|
|
|
|
unless $type; |
1306
|
|
|
|
|
|
|
|
1307
|
|
|
|
|
|
|
# If we have any documentation strings collected up, then they belong to the previous |
1308
|
|
|
|
|
|
|
# rule. If the current rule is a parameter rule, then add the collected documentation to |
1309
|
|
|
|
|
|
|
# the previous rule and set this new rule as the target for subsequent documentation. |
1310
|
|
|
|
|
|
|
|
1311
|
181
|
100
|
|
|
|
257
|
if ( $CATEGORY{$type} ne 'modifier' ) |
1312
|
|
|
|
|
|
|
{ |
1313
|
176
|
|
|
|
|
229
|
$self->add_doc($rs, $doc_rule, @doc_lines); |
1314
|
176
|
|
|
|
|
151
|
$doc_rule = $rr; |
1315
|
176
|
|
|
|
|
184
|
@doc_lines = (); |
1316
|
|
|
|
|
|
|
} |
1317
|
|
|
|
|
|
|
|
1318
|
|
|
|
|
|
|
# If the previous rule is an 'include' or 'constraint' rule, then any subsequent |
1319
|
|
|
|
|
|
|
# documentation should become an ordinary paragraph; so set $doc_rule to undefined. If |
1320
|
|
|
|
|
|
|
# the previous rule is a 'modifier' rule, and if $doc_rule is not empty, then its |
1321
|
|
|
|
|
|
|
# documentation should be added to that previously encountered parameter rule. |
1322
|
|
|
|
|
|
|
|
1323
|
|
|
|
|
|
|
# elsif ( $CATEGORY{$type} ne 'modifier' ) |
1324
|
|
|
|
|
|
|
# { |
1325
|
|
|
|
|
|
|
# $self->add_doc($rs, $doc_rule); |
1326
|
|
|
|
|
|
|
# $self->add_doc($rs, undef, @doc_lines); |
1327
|
|
|
|
|
|
|
# $doc_rule = undef; |
1328
|
|
|
|
|
|
|
# @doc_lines = (); |
1329
|
|
|
|
|
|
|
# } |
1330
|
|
|
|
|
|
|
|
1331
|
|
|
|
|
|
|
# Now process the rule according to its type. |
1332
|
|
|
|
|
|
|
|
1333
|
181
|
|
|
|
|
147
|
my $typevalue = $rule->{$type}; |
1334
|
|
|
|
|
|
|
|
1335
|
181
|
100
|
|
|
|
284
|
if ( $CATEGORY{$type} eq 'param' ) |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
1336
|
|
|
|
|
|
|
{ |
1337
|
131
|
|
|
|
|
132
|
$rr->{type} = 'param'; |
1338
|
131
|
|
|
|
|
106
|
$rr->{param} = $typevalue; |
1339
|
|
|
|
|
|
|
|
1340
|
|
|
|
|
|
|
# Do some basic sanity checking. |
1341
|
|
|
|
|
|
|
|
1342
|
131
|
100
|
66
|
|
|
650
|
croak "the value of '$type' must be a parameter name" |
|
|
|
66
|
|
|
|
|
1343
|
|
|
|
|
|
|
unless defined $typevalue && !ref $typevalue && $typevalue ne ''; |
1344
|
|
|
|
|
|
|
|
1345
|
|
|
|
|
|
|
# Check the validators. |
1346
|
|
|
|
|
|
|
|
1347
|
130
|
100
|
|
|
|
229
|
my @validators = ref $rule->{valid} eq 'ARRAY' ? @{$rule->{valid}} : $rule->{valid}; |
|
3
|
|
|
|
|
6
|
|
1348
|
|
|
|
|
|
|
|
1349
|
130
|
|
|
|
|
125
|
foreach my $v (@validators) |
1350
|
|
|
|
|
|
|
{ |
1351
|
132
|
100
|
66
|
|
|
353
|
if ( defined $v && $VALIDATOR_DEF{$v} ) |
|
|
100
|
|
|
|
|
|
1352
|
|
|
|
|
|
|
{ |
1353
|
6
|
100
|
|
|
|
11
|
$rr->{flag} = 1 if $v eq 'FLAG_VALUE'; |
1354
|
6
|
100
|
|
|
|
17
|
push @{$rr->{validators}}, \&boolean_value if $v eq 'FLAG_VALUE'; |
|
2
|
|
|
|
|
6
|
|
1355
|
|
|
|
|
|
|
} |
1356
|
|
|
|
|
|
|
|
1357
|
|
|
|
|
|
|
elsif ( defined $v ) |
1358
|
|
|
|
|
|
|
{ |
1359
|
87
|
100
|
100
|
|
|
446
|
croak "invalid validator '$v': must be a code ref" |
1360
|
|
|
|
|
|
|
unless ref $v && reftype $v eq 'CODE'; |
1361
|
|
|
|
|
|
|
|
1362
|
85
|
|
|
|
|
46
|
push @{$rr->{validators}}, $v; |
|
85
|
|
|
|
|
169
|
|
1363
|
|
|
|
|
|
|
} |
1364
|
|
|
|
|
|
|
} |
1365
|
|
|
|
|
|
|
|
1366
|
128
|
100
|
100
|
|
|
344
|
$rr->{$type} = 1 if $type eq 'optional' || $type eq 'mandatory'; |
1367
|
|
|
|
|
|
|
|
1368
|
128
|
100
|
|
|
|
162
|
if ( $type ne 'optional' ) |
1369
|
|
|
|
|
|
|
{ |
1370
|
104
|
50
|
|
|
|
149
|
push @{$rs->{fulfill_order}}, $typevalue unless $rs->{params}{$typevalue}; |
|
104
|
|
|
|
|
126
|
|
1371
|
|
|
|
|
|
|
} |
1372
|
|
|
|
|
|
|
|
1373
|
128
|
|
|
|
|
166
|
$rs->{params}{$typevalue} = 1; |
1374
|
|
|
|
|
|
|
|
1375
|
|
|
|
|
|
|
# If a default value was given, run it through all of the |
1376
|
|
|
|
|
|
|
# validators in turn until it passes one of them. Store the |
1377
|
|
|
|
|
|
|
# resulting clean value. If the default does not pass any of the |
1378
|
|
|
|
|
|
|
# validators, throw an error. |
1379
|
|
|
|
|
|
|
|
1380
|
128
|
100
|
|
|
|
240
|
if ( defined $rr->{default} ) |
1381
|
|
|
|
|
|
|
{ |
1382
|
3
|
50
|
|
|
|
8
|
croak "default value must be a scalar\n" if ref $rr->{default}; |
1383
|
|
|
|
|
|
|
|
1384
|
|
|
|
|
|
|
next RULE unless ref $rr->{validators} eq 'ARRAY' && |
1385
|
3
|
100
|
66
|
|
|
11
|
@{$rr->{validators}}; |
|
2
|
|
|
|
|
6
|
|
1386
|
|
|
|
|
|
|
|
1387
|
2
|
|
|
|
|
3
|
foreach my $v ( @{$rr->{validators}} ) |
|
2
|
|
|
|
|
3
|
|
1388
|
|
|
|
|
|
|
{ |
1389
|
2
|
|
|
|
|
5
|
my $result = $v->($rr->{default}, {}); |
1390
|
|
|
|
|
|
|
|
1391
|
2
|
50
|
|
|
|
5
|
next RULE unless defined $result; |
1392
|
|
|
|
|
|
|
|
1393
|
2
|
100
|
|
|
|
6
|
if ( exists $result->{value} ) |
1394
|
|
|
|
|
|
|
{ |
1395
|
1
|
|
|
|
|
1
|
$rr->{default} = $result->{value}; |
1396
|
1
|
50
|
|
|
|
2
|
croak "cleaned default value must be a scalar\n" if ref $rr->{default}; |
1397
|
1
|
|
|
|
|
3
|
next RULE; |
1398
|
|
|
|
|
|
|
} |
1399
|
|
|
|
|
|
|
} |
1400
|
|
|
|
|
|
|
|
1401
|
1
|
|
|
|
|
238
|
croak "the default value '$rr->{default}' failed all of the validators\n"; |
1402
|
|
|
|
|
|
|
} |
1403
|
|
|
|
|
|
|
} |
1404
|
|
|
|
|
|
|
|
1405
|
|
|
|
|
|
|
elsif ( $CATEGORY{$type} eq 'modifier' ) |
1406
|
|
|
|
|
|
|
{ |
1407
|
5
|
|
|
|
|
7
|
$rr->{type} = $type; |
1408
|
5
|
|
|
|
|
6
|
$rr->{param} = []; |
1409
|
|
|
|
|
|
|
|
1410
|
5
|
100
|
|
|
|
13
|
my @params = ref $typevalue eq 'ARRAY' ? @$typevalue : $typevalue; |
1411
|
|
|
|
|
|
|
|
1412
|
5
|
|
|
|
|
9
|
foreach my $arg (@params) |
1413
|
|
|
|
|
|
|
{ |
1414
|
|
|
|
|
|
|
# croak "parameter '$arg' was not defined" unless defined |
1415
|
|
|
|
|
|
|
# $rs->{params}{$arg} || $type eq 'ignore'; |
1416
|
9
|
|
|
|
|
3
|
push @{$rr->{param}}, $arg; |
|
9
|
|
|
|
|
14
|
|
1417
|
|
|
|
|
|
|
} |
1418
|
|
|
|
|
|
|
|
1419
|
|
|
|
|
|
|
croak "a rule of type '$type' requires at least one parameter name" |
1420
|
5
|
50
|
|
|
|
5
|
unless @{$rr->{param}} > 0; |
|
5
|
|
|
|
|
15
|
|
1421
|
|
|
|
|
|
|
} |
1422
|
|
|
|
|
|
|
|
1423
|
|
|
|
|
|
|
elsif ( $CATEGORY{$type} eq 'include' ) |
1424
|
|
|
|
|
|
|
{ |
1425
|
31
|
|
|
|
|
32
|
$rr->{type} = 'include'; |
1426
|
31
|
100
|
|
|
|
52
|
$rr->{require} = 1 if $type eq 'require'; |
1427
|
31
|
|
|
|
|
47
|
$rr->{ruleset} = $typevalue; |
1428
|
|
|
|
|
|
|
|
1429
|
31
|
100
|
100
|
|
|
320
|
croak "the value of '$type' must be a ruleset name" |
|
|
|
66
|
|
|
|
|
1430
|
|
|
|
|
|
|
unless defined $typevalue && !ref $typevalue && $typevalue ne ''; |
1431
|
|
|
|
|
|
|
|
1432
|
29
|
100
|
|
|
|
124
|
croak "ruleset '$typevalue' not found" unless defined $self->{RULESETS}{$typevalue}; |
1433
|
|
|
|
|
|
|
|
1434
|
28
|
|
|
|
|
67
|
$rs->{includes}{$typevalue} = 1; |
1435
|
|
|
|
|
|
|
} |
1436
|
|
|
|
|
|
|
|
1437
|
|
|
|
|
|
|
elsif ( $CATEGORY{$type} eq 'constraint' ) |
1438
|
|
|
|
|
|
|
{ |
1439
|
10
|
|
|
|
|
13
|
$rr->{type} = 'constraint'; |
1440
|
10
|
|
|
|
|
8
|
$rr->{constraint} = $type; |
1441
|
10
|
|
|
|
|
17
|
$rr->{ruleset} = []; |
1442
|
|
|
|
|
|
|
|
1443
|
10
|
50
|
33
|
|
|
40
|
croak "the value of '$type' must be a list of ruleset names" |
1444
|
|
|
|
|
|
|
unless defined $typevalue && ref $typevalue eq 'ARRAY'; |
1445
|
|
|
|
|
|
|
|
1446
|
10
|
|
|
|
|
12
|
foreach my $arg (@$typevalue) |
1447
|
|
|
|
|
|
|
{ |
1448
|
20
|
50
|
33
|
|
|
56
|
next unless defined $arg && $arg ne ''; |
1449
|
|
|
|
|
|
|
|
1450
|
20
|
50
|
|
|
|
34
|
croak "ruleset '$arg' was not included by any rule" unless defined $rs->{includes}{$arg}; |
1451
|
20
|
|
|
|
|
11
|
push @{$rr->{ruleset}}, $arg; |
|
20
|
|
|
|
|
30
|
|
1452
|
|
|
|
|
|
|
} |
1453
|
|
|
|
|
|
|
|
1454
|
|
|
|
|
|
|
croak "a rule of type '$type' requires at least one ruleset name" |
1455
|
10
|
50
|
|
|
|
19
|
unless @{$rr->{ruleset}} > 0; |
|
10
|
|
|
|
|
34
|
|
1456
|
|
|
|
|
|
|
} |
1457
|
|
|
|
|
|
|
|
1458
|
|
|
|
|
|
|
elsif ( $type eq 'content_type' ) |
1459
|
|
|
|
|
|
|
{ |
1460
|
4
|
|
|
|
|
7
|
$rr->{type} = 'content_type'; |
1461
|
4
|
|
|
|
|
7
|
$rr->{param} = $typevalue; |
1462
|
|
|
|
|
|
|
|
1463
|
4
|
|
|
|
|
3
|
my %map; |
1464
|
|
|
|
|
|
|
|
1465
|
4
|
50
|
33
|
|
|
38
|
croak "invalid parameter name '$typevalue'" if ref $typevalue || $typevalue !~ /\w/; |
1466
|
|
|
|
|
|
|
|
1467
|
4
|
50
|
|
|
|
14
|
my @types = ref $rule->{valid} eq 'ARRAY' ? @{$rule->{valid}} : $rule->{valid}; |
|
4
|
|
|
|
|
12
|
|
1468
|
|
|
|
|
|
|
|
1469
|
4
|
|
|
|
|
6
|
foreach my $t (@types) |
1470
|
|
|
|
|
|
|
{ |
1471
|
10
|
50
|
|
|
|
17
|
if ( $t eq '' ) |
1472
|
|
|
|
|
|
|
{ |
1473
|
0
|
|
|
|
|
0
|
carp "ignored empty value '$t' for 'content_type'"; |
1474
|
0
|
|
|
|
|
0
|
next; |
1475
|
|
|
|
|
|
|
} |
1476
|
|
|
|
|
|
|
|
1477
|
10
|
|
|
|
|
30
|
my ($short, $long) = split /\s*=\s*/, $t; |
1478
|
10
|
|
100
|
|
|
29
|
$long ||= $MEDIA_TYPE{$short}; |
1479
|
|
|
|
|
|
|
|
1480
|
10
|
100
|
|
|
|
111
|
croak "unknown content type for '$short': you must specify a full content type with '$short=some/type'" |
1481
|
|
|
|
|
|
|
unless $long; |
1482
|
|
|
|
|
|
|
|
1483
|
9
|
50
|
|
|
|
20
|
croak "type '$short' cannot be specified twice" if defined $rr->{type_map}{$short}; |
1484
|
|
|
|
|
|
|
|
1485
|
9
|
|
|
|
|
9
|
$rr->{type_map}{$short} = $long; |
1486
|
9
|
|
|
|
|
11
|
push @{$rr->{type_list}}, $short; |
|
9
|
|
|
|
|
18
|
|
1487
|
|
|
|
|
|
|
} |
1488
|
|
|
|
|
|
|
|
1489
|
3
|
50
|
|
|
|
11
|
croak "you must specify at least one value for 'content_type'" unless $rr->{type_map}; |
1490
|
|
|
|
|
|
|
} |
1491
|
|
|
|
|
|
|
|
1492
|
|
|
|
|
|
|
else |
1493
|
|
|
|
|
|
|
{ |
1494
|
0
|
|
|
|
|
0
|
croak "invalid rule type '$type'\n"; |
1495
|
|
|
|
|
|
|
} |
1496
|
|
|
|
|
|
|
} |
1497
|
|
|
|
|
|
|
|
1498
|
|
|
|
|
|
|
# If we have documentation strings collected up, then they belong to the |
1499
|
|
|
|
|
|
|
# last-defined rule. Then call add_doc with a special parameter |
1500
|
|
|
|
|
|
|
# to close any pending lists. |
1501
|
|
|
|
|
|
|
|
1502
|
61
|
|
|
|
|
99
|
$self->add_doc($rs, $doc_rule, @doc_lines); |
1503
|
|
|
|
|
|
|
} |
1504
|
|
|
|
|
|
|
|
1505
|
|
|
|
|
|
|
|
1506
|
|
|
|
|
|
|
# add_doc ( ruleset, rule_record, line... ) |
1507
|
|
|
|
|
|
|
# |
1508
|
|
|
|
|
|
|
# Add the specified documentation lines to the specified ruleset. If |
1509
|
|
|
|
|
|
|
# $rule_record is defined, it represents the rule to which this documentation |
1510
|
|
|
|
|
|
|
# applies. Otherwise, the documentation represents header material to be |
1511
|
|
|
|
|
|
|
# output before the documentation for the first rule. If the beginning of the |
1512
|
|
|
|
|
|
|
# first documentation line is '!', then return without doing anything. |
1513
|
|
|
|
|
|
|
# |
1514
|
|
|
|
|
|
|
# Any line starting with = is, of course, taken to indicate a Pod command |
1515
|
|
|
|
|
|
|
# paragraph. It will be preceded and followed by a blank line. |
1516
|
|
|
|
|
|
|
# |
1517
|
|
|
|
|
|
|
# If $rule_record is undefined, then close any pending lists and do nothing |
1518
|
|
|
|
|
|
|
# else. |
1519
|
|
|
|
|
|
|
|
1520
|
|
|
|
|
|
|
sub add_doc { |
1521
|
|
|
|
|
|
|
|
1522
|
238
|
|
|
238
|
0
|
231
|
my ($self, $rs, $rr, @lines) = @_; |
1523
|
|
|
|
|
|
|
|
1524
|
|
|
|
|
|
|
# Don't do anything unless we were given either a rule record or some |
1525
|
|
|
|
|
|
|
# documentation or both. |
1526
|
|
|
|
|
|
|
|
1527
|
238
|
100
|
100
|
|
|
488
|
return unless defined($rr) || @lines; |
1528
|
|
|
|
|
|
|
|
1529
|
|
|
|
|
|
|
# If the first documentation line starts with !, return without doing |
1530
|
|
|
|
|
|
|
# anything. That character indicates that this rule should not be |
1531
|
|
|
|
|
|
|
# documented. |
1532
|
|
|
|
|
|
|
|
1533
|
172
|
100
|
100
|
|
|
291
|
return if @lines && $lines[0] =~ /^[!]/; |
1534
|
|
|
|
|
|
|
|
1535
|
|
|
|
|
|
|
# Similarly, return without doing anything if the rule contains the |
1536
|
|
|
|
|
|
|
# 'undocumented' attribute." |
1537
|
|
|
|
|
|
|
|
1538
|
171
|
100
|
66
|
|
|
359
|
return if defined $rr && $rr->{undocumented}; |
1539
|
|
|
|
|
|
|
|
1540
|
|
|
|
|
|
|
# Otherwise, put the documentation lines together into a single string |
1541
|
|
|
|
|
|
|
# (which may contain a series of POD paragraphs). |
1542
|
|
|
|
|
|
|
|
1543
|
170
|
|
|
|
|
132
|
my $body = ''; |
1544
|
170
|
|
|
|
|
96
|
my $last_pod; |
1545
|
|
|
|
|
|
|
my $this_pod; |
1546
|
|
|
|
|
|
|
|
1547
|
170
|
|
|
|
|
167
|
foreach my $line (@lines) |
1548
|
|
|
|
|
|
|
{ |
1549
|
|
|
|
|
|
|
# If this line starts with =, then it needs extra spacing. |
1550
|
|
|
|
|
|
|
|
1551
|
15
|
|
|
|
|
39
|
my $this_pod = $line =~ qr{ ^ = }x; |
1552
|
|
|
|
|
|
|
|
1553
|
|
|
|
|
|
|
# If $body already has something in it, add a newline first. Add |
1554
|
|
|
|
|
|
|
# two if this line starts with =, or if the previously added line |
1555
|
|
|
|
|
|
|
# did, so that we get a new paragraph. |
1556
|
|
|
|
|
|
|
|
1557
|
15
|
100
|
|
|
|
22
|
if ( $body ne '' ) |
1558
|
|
|
|
|
|
|
{ |
1559
|
4
|
50
|
33
|
|
|
12
|
$body .= "\n" if $last_pod || $this_pod; |
1560
|
4
|
|
|
|
|
4
|
$body .= "\n"; |
1561
|
|
|
|
|
|
|
} |
1562
|
|
|
|
|
|
|
|
1563
|
15
|
|
|
|
|
18
|
$body .= $line; |
1564
|
15
|
|
|
|
|
15
|
$last_pod = $this_pod; |
1565
|
|
|
|
|
|
|
} |
1566
|
|
|
|
|
|
|
|
1567
|
|
|
|
|
|
|
# Then add the documentation to the ruleset record: |
1568
|
|
|
|
|
|
|
|
1569
|
|
|
|
|
|
|
# If there is no attached rule, then we add the body as an ordinary paragraph. |
1570
|
|
|
|
|
|
|
|
1571
|
170
|
100
|
66
|
|
|
614
|
unless ( defined $rr ) |
|
|
100
|
66
|
|
|
|
|
|
|
100
|
|
|
|
|
|
1572
|
|
|
|
|
|
|
{ |
1573
|
5
|
|
|
|
|
4
|
push @{$rs->{doc_items}}, "=ORDINARY"; |
|
5
|
|
|
|
|
9
|
|
1574
|
5
|
50
|
|
|
|
7
|
push @{$rs->{doc_items}}, process_doc($body) if defined $body; |
|
5
|
|
|
|
|
7
|
|
1575
|
|
|
|
|
|
|
} |
1576
|
|
|
|
|
|
|
|
1577
|
|
|
|
|
|
|
# If the indicated rule is a parameter rule, then add its record to the list. |
1578
|
|
|
|
|
|
|
|
1579
|
|
|
|
|
|
|
elsif ( defined $rr and $rr->{type} eq 'param' ) |
1580
|
|
|
|
|
|
|
{ |
1581
|
125
|
|
|
|
|
83
|
push @{$rs->{doc_items}}, $rr; |
|
125
|
|
|
|
|
160
|
|
1582
|
125
|
|
|
|
|
190
|
weaken $rs->{doc_items}[-1]; |
1583
|
125
|
50
|
|
|
|
161
|
push @{$rs->{doc_items}}, process_doc($body, 1) if defined $body; |
|
125
|
|
|
|
|
158
|
|
1584
|
|
|
|
|
|
|
} |
1585
|
|
|
|
|
|
|
|
1586
|
|
|
|
|
|
|
# If this is an include rule, then we add a special line to include the |
1587
|
|
|
|
|
|
|
# specified ruleset(s). |
1588
|
|
|
|
|
|
|
|
1589
|
|
|
|
|
|
|
elsif ( defined $rr and $rr->{type} eq 'include' ) |
1590
|
|
|
|
|
|
|
{ |
1591
|
27
|
|
|
|
|
23
|
push @{$rs->{doc_items}}, "=INCLUDE $rr->{ruleset}"; |
|
27
|
|
|
|
|
55
|
|
1592
|
|
|
|
|
|
|
|
1593
|
|
|
|
|
|
|
# If any body text was specified, then add it as an ordinary paragraph |
1594
|
|
|
|
|
|
|
# after the inclusion. |
1595
|
|
|
|
|
|
|
|
1596
|
27
|
100
|
|
|
|
51
|
if ( $body ne '' ) |
1597
|
|
|
|
|
|
|
{ |
1598
|
1
|
|
|
|
|
1
|
push @{$rs->{doc_items}}, "=ORDINARY"; |
|
1
|
|
|
|
|
1
|
|
1599
|
1
|
50
|
|
|
|
5
|
push @{$rs->{doc_items}}, process_doc($body) if defined $body; |
|
1
|
|
|
|
|
4
|
|
1600
|
|
|
|
|
|
|
} |
1601
|
|
|
|
|
|
|
} |
1602
|
|
|
|
|
|
|
} |
1603
|
|
|
|
|
|
|
|
1604
|
|
|
|
|
|
|
|
1605
|
|
|
|
|
|
|
# process_doc ( ) |
1606
|
|
|
|
|
|
|
# |
1607
|
|
|
|
|
|
|
# Make sure that the indicated string is valid POD. In particular, if there |
1608
|
|
|
|
|
|
|
# are any unclosed =over sections, close them at the end. Throw an exception |
1609
|
|
|
|
|
|
|
# if we find an =item before the first =over or a =head inside an =over. |
1610
|
|
|
|
|
|
|
|
1611
|
|
|
|
|
|
|
sub process_doc { |
1612
|
|
|
|
|
|
|
|
1613
|
131
|
|
|
131
|
0
|
111
|
my ($docstring, $item_body) = @_; |
1614
|
|
|
|
|
|
|
|
1615
|
131
|
|
|
|
|
97
|
my ($list_level) = 0; |
1616
|
|
|
|
|
|
|
|
1617
|
131
|
|
|
|
|
195
|
while ( $docstring =~ / ^ (=[a-z]+) /gmx ) |
1618
|
|
|
|
|
|
|
{ |
1619
|
0
|
0
|
|
|
|
0
|
if ( $1 eq '=over' ) |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
1620
|
|
|
|
|
|
|
{ |
1621
|
0
|
|
|
|
|
0
|
$list_level++; |
1622
|
|
|
|
|
|
|
} |
1623
|
|
|
|
|
|
|
|
1624
|
|
|
|
|
|
|
elsif ( $1 eq '=back' ) |
1625
|
|
|
|
|
|
|
{ |
1626
|
0
|
|
|
|
|
0
|
$list_level--; |
1627
|
0
|
0
|
|
|
|
0
|
croak "invalid POD string: =back does not match any =over" if $list_level < 0; |
1628
|
|
|
|
|
|
|
} |
1629
|
|
|
|
|
|
|
|
1630
|
|
|
|
|
|
|
elsif ( $1 eq '=item' ) |
1631
|
|
|
|
|
|
|
{ |
1632
|
0
|
0
|
|
|
|
0
|
croak "invalid POD string: =item outside of =over" if $list_level == 0; |
1633
|
|
|
|
|
|
|
} |
1634
|
|
|
|
|
|
|
|
1635
|
|
|
|
|
|
|
elsif ( $1 eq '=head' ) |
1636
|
|
|
|
|
|
|
{ |
1637
|
0
|
0
|
0
|
|
|
0
|
croak "invalid POD string: =head inside =over" if $list_level > 0 or $item_body; |
1638
|
|
|
|
|
|
|
} |
1639
|
|
|
|
|
|
|
} |
1640
|
|
|
|
|
|
|
|
1641
|
131
|
|
|
|
|
257
|
return $docstring, ('=back') x $list_level; |
1642
|
|
|
|
|
|
|
} |
1643
|
|
|
|
|
|
|
|
1644
|
|
|
|
|
|
|
|
1645
|
|
|
|
|
|
|
# generate_docstring ( ruleset ) |
1646
|
|
|
|
|
|
|
# |
1647
|
|
|
|
|
|
|
# Generate the documentation string for the specified ruleset, recursively |
1648
|
|
|
|
|
|
|
# evaluating all of the rulesets it includes. This will generate a series of |
1649
|
|
|
|
|
|
|
# flat top-level lists describing all of the various parameters, potentially |
1650
|
|
|
|
|
|
|
# with non-list paragraphs in between. |
1651
|
|
|
|
|
|
|
|
1652
|
|
|
|
|
|
|
sub generate_docstring { |
1653
|
|
|
|
|
|
|
|
1654
|
6
|
|
|
6
|
0
|
5
|
my ($self, $rs, $state) = @_; |
1655
|
|
|
|
|
|
|
|
1656
|
|
|
|
|
|
|
# Make sure that we process each ruleset only once, even if it is included |
1657
|
|
|
|
|
|
|
# multiple times. Also keep track of our recursion level. |
1658
|
|
|
|
|
|
|
|
1659
|
6
|
50
|
|
|
|
11
|
return '' if $state->{processed}{$rs->{name}}; |
1660
|
|
|
|
|
|
|
|
1661
|
6
|
|
|
|
|
6
|
$state->{processed}{$rs->{name}} = 1; |
1662
|
6
|
|
|
|
|
6
|
$state->{level}++; |
1663
|
|
|
|
|
|
|
|
1664
|
|
|
|
|
|
|
# Start with an empty string. If there are no doc_items for this |
1665
|
|
|
|
|
|
|
# ruleset, just return that. |
1666
|
|
|
|
|
|
|
|
1667
|
6
|
|
|
|
|
5
|
my $doc = ''; |
1668
|
|
|
|
|
|
|
|
1669
|
6
|
50
|
33
|
|
|
22
|
return $doc unless ref $rs && ref $rs->{doc_items} eq 'ARRAY'; |
1670
|
|
|
|
|
|
|
|
1671
|
|
|
|
|
|
|
# Go through each docstring, treating it as a POD paragraph. That means |
1672
|
|
|
|
|
|
|
# that they will be separated from each other by a blank line. |
1673
|
|
|
|
|
|
|
|
1674
|
6
|
|
|
|
|
6
|
foreach my $item ( @{$rs->{doc_items}} ) |
|
6
|
|
|
|
|
8
|
|
1675
|
|
|
|
|
|
|
{ |
1676
|
|
|
|
|
|
|
# An item record starts a list if not already in one. |
1677
|
|
|
|
|
|
|
|
1678
|
38
|
100
|
66
|
|
|
144
|
if ( ref $item && defined $item->{param} ) |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
1679
|
|
|
|
|
|
|
{ |
1680
|
10
|
100
|
|
|
|
13
|
unless ( $state->{in_list} ) |
1681
|
|
|
|
|
|
|
{ |
1682
|
5
|
100
|
|
|
|
10
|
$doc .= "\n\n" if $doc ne ''; |
1683
|
5
|
|
|
|
|
4
|
$doc .= "=over"; |
1684
|
5
|
|
|
|
|
5
|
$state->{in_list} = 1; |
1685
|
|
|
|
|
|
|
} |
1686
|
|
|
|
|
|
|
|
1687
|
10
|
|
|
|
|
13
|
$doc .= "\n\n=item $item->{param}"; |
1688
|
|
|
|
|
|
|
} |
1689
|
|
|
|
|
|
|
|
1690
|
|
|
|
|
|
|
# A string starting with =ORDINARY closes any current list. |
1691
|
|
|
|
|
|
|
|
1692
|
|
|
|
|
|
|
elsif ( $item =~ qr{ ^ =ORDINARY }x ) |
1693
|
|
|
|
|
|
|
{ |
1694
|
8
|
100
|
|
|
|
14
|
if ( $state->{in_list} ) |
1695
|
|
|
|
|
|
|
{ |
1696
|
3
|
50
|
|
|
|
7
|
$doc .= "\n\n" if $doc ne ''; |
1697
|
3
|
|
|
|
|
3
|
$doc .= "=back"; |
1698
|
3
|
|
|
|
|
4
|
$state->{in_list} = 0; |
1699
|
|
|
|
|
|
|
} |
1700
|
|
|
|
|
|
|
} |
1701
|
|
|
|
|
|
|
|
1702
|
|
|
|
|
|
|
# A string starting with =INCLUDE inserts the specified ruleset. |
1703
|
|
|
|
|
|
|
|
1704
|
|
|
|
|
|
|
elsif ( $item =~ qr{ ^ =INCLUDE \s* (.*) }xs ) |
1705
|
|
|
|
|
|
|
{ |
1706
|
2
|
|
|
|
|
3
|
my $included_rs = $self->{RULESETS}{$1}; |
1707
|
|
|
|
|
|
|
|
1708
|
2
|
50
|
|
|
|
4
|
if ( ref $included_rs eq 'HTTP::Validate::Ruleset' ) |
1709
|
|
|
|
|
|
|
{ |
1710
|
2
|
|
|
|
|
10
|
my $subdoc = $self->generate_docstring($included_rs, $state); |
1711
|
|
|
|
|
|
|
|
1712
|
2
|
50
|
33
|
|
|
9
|
$doc .= "\n\n" if $doc ne '' && $subdoc ne ''; |
1713
|
2
|
50
|
|
|
|
4
|
$doc .= $subdoc if $subdoc ne ''; |
1714
|
|
|
|
|
|
|
} |
1715
|
|
|
|
|
|
|
} |
1716
|
|
|
|
|
|
|
|
1717
|
|
|
|
|
|
|
# All other strings are added as-is. |
1718
|
|
|
|
|
|
|
|
1719
|
|
|
|
|
|
|
else |
1720
|
|
|
|
|
|
|
{ |
1721
|
18
|
100
|
100
|
|
|
46
|
$doc .= "\n\n" if $doc ne '' && $item ne ''; |
1722
|
18
|
|
|
|
|
28
|
$doc .= $item; |
1723
|
|
|
|
|
|
|
} |
1724
|
|
|
|
|
|
|
} |
1725
|
|
|
|
|
|
|
|
1726
|
|
|
|
|
|
|
# If we get to the end of the top-level ruleset and we are still in a |
1727
|
|
|
|
|
|
|
# list, close it. Also make sure that our resulting documentation string |
1728
|
|
|
|
|
|
|
# ends with a newline. |
1729
|
|
|
|
|
|
|
|
1730
|
6
|
100
|
|
|
|
10
|
if ( --$state->{level} == 0 ) |
1731
|
|
|
|
|
|
|
{ |
1732
|
4
|
100
|
|
|
|
6
|
$doc .= "\n\n=back" if $state->{in_list}; |
1733
|
4
|
|
|
|
|
3
|
$state->{in_list} = 0; |
1734
|
4
|
|
|
|
|
4
|
$doc .= "\n"; |
1735
|
|
|
|
|
|
|
} |
1736
|
|
|
|
|
|
|
|
1737
|
6
|
|
|
|
|
10
|
return $doc; |
1738
|
|
|
|
|
|
|
} |
1739
|
|
|
|
|
|
|
|
1740
|
|
|
|
|
|
|
|
1741
|
|
|
|
|
|
|
# generate_param_list ( ruleset ) |
1742
|
|
|
|
|
|
|
# |
1743
|
|
|
|
|
|
|
# Generate a list of unique parameter names for the ruleset and its included |
1744
|
|
|
|
|
|
|
# rulesets if any. |
1745
|
|
|
|
|
|
|
|
1746
|
|
|
|
|
|
|
sub generate_param_list { |
1747
|
|
|
|
|
|
|
|
1748
|
3
|
|
|
3
|
0
|
4
|
my ($self, $rs_name, $uniq) = @_; |
1749
|
|
|
|
|
|
|
|
1750
|
3
|
|
100
|
|
|
8
|
$uniq ||= {}; |
1751
|
|
|
|
|
|
|
|
1752
|
3
|
50
|
|
|
|
7
|
return if $uniq->{$rs_name}; $uniq->{$rs_name} = 1; |
|
3
|
|
|
|
|
4
|
|
1753
|
|
|
|
|
|
|
|
1754
|
3
|
|
|
|
|
3
|
my @params; |
1755
|
|
|
|
|
|
|
|
1756
|
3
|
|
|
|
|
2
|
foreach my $rule ( @{$self->{RULESETS}{$rs_name}{rules}} ) |
|
3
|
|
|
|
|
9
|
|
1757
|
|
|
|
|
|
|
{ |
1758
|
7
|
100
|
|
|
|
13
|
if ( $rule->{type} eq 'param' ) |
|
|
50
|
|
|
|
|
|
1759
|
|
|
|
|
|
|
{ |
1760
|
5
|
|
|
|
|
9
|
push @params, $rule->{param}; |
1761
|
|
|
|
|
|
|
} |
1762
|
|
|
|
|
|
|
|
1763
|
|
|
|
|
|
|
elsif ( $rule->{type} eq 'include' ) |
1764
|
|
|
|
|
|
|
{ |
1765
|
2
|
|
|
|
|
6
|
push @params, $self->generate_param_list($rule->{ruleset}, $uniq); |
1766
|
|
|
|
|
|
|
} |
1767
|
|
|
|
|
|
|
} |
1768
|
|
|
|
|
|
|
|
1769
|
3
|
|
|
|
|
9
|
return @params; |
1770
|
|
|
|
|
|
|
} |
1771
|
|
|
|
|
|
|
|
1772
|
|
|
|
|
|
|
|
1773
|
|
|
|
|
|
|
# new_execution ( context, params ) |
1774
|
|
|
|
|
|
|
# |
1775
|
|
|
|
|
|
|
# Create a new validation-execution control record, using the given context |
1776
|
|
|
|
|
|
|
# and input parameters. |
1777
|
|
|
|
|
|
|
|
1778
|
|
|
|
|
|
|
sub new_execution { |
1779
|
|
|
|
|
|
|
|
1780
|
60
|
|
|
60
|
0
|
49
|
my ($self, $context, $input_params) = @_; |
1781
|
|
|
|
|
|
|
|
1782
|
|
|
|
|
|
|
# First check the types of the arguments to this function. |
1783
|
|
|
|
|
|
|
|
1784
|
60
|
50
|
33
|
|
|
379
|
croak "the second parameter to check_params() must be a hashref if defined" |
|
|
|
33
|
|
|
|
|
1785
|
|
|
|
|
|
|
if defined $context && (!ref $context || reftype $context ne 'HASH'); |
1786
|
|
|
|
|
|
|
|
1787
|
60
|
50
|
|
|
|
86
|
$context = {} unless defined $context; |
1788
|
|
|
|
|
|
|
|
1789
|
60
|
50
|
|
|
|
92
|
croak "the third parameter to check_params() must be a hashref or listref" |
1790
|
|
|
|
|
|
|
unless ref $input_params; |
1791
|
|
|
|
|
|
|
|
1792
|
|
|
|
|
|
|
# If the parameters were given as a hashref, just use it straight. |
1793
|
|
|
|
|
|
|
|
1794
|
60
|
|
|
|
|
53
|
my $unpacked_params = {}; |
1795
|
|
|
|
|
|
|
|
1796
|
60
|
100
|
|
|
|
145
|
if ( reftype $input_params eq 'HASH' ) |
|
|
50
|
|
|
|
|
|
1797
|
|
|
|
|
|
|
{ |
1798
|
29
|
|
|
|
|
69
|
%$unpacked_params = %$input_params; |
1799
|
|
|
|
|
|
|
} |
1800
|
|
|
|
|
|
|
|
1801
|
|
|
|
|
|
|
# If the parameters were given as a listref, we need to look for hashrefs |
1802
|
|
|
|
|
|
|
# at the front. |
1803
|
|
|
|
|
|
|
|
1804
|
|
|
|
|
|
|
elsif ( reftype $input_params eq 'ARRAY' ) |
1805
|
|
|
|
|
|
|
{ |
1806
|
|
|
|
|
|
|
# Look for hashrefs at the beginning of the list and unpack them. |
1807
|
|
|
|
|
|
|
|
1808
|
31
|
|
66
|
|
|
76
|
while ( ref $input_params->[0] && reftype $input_params->[0] eq 'HASH' ) |
1809
|
|
|
|
|
|
|
{ |
1810
|
3
|
|
|
|
|
2
|
my $p = shift @$input_params; |
1811
|
|
|
|
|
|
|
|
1812
|
3
|
|
|
|
|
7
|
foreach my $x (keys %$p) |
1813
|
|
|
|
|
|
|
{ |
1814
|
6
|
|
|
|
|
8
|
add_param($unpacked_params, $x, $p->{$x}); |
1815
|
|
|
|
|
|
|
} |
1816
|
|
|
|
|
|
|
} |
1817
|
|
|
|
|
|
|
|
1818
|
|
|
|
|
|
|
# All other items must be name/value pairs. |
1819
|
|
|
|
|
|
|
|
1820
|
31
|
|
|
|
|
51
|
while ( @$input_params ) |
1821
|
|
|
|
|
|
|
{ |
1822
|
72
|
|
|
|
|
51
|
my $p = shift @$input_params; |
1823
|
|
|
|
|
|
|
|
1824
|
72
|
50
|
|
|
|
70
|
if ( ref $p ) |
1825
|
|
|
|
|
|
|
{ |
1826
|
0
|
|
|
|
|
0
|
croak "invalid parameter '$p'"; |
1827
|
|
|
|
|
|
|
} |
1828
|
|
|
|
|
|
|
|
1829
|
|
|
|
|
|
|
else |
1830
|
|
|
|
|
|
|
{ |
1831
|
72
|
|
|
|
|
81
|
add_param($unpacked_params, $p, shift @$input_params); |
1832
|
|
|
|
|
|
|
} |
1833
|
|
|
|
|
|
|
} |
1834
|
|
|
|
|
|
|
} |
1835
|
|
|
|
|
|
|
|
1836
|
|
|
|
|
|
|
# Anything else is invalid. |
1837
|
|
|
|
|
|
|
|
1838
|
|
|
|
|
|
|
else |
1839
|
|
|
|
|
|
|
{ |
1840
|
0
|
|
|
|
|
0
|
croak "the third parameter to check_params() must be a hashref or listref"; |
1841
|
|
|
|
|
|
|
} |
1842
|
|
|
|
|
|
|
|
1843
|
|
|
|
|
|
|
# Now create a new validation record |
1844
|
|
|
|
|
|
|
|
1845
|
60
|
|
|
|
|
53
|
my %settings = %{$self->{SETTINGS}}; |
|
60
|
|
|
|
|
194
|
|
1846
|
|
|
|
|
|
|
|
1847
|
60
|
|
|
|
|
229
|
my $vr = { raw => $unpacked_params, # the raw parameters and values |
1848
|
|
|
|
|
|
|
clean => { }, # the parameter keys and values |
1849
|
|
|
|
|
|
|
clean_list => [ ], # the parameter keys in order of recognition |
1850
|
|
|
|
|
|
|
context => $context, # context for the validators to use |
1851
|
|
|
|
|
|
|
ps => { }, # the status (failed=0, passed=1, ignored=undef) of each parameter |
1852
|
|
|
|
|
|
|
rs => { }, # the status (checked=1, fulfilled=2) of each ruleset |
1853
|
|
|
|
|
|
|
settings => \%settings, # a copy of our current settings |
1854
|
|
|
|
|
|
|
}; |
1855
|
|
|
|
|
|
|
|
1856
|
60
|
|
|
|
|
112
|
return bless $vr, 'HTTP::Validate::Progress'; |
1857
|
|
|
|
|
|
|
} |
1858
|
|
|
|
|
|
|
|
1859
|
|
|
|
|
|
|
|
1860
|
|
|
|
|
|
|
sub add_param { |
1861
|
|
|
|
|
|
|
|
1862
|
78
|
|
|
78
|
0
|
62
|
my ($hash, $param, $value) = @_; |
1863
|
|
|
|
|
|
|
|
1864
|
|
|
|
|
|
|
# If there is already more than one value for this parameter, add the new |
1865
|
|
|
|
|
|
|
# value(s) to the array ref. |
1866
|
|
|
|
|
|
|
|
1867
|
78
|
50
|
33
|
|
|
207
|
if ( ref $hash->{$param} && reftype $hash->{$param} eq 'ARRAY' ) |
|
|
100
|
100
|
|
|
|
|
1868
|
|
|
|
|
|
|
{ |
1869
|
0
|
0
|
0
|
|
|
0
|
push @{$hash->{$param}}, |
|
0
|
|
|
|
|
0
|
|
1870
|
|
|
|
|
|
|
(ref $value && reftype $value eq 'ARRAY' ? @$value : $value); |
1871
|
|
|
|
|
|
|
} |
1872
|
|
|
|
|
|
|
|
1873
|
|
|
|
|
|
|
# If there is already one value for this parameter, turn it into an array |
1874
|
|
|
|
|
|
|
# ref. |
1875
|
|
|
|
|
|
|
|
1876
|
|
|
|
|
|
|
elsif ( defined $hash->{$param} && $hash->{$param} ne '' ) |
1877
|
|
|
|
|
|
|
{ |
1878
|
3
|
50
|
33
|
|
|
19
|
$hash->{$param} = [$hash->{$param}, |
1879
|
|
|
|
|
|
|
(ref $value && reftype $value eq 'ARRAY' ? @$value : $value)]; |
1880
|
|
|
|
|
|
|
} |
1881
|
|
|
|
|
|
|
|
1882
|
|
|
|
|
|
|
# Otherwise, set the value for this parameter to be the new value (which |
1883
|
|
|
|
|
|
|
# could be either a scalar or a reference). |
1884
|
|
|
|
|
|
|
|
1885
|
|
|
|
|
|
|
else |
1886
|
|
|
|
|
|
|
{ |
1887
|
75
|
|
|
|
|
162
|
$hash->{$param} = $value; |
1888
|
|
|
|
|
|
|
} |
1889
|
|
|
|
|
|
|
} |
1890
|
|
|
|
|
|
|
|
1891
|
|
|
|
|
|
|
|
1892
|
|
|
|
|
|
|
# This function performs a validation using the given validation-progress |
1893
|
|
|
|
|
|
|
# record, starting with the given ruleset, and returns a hash with the |
1894
|
|
|
|
|
|
|
# results. |
1895
|
|
|
|
|
|
|
|
1896
|
|
|
|
|
|
|
sub execute_validation { |
1897
|
|
|
|
|
|
|
|
1898
|
60
|
|
|
60
|
0
|
59
|
my ($self, $vr, $ruleset_name) = @_; |
1899
|
|
|
|
|
|
|
|
1900
|
60
|
50
|
33
|
|
|
195
|
croak "you must provide a ruleset name" unless defined $ruleset_name && $ruleset_name ne ''; |
1901
|
60
|
50
|
33
|
|
|
293
|
croak "invalid ruleset name: '$ruleset_name'" if ref $ruleset_name || $ruleset_name !~ /\w/; |
1902
|
|
|
|
|
|
|
|
1903
|
|
|
|
|
|
|
# First perform the specified validation against the specified ruleset. |
1904
|
|
|
|
|
|
|
# This may trigger validations against additional rulesets if the intial |
1905
|
|
|
|
|
|
|
# one contains 'allow' or 'require' rules. |
1906
|
|
|
|
|
|
|
|
1907
|
60
|
|
|
|
|
88
|
$self->validate_ruleset($vr, $ruleset_name); |
1908
|
|
|
|
|
|
|
|
1909
|
|
|
|
|
|
|
# Now, if this ruleset was not fulfilled, add an appropriate error |
1910
|
|
|
|
|
|
|
# message. |
1911
|
|
|
|
|
|
|
|
1912
|
60
|
100
|
|
|
|
109
|
if ( $vr->{rs}{$ruleset_name} != 2 ) |
1913
|
|
|
|
|
|
|
{ |
1914
|
1
|
|
|
|
|
2
|
my @names = @{$self->{RULESETS}{$ruleset_name}{fulfill_order}}; |
|
1
|
|
|
|
|
5
|
|
1915
|
1
|
50
|
|
|
|
5
|
my $msg = @names == 1 ? 'ERR_REQ_SINGLE': 'ERR_REQ_MULT'; |
1916
|
1
|
|
|
|
|
7
|
add_error($vr, { key => $ruleset_name }, $msg, { param => \@names }); |
1917
|
|
|
|
|
|
|
} |
1918
|
|
|
|
|
|
|
|
1919
|
|
|
|
|
|
|
# Create an object to hold the result of this function. |
1920
|
|
|
|
|
|
|
|
1921
|
60
|
|
|
|
|
89
|
my $result = bless {}, 'HTTP::Validate::Result'; |
1922
|
|
|
|
|
|
|
|
1923
|
|
|
|
|
|
|
# Add the clean-value hash and the raw-value hash |
1924
|
|
|
|
|
|
|
|
1925
|
60
|
|
|
|
|
86
|
$result->{clean} = $vr->{clean}; |
1926
|
60
|
|
|
|
|
60
|
$result->{clean_list} = $vr->{clean_list}; |
1927
|
60
|
|
|
|
|
55
|
$result->{raw} = $vr->{raw}; |
1928
|
|
|
|
|
|
|
|
1929
|
|
|
|
|
|
|
# Put the clean-value hash under the old name, for backward compatibility |
1930
|
|
|
|
|
|
|
# (it will be eventually removed). |
1931
|
|
|
|
|
|
|
|
1932
|
60
|
|
|
|
|
62
|
$result->{values} = $vr->{clean}; |
1933
|
|
|
|
|
|
|
|
1934
|
|
|
|
|
|
|
# Add the content type, if one was specified. |
1935
|
|
|
|
|
|
|
|
1936
|
|
|
|
|
|
|
$result->{content_type} = $vr->{content_type} |
1937
|
|
|
|
|
|
|
if defined $vr->{content_type} and |
1938
|
|
|
|
|
|
|
$vr->{content_type} ne '' and |
1939
|
60
|
100
|
66
|
|
|
116
|
$vr->{content_type} ne 'unknown'; |
|
|
|
100
|
|
|
|
|
1940
|
|
|
|
|
|
|
|
1941
|
|
|
|
|
|
|
# Add any errors that were generated. |
1942
|
|
|
|
|
|
|
|
1943
|
60
|
|
|
|
|
67
|
$result->{ec} = $vr->{ec}; |
1944
|
60
|
|
|
|
|
63
|
$result->{er} = $vr->{er}; |
1945
|
60
|
|
|
|
|
55
|
$result->{wc} = $vr->{wc}; |
1946
|
60
|
|
|
|
|
91
|
$result->{wn} = $vr->{wn}; |
1947
|
60
|
|
|
|
|
49
|
$result->{ig} = $vr->{ig}; |
1948
|
|
|
|
|
|
|
|
1949
|
|
|
|
|
|
|
# Now check for unrecognized parameters, and generate errors or warnings |
1950
|
|
|
|
|
|
|
# for them. |
1951
|
|
|
|
|
|
|
|
1952
|
60
|
100
|
|
|
|
119
|
return $result if $self->{SETTINGS}{ignore_unrecognized}; |
1953
|
|
|
|
|
|
|
|
1954
|
52
|
|
|
|
|
38
|
foreach my $key (keys %{$vr->{raw}}) |
|
52
|
|
|
|
|
105
|
|
1955
|
|
|
|
|
|
|
{ |
1956
|
109
|
100
|
66
|
|
|
192
|
next if exists $vr->{ps}{$key} or exists $vr->{ig}{$key}; |
1957
|
|
|
|
|
|
|
|
1958
|
4
|
100
|
|
|
|
7
|
if ( $self->{SETTINGS}{permissive} ) |
1959
|
|
|
|
|
|
|
{ |
1960
|
2
|
|
|
|
|
2
|
unshift @{$result->{wn}}, [$key, "unknown parameter '$key'"]; |
|
2
|
|
|
|
|
7
|
|
1961
|
2
|
|
|
|
|
4
|
$result->{wc}{$key}++; |
1962
|
|
|
|
|
|
|
} |
1963
|
|
|
|
|
|
|
else |
1964
|
|
|
|
|
|
|
{ |
1965
|
2
|
|
|
|
|
2
|
unshift @{$result->{er}}, [$key, "unknown parameter '$key'"]; |
|
2
|
|
|
|
|
10
|
|
1966
|
2
|
|
|
|
|
4
|
$result->{ec}{$key}++; |
1967
|
|
|
|
|
|
|
} |
1968
|
|
|
|
|
|
|
} |
1969
|
|
|
|
|
|
|
|
1970
|
|
|
|
|
|
|
# Now return the result object. |
1971
|
|
|
|
|
|
|
|
1972
|
52
|
|
|
|
|
212
|
return $result; |
1973
|
|
|
|
|
|
|
} |
1974
|
|
|
|
|
|
|
|
1975
|
|
|
|
|
|
|
|
1976
|
|
|
|
|
|
|
# This function does the actual work of validating. It takes two parameters: |
1977
|
|
|
|
|
|
|
# a validation record and a ruleset name. It sets various subfields of the |
1978
|
|
|
|
|
|
|
# validation record according to the results of the validation. |
1979
|
|
|
|
|
|
|
|
1980
|
|
|
|
|
|
|
sub validate_ruleset { |
1981
|
|
|
|
|
|
|
|
1982
|
82
|
|
|
82
|
0
|
77
|
my ($self, $vr, $ruleset_name) = @_; |
1983
|
|
|
|
|
|
|
|
1984
|
82
|
50
|
|
|
|
106
|
die "Missing ruleset" unless defined $ruleset_name; |
1985
|
|
|
|
|
|
|
|
1986
|
82
|
|
|
|
|
85
|
my $rs = $self->{RULESETS}{$ruleset_name}; |
1987
|
|
|
|
|
|
|
|
1988
|
|
|
|
|
|
|
# Throw an error if this ruleset does not exist. |
1989
|
|
|
|
|
|
|
|
1990
|
82
|
50
|
|
|
|
129
|
croak "Unknown ruleset '$ruleset_name'" unless ref $rs; |
1991
|
|
|
|
|
|
|
|
1992
|
|
|
|
|
|
|
# Return immediately if we have already visited this ruleset. Otherwise, |
1993
|
|
|
|
|
|
|
# mark it as visited. |
1994
|
|
|
|
|
|
|
|
1995
|
82
|
50
|
|
|
|
130
|
return if exists $vr->{rs}{$ruleset_name}; |
1996
|
82
|
|
|
|
|
105
|
$vr->{rs}{$ruleset_name} = 1; |
1997
|
|
|
|
|
|
|
|
1998
|
|
|
|
|
|
|
# Mark the ruleset as fulfilled if it has no non-optional parameters. |
1999
|
|
|
|
|
|
|
|
2000
|
82
|
100
|
66
|
|
|
169
|
$vr->{rs}{$ruleset_name} = 2 unless ref $rs->{fulfill_order} && @{$rs->{fulfill_order}}; |
|
82
|
|
|
|
|
244
|
|
2001
|
|
|
|
|
|
|
|
2002
|
|
|
|
|
|
|
# Now check all of the rules in this ruleset against the parameter values |
2003
|
|
|
|
|
|
|
# stored in $vr->{raw}. |
2004
|
|
|
|
|
|
|
|
2005
|
|
|
|
|
|
|
RULE: |
2006
|
82
|
|
|
|
|
75
|
foreach my $rr (@{$rs->{rules}}) |
|
82
|
|
|
|
|
132
|
|
2007
|
|
|
|
|
|
|
{ |
2008
|
214
|
|
|
|
|
190
|
my $type = $rr->{type}; |
2009
|
214
|
|
|
|
|
195
|
my $param = $rr->{param}; |
2010
|
214
|
|
100
|
|
|
457
|
my $key = $rr->{key} || $param; |
2011
|
214
|
|
|
|
|
118
|
my $default_used; |
2012
|
|
|
|
|
|
|
|
2013
|
|
|
|
|
|
|
# To evaluate a rule of type 'param' we check to see if a |
2014
|
|
|
|
|
|
|
# corresponding parameter was specified. |
2015
|
|
|
|
|
|
|
|
2016
|
214
|
100
|
100
|
|
|
380
|
if ( $type eq 'param' ) |
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
2017
|
|
|
|
|
|
|
{ |
2018
|
170
|
|
|
|
|
111
|
my (%names_found, @names_found, @raw_values); |
2019
|
|
|
|
|
|
|
|
2020
|
|
|
|
|
|
|
# Skip this rule if a previous 'ignore' was encountered. |
2021
|
|
|
|
|
|
|
|
2022
|
170
|
50
|
|
|
|
279
|
next RULE if $vr->{ig}{$key}; |
2023
|
|
|
|
|
|
|
|
2024
|
|
|
|
|
|
|
# Otherwise check to see if the parameter or any of its aliases were |
2025
|
|
|
|
|
|
|
# specified. If so, then collect up their values. |
2026
|
|
|
|
|
|
|
|
2027
|
170
|
|
|
|
|
130
|
foreach my $name ( $rr->{param}, @{$rr->{alias}} ) |
|
170
|
|
|
|
|
222
|
|
2028
|
|
|
|
|
|
|
{ |
2029
|
177
|
100
|
|
|
|
269
|
next unless exists $vr->{raw}{$name}; |
2030
|
115
|
|
|
|
|
100
|
$names_found{$name} = 1; |
2031
|
115
|
|
|
|
|
96
|
my $v = $vr->{raw}{$name}; |
2032
|
115
|
100
|
|
|
|
167
|
push @raw_values, grep { defined $_ && $_ ne '' } ref $v eq 'ARRAY' ? @$v : $v; |
|
118
|
100
|
|
|
|
406
|
|
2033
|
|
|
|
|
|
|
# Make sure this parameter exists in {ps}, but don't |
2034
|
|
|
|
|
|
|
# change its status if any. |
2035
|
115
|
50
|
|
|
|
249
|
$vr->{ps}{$name} = undef unless exists $vr->{ps}{$name}; |
2036
|
|
|
|
|
|
|
} |
2037
|
|
|
|
|
|
|
|
2038
|
|
|
|
|
|
|
# If more than one of the aliases for this parameter was |
2039
|
|
|
|
|
|
|
# specified, and the 'multiple' option was not specified, |
2040
|
|
|
|
|
|
|
# then generate an error and go on to the next rule. |
2041
|
|
|
|
|
|
|
|
2042
|
170
|
100
|
66
|
|
|
849
|
if ( keys(%names_found) > 1 && ! $rr->{multiple} ) |
|
|
50
|
66
|
|
|
|
|
|
|
100
|
100
|
|
|
|
|
|
|
100
|
|
|
|
|
|
2043
|
|
|
|
|
|
|
{ |
2044
|
1
|
|
|
|
|
9
|
add_error($vr, $rr, 'ERR_MULT_NAMES', { param => [ sort keys %names_found ] }); |
2045
|
1
|
|
|
|
|
4
|
next RULE; |
2046
|
|
|
|
|
|
|
} |
2047
|
|
|
|
|
|
|
|
2048
|
|
|
|
|
|
|
# If a clean value has already been determined for this parameter, |
2049
|
|
|
|
|
|
|
# then it was already recognized by some other rule. |
2050
|
|
|
|
|
|
|
# Consequently, this rule can be ignored. |
2051
|
|
|
|
|
|
|
|
2052
|
|
|
|
|
|
|
elsif ( exists $vr->{clean}{$key} ) |
2053
|
|
|
|
|
|
|
{ |
2054
|
0
|
|
|
|
|
0
|
next RULE; |
2055
|
|
|
|
|
|
|
} |
2056
|
|
|
|
|
|
|
|
2057
|
|
|
|
|
|
|
# If no values were specified for this parameter, check |
2058
|
|
|
|
|
|
|
# to see if the rule includes a default value. If so, use that |
2059
|
|
|
|
|
|
|
# instead and go on to the next rule. |
2060
|
|
|
|
|
|
|
|
2061
|
|
|
|
|
|
|
elsif ( ! @raw_values && exists $rr->{default} ) |
2062
|
|
|
|
|
|
|
{ |
2063
|
1
|
|
|
|
|
3
|
$vr->{clean}{$key} = $rr->{default}; |
2064
|
1
|
|
|
|
|
2
|
push @{$vr->{clean_list}}, $key; |
|
1
|
|
|
|
|
2
|
|
2065
|
1
|
|
|
|
|
4
|
next RULE; |
2066
|
|
|
|
|
|
|
} |
2067
|
|
|
|
|
|
|
|
2068
|
|
|
|
|
|
|
# If more than one value was given and the rule does not include |
2069
|
|
|
|
|
|
|
# the 'multiple' directive, signal an error. |
2070
|
|
|
|
|
|
|
|
2071
|
|
|
|
|
|
|
elsif ( @raw_values > 1 && ! $rr->{multiple} ) |
2072
|
|
|
|
|
|
|
{ |
2073
|
2
|
|
|
|
|
12
|
add_error($vr, $rr, 'ERR_MULT_VALUES', |
2074
|
|
|
|
|
|
|
{ param => [ sort keys %names_found ], value => \@raw_values }); |
2075
|
2
|
|
|
|
|
7
|
next RULE; |
2076
|
|
|
|
|
|
|
} |
2077
|
|
|
|
|
|
|
|
2078
|
|
|
|
|
|
|
# Now we can process the rule. If the 'split' directive was |
2079
|
|
|
|
|
|
|
# given, split the value(s) using the specified regexp. |
2080
|
|
|
|
|
|
|
|
2081
|
166
|
100
|
|
|
|
222
|
if ( $rr->{split} ) |
2082
|
|
|
|
|
|
|
{ |
2083
|
|
|
|
|
|
|
# Split all of the raw values, and discard empty strings. |
2084
|
|
|
|
|
|
|
|
2085
|
22
|
50
|
|
|
|
64
|
my @new_values = grep { defined $_ && $_ ne '' } |
2086
|
20
|
|
|
|
|
23
|
map { split $rr->{split}, $_ } @raw_values; |
|
9
|
|
|
|
|
53
|
|
2087
|
20
|
|
|
|
|
26
|
@raw_values = @new_values; |
2088
|
|
|
|
|
|
|
} |
2089
|
|
|
|
|
|
|
|
2090
|
|
|
|
|
|
|
# If this is a 'flag' parameter and the parameter was present but |
2091
|
|
|
|
|
|
|
# no values were given, assume the value '1'. |
2092
|
|
|
|
|
|
|
|
2093
|
166
|
100
|
100
|
|
|
246
|
if ( $rr->{flag} && keys(%names_found) && ! @raw_values ) |
|
|
|
66
|
|
|
|
|
2094
|
|
|
|
|
|
|
{ |
2095
|
2
|
|
|
|
|
3
|
@raw_values = (1); |
2096
|
|
|
|
|
|
|
} |
2097
|
|
|
|
|
|
|
|
2098
|
|
|
|
|
|
|
# At this point, if there are no values then generate an error if |
2099
|
|
|
|
|
|
|
# the parameter is mandatory. Otherwise just skip this rule. |
2100
|
|
|
|
|
|
|
|
2101
|
166
|
100
|
|
|
|
206
|
unless ( @raw_values ) |
2102
|
|
|
|
|
|
|
{ |
2103
|
|
|
|
|
|
|
add_error($vr, $rr, 'ERR_MANDATORY', { param => $rr->{param} }) |
2104
|
67
|
100
|
|
|
|
111
|
if $rr->{mandatory}; |
2105
|
|
|
|
|
|
|
|
2106
|
67
|
|
|
|
|
115
|
next RULE; |
2107
|
|
|
|
|
|
|
} |
2108
|
|
|
|
|
|
|
|
2109
|
|
|
|
|
|
|
# Now we process each value in turn. |
2110
|
|
|
|
|
|
|
|
2111
|
99
|
|
|
|
|
73
|
my @clean_values; |
2112
|
|
|
|
|
|
|
my $error_flag; |
2113
|
|
|
|
|
|
|
|
2114
|
|
|
|
|
|
|
VALUE: |
2115
|
99
|
|
|
|
|
96
|
foreach my $raw_val ( @raw_values ) |
2116
|
|
|
|
|
|
|
{ |
2117
|
|
|
|
|
|
|
# If no validators were defined, just pass all of the values |
2118
|
|
|
|
|
|
|
# that are not empty. |
2119
|
|
|
|
|
|
|
|
2120
|
111
|
100
|
|
|
|
153
|
unless ( $rr->{validators} ) |
2121
|
|
|
|
|
|
|
{ |
2122
|
40
|
50
|
33
|
|
|
109
|
if ( defined $raw_val && $raw_val ne '' ) |
2123
|
|
|
|
|
|
|
{ |
2124
|
40
|
100
|
|
|
|
98
|
$raw_val = $rr->{cleaner}($raw_val) if ref $rr->{cleaner} eq 'CODE'; |
2125
|
40
|
|
|
|
|
41
|
push @clean_values, $raw_val; |
2126
|
|
|
|
|
|
|
} |
2127
|
|
|
|
|
|
|
|
2128
|
40
|
|
|
|
|
41
|
next VALUE; |
2129
|
|
|
|
|
|
|
} |
2130
|
|
|
|
|
|
|
|
2131
|
|
|
|
|
|
|
# Otherwise, check each value against the validators in turn until |
2132
|
|
|
|
|
|
|
# one of them passes the value or until we have tried them |
2133
|
|
|
|
|
|
|
# all. |
2134
|
|
|
|
|
|
|
|
2135
|
71
|
|
|
|
|
49
|
my $result; |
2136
|
|
|
|
|
|
|
|
2137
|
|
|
|
|
|
|
VALIDATOR: |
2138
|
71
|
|
|
|
|
39
|
foreach my $validator ( @{$rr->{validators}} ) |
|
71
|
|
|
|
|
87
|
|
2139
|
|
|
|
|
|
|
{ |
2140
|
71
|
|
|
|
|
111
|
$result = $validator->($raw_val, $vr->{context}); |
2141
|
|
|
|
|
|
|
|
2142
|
|
|
|
|
|
|
# If the result is not a hash ref, then the value passes |
2143
|
|
|
|
|
|
|
# the test. |
2144
|
|
|
|
|
|
|
|
2145
|
71
|
100
|
66
|
|
|
300
|
last VALIDATOR unless ref $result && reftype $result eq 'HASH'; |
2146
|
|
|
|
|
|
|
|
2147
|
|
|
|
|
|
|
# If the result contains an 'error' key, then we need to |
2148
|
|
|
|
|
|
|
# try the next validator (if any). Otherwise, the value |
2149
|
|
|
|
|
|
|
# passes the test. |
2150
|
|
|
|
|
|
|
|
2151
|
67
|
100
|
|
|
|
110
|
last VALIDATOR unless $result->{error}; |
2152
|
|
|
|
|
|
|
} |
2153
|
|
|
|
|
|
|
|
2154
|
|
|
|
|
|
|
# If the last validator to be tried generated an error, then |
2155
|
|
|
|
|
|
|
# the value is bad. We must report it and skip to the next value. |
2156
|
|
|
|
|
|
|
|
2157
|
71
|
100
|
66
|
|
|
172
|
if ( ref $result and $result->{error} ) |
2158
|
|
|
|
|
|
|
{ |
2159
|
|
|
|
|
|
|
# If the rule contains a 'warn' directive, then generate a |
2160
|
|
|
|
|
|
|
# warning. But the value is still bad, and will be |
2161
|
|
|
|
|
|
|
# ignored. |
2162
|
|
|
|
|
|
|
|
2163
|
25
|
100
|
|
|
|
34
|
if ( $rr->{warn} ) |
2164
|
|
|
|
|
|
|
{ |
2165
|
|
|
|
|
|
|
my $msg = $rr->{warn} ne '1' ? $rr->{warn} : |
2166
|
8
|
50
|
33
|
|
|
41
|
$rr->{ERR_INVALID} || $rr->{errmsg} || $result->{error}; |
2167
|
8
|
|
|
|
|
33
|
add_warning($vr, $rr, $msg, { param => [ keys %names_found ], value => $raw_val }); |
2168
|
|
|
|
|
|
|
} |
2169
|
|
|
|
|
|
|
|
2170
|
|
|
|
|
|
|
# Otherwise, generate an error. |
2171
|
|
|
|
|
|
|
|
2172
|
|
|
|
|
|
|
else |
2173
|
|
|
|
|
|
|
{ |
2174
|
17
|
|
33
|
|
|
48
|
my $msg = $rr->{ERR_INVALID} || $rr->{errmsg} || $result->{error}; |
2175
|
17
|
|
|
|
|
67
|
add_error($vr, $rr, $msg, { param => [ sort keys %names_found ], value => $raw_val }); |
2176
|
|
|
|
|
|
|
} |
2177
|
|
|
|
|
|
|
|
2178
|
25
|
|
|
|
|
42
|
$error_flag = 1; |
2179
|
25
|
|
|
|
|
38
|
next VALUE; |
2180
|
|
|
|
|
|
|
} |
2181
|
|
|
|
|
|
|
|
2182
|
|
|
|
|
|
|
# If the result contains a 'warn' field, then generate a |
2183
|
|
|
|
|
|
|
# warning. In this case, the value is still assumed to be |
2184
|
|
|
|
|
|
|
# good. |
2185
|
|
|
|
|
|
|
|
2186
|
46
|
100
|
66
|
|
|
98
|
if ( ref $result and $result->{warn} ) |
2187
|
|
|
|
|
|
|
{ |
2188
|
1
|
|
|
|
|
6
|
add_warning($vr, $rr, $result->{warn}, { param => [ sort keys %names_found ], value => $raw_val }); |
2189
|
|
|
|
|
|
|
} |
2190
|
|
|
|
|
|
|
|
2191
|
|
|
|
|
|
|
# If we get here, then the value is good. If the result was a |
2192
|
|
|
|
|
|
|
# hash ref with a 'value' field, we use that for the clean |
2193
|
|
|
|
|
|
|
# value. Otherwise, we use the raw value. |
2194
|
|
|
|
|
|
|
|
2195
|
46
|
100
|
66
|
|
|
105
|
my $value = ref $result && exists $result->{value} ? $result->{value} : $raw_val; |
2196
|
|
|
|
|
|
|
|
2197
|
|
|
|
|
|
|
# If a cleaning subroutine was defined, pass the value through |
2198
|
|
|
|
|
|
|
# it and save the cleaned value. |
2199
|
|
|
|
|
|
|
|
2200
|
46
|
50
|
|
|
|
64
|
$value = $rr->{cleaner}($value) if ref $rr->{cleaner} eq 'CODE'; |
2201
|
|
|
|
|
|
|
|
2202
|
46
|
|
|
|
|
77
|
push @clean_values, $value; |
2203
|
|
|
|
|
|
|
} |
2204
|
|
|
|
|
|
|
|
2205
|
|
|
|
|
|
|
# If clean values were found, store them. If multiple values are |
2206
|
|
|
|
|
|
|
# allowed, then we store them as a list. Otherwise, there should |
2207
|
|
|
|
|
|
|
# only be one clean value and so we just store it as a scalar. |
2208
|
|
|
|
|
|
|
|
2209
|
99
|
100
|
|
|
|
113
|
if ( @clean_values ) |
2210
|
|
|
|
|
|
|
{ |
2211
|
78
|
|
|
|
|
55
|
push @{$vr->{clean_list}}, $key; |
|
78
|
|
|
|
|
105
|
|
2212
|
|
|
|
|
|
|
|
2213
|
78
|
100
|
|
|
|
95
|
if ( $rr->{multiple} ) |
2214
|
|
|
|
|
|
|
{ |
2215
|
7
|
|
|
|
|
10
|
$vr->{clean}{$key} = \@clean_values; |
2216
|
|
|
|
|
|
|
} |
2217
|
|
|
|
|
|
|
|
2218
|
|
|
|
|
|
|
else |
2219
|
|
|
|
|
|
|
{ |
2220
|
71
|
|
|
|
|
91
|
$vr->{clean}{$key} = $clean_values[0]; |
2221
|
|
|
|
|
|
|
} |
2222
|
|
|
|
|
|
|
} |
2223
|
|
|
|
|
|
|
|
2224
|
|
|
|
|
|
|
# If raw values were found for this parameter, but none of them |
2225
|
|
|
|
|
|
|
# pass the validators, then we need to indicate this condition. |
2226
|
|
|
|
|
|
|
|
2227
|
|
|
|
|
|
|
else |
2228
|
|
|
|
|
|
|
{ |
2229
|
21
|
|
|
|
|
17
|
push @{$vr->{clean_list}}, $key; |
|
21
|
|
|
|
|
30
|
|
2230
|
|
|
|
|
|
|
|
2231
|
21
|
100
|
100
|
|
|
60
|
if ( defined $rr->{bad_value} && $rr->{bad_value} eq 'ERROR' ) |
|
|
100
|
|
|
|
|
|
2232
|
|
|
|
|
|
|
{ |
2233
|
2
|
|
|
|
|
12
|
add_error($vr, $rr, 'ERR_BAD_VALUES', |
2234
|
|
|
|
|
|
|
{ param => [ sort keys %names_found ], value => \@raw_values }); |
2235
|
2
|
|
|
|
|
5
|
$vr->{clean}{$key} = undef; |
2236
|
2
|
|
|
|
|
4
|
$error_flag = 1; |
2237
|
|
|
|
|
|
|
} |
2238
|
|
|
|
|
|
|
|
2239
|
|
|
|
|
|
|
elsif ( defined $rr->{bad_value} ) |
2240
|
|
|
|
|
|
|
{ |
2241
|
1
|
50
|
|
|
|
8
|
$vr->{clean}{$key} = $rr->{multiple} ? [ $rr->{bad_value} ] : $rr->{bad_value}; |
2242
|
|
|
|
|
|
|
} |
2243
|
|
|
|
|
|
|
|
2244
|
|
|
|
|
|
|
else |
2245
|
|
|
|
|
|
|
{ |
2246
|
18
|
|
|
|
|
22
|
$vr->{clean}{$key} = undef; |
2247
|
|
|
|
|
|
|
} |
2248
|
|
|
|
|
|
|
} |
2249
|
|
|
|
|
|
|
|
2250
|
|
|
|
|
|
|
# Set the status of this parameter to 1 (passed) unless an error |
2251
|
|
|
|
|
|
|
# was generated, 0 (failed) otherwise. |
2252
|
|
|
|
|
|
|
|
2253
|
99
|
100
|
|
|
|
136
|
$vr->{ps}{$param} = $error_flag ? 0 : 1; |
2254
|
|
|
|
|
|
|
|
2255
|
|
|
|
|
|
|
# If this rule is not 'optional', then set the status of this |
2256
|
|
|
|
|
|
|
# ruleset to 'fulfilled' (2). That does not mean that the validation |
2257
|
|
|
|
|
|
|
# passes, because the parameter value may still have generated an |
2258
|
|
|
|
|
|
|
# error. |
2259
|
|
|
|
|
|
|
|
2260
|
99
|
100
|
|
|
|
163
|
unless ( $rr->{optional} ) |
2261
|
|
|
|
|
|
|
{ |
2262
|
77
|
|
|
|
|
152
|
$vr->{rs}{$ruleset_name} = 2; |
2263
|
|
|
|
|
|
|
} |
2264
|
|
|
|
|
|
|
} |
2265
|
|
|
|
|
|
|
|
2266
|
|
|
|
|
|
|
# An 'ignore' directive causes the parameter to be recognized, but no |
2267
|
|
|
|
|
|
|
# cleaned value is generated and the containing ruleset is not |
2268
|
|
|
|
|
|
|
# triggered. No error messages will be generated for this parameter, |
2269
|
|
|
|
|
|
|
# either. |
2270
|
|
|
|
|
|
|
|
2271
|
|
|
|
|
|
|
elsif ( $rr->{type} eq 'ignore' ) |
2272
|
|
|
|
|
|
|
{ |
2273
|
|
|
|
|
|
|
# Make sure that the parameter is counted as having been |
2274
|
|
|
|
|
|
|
# recognized. |
2275
|
|
|
|
|
|
|
|
2276
|
0
|
|
|
|
|
0
|
foreach my $param ( @{$rr->{param}} ) |
|
0
|
|
|
|
|
0
|
|
2277
|
|
|
|
|
|
|
{ |
2278
|
0
|
|
|
|
|
0
|
$vr->{ps}{$param} = undef; |
2279
|
|
|
|
|
|
|
|
2280
|
|
|
|
|
|
|
# Make sure that errors, warnings, and cleaned values for this key |
2281
|
|
|
|
|
|
|
# are ignored. |
2282
|
|
|
|
|
|
|
|
2283
|
0
|
|
0
|
|
|
0
|
my $key = $rr->{key} || $param; |
2284
|
0
|
|
|
|
|
0
|
$vr->{ig}{$key} = 1; |
2285
|
0
|
|
|
|
|
0
|
delete $vr->{clean}{$param}; |
2286
|
|
|
|
|
|
|
} |
2287
|
|
|
|
|
|
|
} |
2288
|
|
|
|
|
|
|
|
2289
|
|
|
|
|
|
|
# A 'together' or 'at_most_one' rule requires checking the presence |
2290
|
|
|
|
|
|
|
# of each of the specified parameters. This kind of rule does not |
2291
|
|
|
|
|
|
|
# affect the status of any parameters or rulesets, but if violated |
2292
|
|
|
|
|
|
|
# will generate an error message and cause the entire validation to |
2293
|
|
|
|
|
|
|
# fail. |
2294
|
|
|
|
|
|
|
|
2295
|
|
|
|
|
|
|
elsif ( $rr->{type} eq 'together' or $rr->{type} eq 'at_most_one' ) |
2296
|
|
|
|
|
|
|
{ |
2297
|
|
|
|
|
|
|
# We start by listing those that are present in the parameter set. |
2298
|
|
|
|
|
|
|
|
2299
|
12
|
|
|
|
|
8
|
my @present = grep exists $vr->{raw}{$_}, @{$rr->{param}}; |
|
12
|
|
|
|
|
34
|
|
2300
|
|
|
|
|
|
|
|
2301
|
|
|
|
|
|
|
# For a 'together' rule, the count must equal the number of |
2302
|
|
|
|
|
|
|
# arguments to this rule, or must be zero. In other words, there |
2303
|
|
|
|
|
|
|
# must be none present or all present. |
2304
|
|
|
|
|
|
|
|
2305
|
12
|
100
|
100
|
|
|
71
|
if ( $rr->{type} eq 'together' and @present > 0 and @present < @{$rr->{param}} ) |
|
1
|
100
|
66
|
|
|
4
|
|
|
|
|
100
|
|
|
|
|
2306
|
|
|
|
|
|
|
{ |
2307
|
1
|
|
|
|
|
7
|
add_error_warn($vr, $rr, 'ERR_TOGETHER', { param => $rr->{param} }); |
2308
|
|
|
|
|
|
|
} |
2309
|
|
|
|
|
|
|
|
2310
|
|
|
|
|
|
|
# For a 'at_most_one' rule, the count must be less than or equal |
2311
|
|
|
|
|
|
|
# to one (i.e. not more than one must have been specified). |
2312
|
|
|
|
|
|
|
|
2313
|
|
|
|
|
|
|
elsif ( $rr->{type} eq 'at_most_one' and @present > 1 ) |
2314
|
|
|
|
|
|
|
{ |
2315
|
2
|
|
|
|
|
6
|
add_error_warn($vr, $rr, 'ERR_AT_MOST', { param => \@present }); |
2316
|
|
|
|
|
|
|
} |
2317
|
|
|
|
|
|
|
} |
2318
|
|
|
|
|
|
|
|
2319
|
|
|
|
|
|
|
# For an 'include' rule, we immediately check the given ruleset |
2320
|
|
|
|
|
|
|
# (unless it has already been checked). This statement essentially |
2321
|
|
|
|
|
|
|
# includes one ruleset within another. It is very powerful, because |
2322
|
|
|
|
|
|
|
# it allows different route handlers to to validate their parameters |
2323
|
|
|
|
|
|
|
# using common rulesets. |
2324
|
|
|
|
|
|
|
|
2325
|
|
|
|
|
|
|
elsif ( $rr->{type} eq 'include' ) |
2326
|
|
|
|
|
|
|
{ |
2327
|
22
|
|
|
|
|
24
|
my $rs_name = $rr->{ruleset}; |
2328
|
|
|
|
|
|
|
|
2329
|
|
|
|
|
|
|
# First try to validate the given ruleset. |
2330
|
|
|
|
|
|
|
|
2331
|
22
|
|
|
|
|
60
|
$self->validate_ruleset($vr, $rs_name); |
2332
|
|
|
|
|
|
|
|
2333
|
|
|
|
|
|
|
# If it was a 'require' rule, check to see if the ruleset was |
2334
|
|
|
|
|
|
|
# fulfilled. |
2335
|
|
|
|
|
|
|
|
2336
|
22
|
100
|
100
|
|
|
62
|
if ( $rr->{require} and not $vr->{rs}{$rs_name} == 2 ) |
2337
|
|
|
|
|
|
|
{ |
2338
|
1
|
|
|
|
|
2
|
my (@missing, %found); |
2339
|
|
|
|
|
|
|
|
2340
|
1
|
|
|
|
|
1
|
@missing = grep { unique($_, \%found) } @{$self->{RULESETS}{$rs_name}{fulfill_order}}; |
|
2
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
3
|
|
2341
|
|
|
|
|
|
|
|
2342
|
1
|
50
|
|
|
|
5
|
my $msg = @missing == 1 ? 'ERR_REQ_SINGLE' : 'ERR_REQ_MULT'; |
2343
|
1
|
|
|
|
|
9
|
add_error_warn($vr, $rr, $msg, { param => \@missing }); |
2344
|
|
|
|
|
|
|
} |
2345
|
|
|
|
|
|
|
} |
2346
|
|
|
|
|
|
|
|
2347
|
|
|
|
|
|
|
elsif ( $rr->{type} eq 'constraint' ) |
2348
|
|
|
|
|
|
|
{ |
2349
|
|
|
|
|
|
|
# From the list of rulesets specified in this rule, check how many |
2350
|
|
|
|
|
|
|
# were and were not fulfilled. |
2351
|
|
|
|
|
|
|
|
2352
|
6
|
|
|
|
|
4
|
my @fulfilled = grep { $vr->{rs}{$_} == 2 } @{$rr->{ruleset}}; |
|
12
|
|
|
|
|
27
|
|
|
6
|
|
|
|
|
10
|
|
2353
|
6
|
|
|
|
|
5
|
my @not_fulfilled = grep { $vr->{rs}{$_} != 2 } @{$rr->{ruleset}}; |
|
12
|
|
|
|
|
22
|
|
|
6
|
|
|
|
|
15
|
|
2354
|
|
|
|
|
|
|
|
2355
|
|
|
|
|
|
|
# For a 'require_one' or 'require_any' rule, generate an error if |
2356
|
|
|
|
|
|
|
# not enough of the rulesets are fulfilled. List all of the |
2357
|
|
|
|
|
|
|
# parameters which could be given in order to fulfill these |
2358
|
|
|
|
|
|
|
# rulesets. |
2359
|
|
|
|
|
|
|
|
2360
|
6
|
100
|
66
|
|
|
45
|
if ( @fulfilled == 0 and ( $rr->{constraint} eq 'require_one' or |
|
|
50
|
66
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
2361
|
|
|
|
|
|
|
$rr->{constraint} eq 'require_any' ) ) |
2362
|
|
|
|
|
|
|
{ |
2363
|
4
|
|
|
|
|
4
|
my (@missing, %found); |
2364
|
|
|
|
|
|
|
|
2365
|
12
|
|
|
|
|
15
|
@missing = grep { unique($_, \%found) } |
2366
|
4
|
|
|
|
|
4
|
map { @{$self->{RULESETS}{$_}{fulfill_order}} } @not_fulfilled; |
|
8
|
|
|
|
|
5
|
|
|
8
|
|
|
|
|
16
|
|
2367
|
|
|
|
|
|
|
|
2368
|
4
|
50
|
|
|
|
7
|
my $msg = @missing == 1 ? 'ERR_REQ_SINGLE' : 'ERR_REQ_MULT'; |
2369
|
4
|
|
|
|
|
9
|
add_error_warn($vr, $rr, $msg, { param => \@missing }); |
2370
|
|
|
|
|
|
|
} |
2371
|
|
|
|
|
|
|
|
2372
|
|
|
|
|
|
|
# For an 'allow_one' or 'require_one' rule, generate an error if |
2373
|
|
|
|
|
|
|
# more than one of the rulesets was fulfilled. |
2374
|
|
|
|
|
|
|
|
2375
|
|
|
|
|
|
|
elsif ( @fulfilled > 1 and ($rr->{constraint} eq 'allow_one' or |
2376
|
|
|
|
|
|
|
$rr->{constraint} eq 'require_one') ) |
2377
|
|
|
|
|
|
|
{ |
2378
|
2
|
|
|
|
|
2
|
my @params; |
2379
|
2
|
|
|
|
|
3
|
my ($label) = "A"; |
2380
|
|
|
|
|
|
|
|
2381
|
2
|
|
|
|
|
4
|
foreach my $rs ( @fulfilled ) |
2382
|
|
|
|
|
|
|
{ |
2383
|
4
|
|
|
|
|
8
|
push @params, "($label)"; $label++; |
|
4
|
|
|
|
|
4
|
|
2384
|
4
|
|
|
|
|
9
|
push @params, @{$self->{RULESETS}{$rs}{fulfill_order}} |
2385
|
4
|
50
|
|
|
|
17
|
if ref $self->{RULESETS}{$rs}{fulfill_order} eq 'ARRAY'; |
2386
|
|
|
|
|
|
|
} |
2387
|
|
|
|
|
|
|
|
2388
|
2
|
|
|
|
|
4
|
my $message = 'ERR_REQ_ONE'; |
2389
|
|
|
|
|
|
|
|
2390
|
2
|
|
|
|
|
7
|
add_error_warn($vr, $rr, 'ERR_REQ_ONE', { param => \@params }); |
2391
|
|
|
|
|
|
|
} |
2392
|
|
|
|
|
|
|
} |
2393
|
|
|
|
|
|
|
|
2394
|
|
|
|
|
|
|
# For a 'content_type' rule, we set the content type of the response |
2395
|
|
|
|
|
|
|
# according to the given parameter. |
2396
|
|
|
|
|
|
|
|
2397
|
|
|
|
|
|
|
elsif ( $type eq 'content_type' ) |
2398
|
|
|
|
|
|
|
{ |
2399
|
4
|
|
|
|
|
5
|
my $param = $rr->{param}; |
2400
|
4
|
|
100
|
|
|
14
|
my $value = $vr->{raw}{$param} || ''; |
2401
|
4
|
|
33
|
|
|
12
|
my $clean_name = $rr->{key} || $rr->{param}; |
2402
|
4
|
|
|
|
|
8
|
my ($selected, $selected_type); |
2403
|
|
|
|
|
|
|
|
2404
|
4
|
|
|
|
|
3
|
push @{$vr->{clean_list}}, $key; |
|
4
|
|
|
|
|
7
|
|
2405
|
|
|
|
|
|
|
|
2406
|
4
|
100
|
|
|
|
9
|
if ( $rr->{type_map}{$value} ) |
2407
|
|
|
|
|
|
|
{ |
2408
|
3
|
|
|
|
|
6
|
$vr->{content_type} = $rr->{type_map}{$value}; |
2409
|
3
|
|
|
|
|
3
|
$vr->{clean}{$clean_name} = $value; |
2410
|
3
|
|
|
|
|
8
|
$vr->{ps}{$param} = 1; |
2411
|
|
|
|
|
|
|
} |
2412
|
|
|
|
|
|
|
|
2413
|
|
|
|
|
|
|
else |
2414
|
|
|
|
|
|
|
{ |
2415
|
1
|
|
|
|
|
3
|
$vr->{content_type} = 'unknown'; |
2416
|
1
|
|
|
|
|
2
|
$vr->{clean}{$clean_name} = undef; |
2417
|
1
|
|
|
|
|
2
|
$vr->{ps}{$param} = 1; |
2418
|
1
|
|
50
|
|
|
5
|
$rr->{key} ||= '_content_type'; |
2419
|
1
|
|
|
|
|
9
|
add_error_warn($vr, $rr, 'ERR_MEDIA_TYPE', { param => $param, value => $rr->{type_list} }); |
2420
|
|
|
|
|
|
|
} |
2421
|
|
|
|
|
|
|
} |
2422
|
|
|
|
|
|
|
} |
2423
|
|
|
|
|
|
|
}; |
2424
|
|
|
|
|
|
|
|
2425
|
|
|
|
|
|
|
|
2426
|
|
|
|
|
|
|
# Helper function - given a hashref to use as a scratchpad, returns true the |
2427
|
|
|
|
|
|
|
# first time a given argument is encountered and false each subsequent time. |
2428
|
|
|
|
|
|
|
# This can be reset by calling it with a newly emptied scratchpad. |
2429
|
|
|
|
|
|
|
|
2430
|
|
|
|
|
|
|
sub unique { |
2431
|
|
|
|
|
|
|
|
2432
|
14
|
|
|
14
|
0
|
13
|
my ($arg, $scratch) = @_; |
2433
|
|
|
|
|
|
|
|
2434
|
14
|
50
|
|
|
|
20
|
return if exists $scratch->{$arg}; |
2435
|
14
|
|
|
|
|
22
|
$scratch->{$arg} = 1; |
2436
|
|
|
|
|
|
|
} |
2437
|
|
|
|
|
|
|
|
2438
|
|
|
|
|
|
|
|
2439
|
|
|
|
|
|
|
# Add an error message to the current validation. |
2440
|
|
|
|
|
|
|
|
2441
|
|
|
|
|
|
|
sub add_error { |
2442
|
|
|
|
|
|
|
|
2443
|
34
|
|
|
34
|
0
|
35
|
my ($vr, $rr, $msg, $subst) = @_; |
2444
|
|
|
|
|
|
|
|
2445
|
|
|
|
|
|
|
# If no message was given, use a default one. It's not a very good |
2446
|
|
|
|
|
|
|
# message, but what can we do? |
2447
|
|
|
|
|
|
|
|
2448
|
34
|
|
50
|
|
|
56
|
$msg ||= 'ERR_DEFAULT'; |
2449
|
|
|
|
|
|
|
|
2450
|
|
|
|
|
|
|
# If the given message starts with 'ERR_', assume it is an error code. If |
2451
|
|
|
|
|
|
|
# the code is present as an attribute of the rule record, use the |
2452
|
|
|
|
|
|
|
# corresponding value as the message. Otherwise, use the global value. |
2453
|
|
|
|
|
|
|
|
2454
|
34
|
100
|
|
|
|
173
|
if ( $msg =~ qr{^ERR_} ) |
2455
|
|
|
|
|
|
|
{ |
2456
|
17
|
|
33
|
|
|
67
|
$msg = $rr->{$msg} || $vr->{settings}{$msg} || $ERROR_MSG{$msg} || $ERROR_MSG{ERR_DEFAULT}; |
2457
|
|
|
|
|
|
|
} |
2458
|
|
|
|
|
|
|
|
2459
|
|
|
|
|
|
|
# Next, figure out the error key. If the rule has a 'key' directive, use |
2460
|
|
|
|
|
|
|
# that. Otherwise determine it according to the rule type, ruleset name, |
2461
|
|
|
|
|
|
|
# and rule number. |
2462
|
|
|
|
|
|
|
|
2463
|
|
|
|
|
|
|
my $err_key = $rr->{key} ? $rr->{key} |
2464
|
|
|
|
|
|
|
: $rr->{type} eq 'param' ? $rr->{param} |
2465
|
34
|
50
|
|
|
|
118
|
: $rr->{type} eq 'content_type' ? '_content_type' |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
2466
|
|
|
|
|
|
|
: "_$rr->{rs}{name}_$rr->{rn}"; |
2467
|
|
|
|
|
|
|
|
2468
|
|
|
|
|
|
|
# Record the error message under the key, and add the key to the error |
2469
|
|
|
|
|
|
|
# list. Other rules might later remove or alter the error |
2470
|
|
|
|
|
|
|
# message. |
2471
|
|
|
|
|
|
|
|
2472
|
34
|
|
|
|
|
18
|
push @{$vr->{er}}, [$err_key, subst_error($msg, $subst)]; |
|
34
|
|
|
|
|
72
|
|
2473
|
34
|
|
|
|
|
111
|
$vr->{ec}{$err_key}++; |
2474
|
|
|
|
|
|
|
} |
2475
|
|
|
|
|
|
|
|
2476
|
|
|
|
|
|
|
|
2477
|
|
|
|
|
|
|
# Add a warning message to the current validation. The $subst hash if |
2478
|
|
|
|
|
|
|
# given specifies placeholder substitutions. |
2479
|
|
|
|
|
|
|
|
2480
|
|
|
|
|
|
|
sub add_warning { |
2481
|
|
|
|
|
|
|
|
2482
|
11
|
|
|
11
|
0
|
14
|
my ($vr, $rr, $msg, $subst) = @_; |
2483
|
|
|
|
|
|
|
|
2484
|
|
|
|
|
|
|
# If no message was given, use a default one. It's not a very good |
2485
|
|
|
|
|
|
|
# message, but what can we do? |
2486
|
|
|
|
|
|
|
|
2487
|
11
|
|
50
|
|
|
20
|
$msg ||= 'ERR_DEFAULT'; |
2488
|
|
|
|
|
|
|
|
2489
|
|
|
|
|
|
|
# If the given message starts with 'ERR_', assume it is an error code. If |
2490
|
|
|
|
|
|
|
# the code is present as an attribute of the rule record, use the |
2491
|
|
|
|
|
|
|
# corresponding value as the message. Otherwise, use the global value. |
2492
|
|
|
|
|
|
|
|
2493
|
11
|
100
|
|
|
|
54
|
if ( $msg =~ qr{^ERR_} ) |
2494
|
|
|
|
|
|
|
{ |
2495
|
1
|
|
0
|
|
|
6
|
$msg = $rr->{$msg} || $vr->{settings}{$msg} || $ERROR_MSG{$msg} || $ERROR_MSG{ERR_DEFAULT}; |
2496
|
|
|
|
|
|
|
} |
2497
|
|
|
|
|
|
|
|
2498
|
|
|
|
|
|
|
# Next, figure out the warning key. If the rule has a 'key' directive, use |
2499
|
|
|
|
|
|
|
# that. Otherwise determine it according to the rule type, ruleset name, |
2500
|
|
|
|
|
|
|
# and rule number. |
2501
|
|
|
|
|
|
|
|
2502
|
|
|
|
|
|
|
my $warn_key = $rr->{key} ? $rr->{key} |
2503
|
|
|
|
|
|
|
: $rr->{type} eq 'param' ? $rr->{param} |
2504
|
11
|
50
|
|
|
|
42
|
: $rr->{type} eq 'content_type' ? '_content_type' |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
2505
|
|
|
|
|
|
|
: "_$rr->{rs}{name}_$rr->{rn}"; |
2506
|
|
|
|
|
|
|
|
2507
|
|
|
|
|
|
|
# Record the warning message under the key. Other rules might later |
2508
|
|
|
|
|
|
|
# alter the warning message if they use the same key. |
2509
|
|
|
|
|
|
|
|
2510
|
11
|
|
|
|
|
12
|
push @{$vr->{wn}}, [$warn_key, subst_error($msg, $subst)]; |
|
11
|
|
|
|
|
24
|
|
2511
|
11
|
|
|
|
|
31
|
$vr->{wc}{$warn_key}++; |
2512
|
|
|
|
|
|
|
} |
2513
|
|
|
|
|
|
|
|
2514
|
|
|
|
|
|
|
|
2515
|
|
|
|
|
|
|
# Add an error or warning message to the current validation. If the rule has |
2516
|
|
|
|
|
|
|
# a 'warn' attribute, add a warning. Otherwise, add an error. If the rule |
2517
|
|
|
|
|
|
|
# has an 'errmsg' attribute, use its value instead of the error message given. |
2518
|
|
|
|
|
|
|
|
2519
|
|
|
|
|
|
|
sub add_error_warn { |
2520
|
|
|
|
|
|
|
|
2521
|
11
|
|
|
11
|
0
|
12
|
my ($vr, $rr, $msg, $subst) = @_; |
2522
|
|
|
|
|
|
|
|
2523
|
11
|
50
|
|
|
|
20
|
$msg = $rr->{errmsg} if $rr->{errmsg}; |
2524
|
|
|
|
|
|
|
|
2525
|
11
|
100
|
|
|
|
18
|
if ( $rr->{warn} ) |
2526
|
|
|
|
|
|
|
{ |
2527
|
2
|
100
|
|
|
|
5
|
$msg = $rr->{warn} if $rr->{warn} ne '1'; |
2528
|
2
|
|
|
|
|
4
|
return add_warning($vr, $rr, $msg, $subst); |
2529
|
|
|
|
|
|
|
} |
2530
|
|
|
|
|
|
|
|
2531
|
|
|
|
|
|
|
else |
2532
|
|
|
|
|
|
|
{ |
2533
|
9
|
|
|
|
|
12
|
return add_error($vr, $rr, $msg, $subst); |
2534
|
|
|
|
|
|
|
} |
2535
|
|
|
|
|
|
|
} |
2536
|
|
|
|
|
|
|
|
2537
|
|
|
|
|
|
|
|
2538
|
|
|
|
|
|
|
# Substitute placeholders in an error or warning message. |
2539
|
|
|
|
|
|
|
|
2540
|
|
|
|
|
|
|
sub subst_error { |
2541
|
|
|
|
|
|
|
|
2542
|
45
|
|
|
45
|
0
|
44
|
my ($message, $subst) = @_; |
2543
|
|
|
|
|
|
|
|
2544
|
45
|
|
|
|
|
159
|
while ( $message =~ /^(.*)\{(\w+)\}(.*)$/ ) |
2545
|
|
|
|
|
|
|
{ |
2546
|
46
|
|
|
|
|
73
|
my $value = $subst->{$2}; |
2547
|
|
|
|
|
|
|
|
2548
|
46
|
100
|
33
|
|
|
86
|
if ( ref $value ) |
|
|
50
|
|
|
|
|
|
2549
|
|
|
|
|
|
|
{ |
2550
|
42
|
50
|
|
|
|
83
|
if ( reftype $value eq 'ARRAY' ) |
|
|
0
|
|
|
|
|
|
2551
|
|
|
|
|
|
|
{ |
2552
|
42
|
|
|
|
|
53
|
$value = name_list(@$value); |
2553
|
|
|
|
|
|
|
} |
2554
|
|
|
|
|
|
|
elsif ( reftype $value eq 'HASH' ) |
2555
|
|
|
|
|
|
|
{ |
2556
|
0
|
|
|
|
|
0
|
$value = name_list(sort keys %$value); |
2557
|
|
|
|
|
|
|
} |
2558
|
|
|
|
|
|
|
} |
2559
|
|
|
|
|
|
|
|
2560
|
|
|
|
|
|
|
elsif ( defined $value && $value !~ /^'/ ) |
2561
|
|
|
|
|
|
|
{ |
2562
|
4
|
|
|
|
|
9
|
$value = "'$value'"; |
2563
|
|
|
|
|
|
|
} |
2564
|
|
|
|
|
|
|
|
2565
|
|
|
|
|
|
|
else |
2566
|
|
|
|
|
|
|
{ |
2567
|
0
|
|
|
|
|
0
|
$value = "''"; |
2568
|
|
|
|
|
|
|
} |
2569
|
|
|
|
|
|
|
|
2570
|
46
|
50
|
33
|
|
|
284
|
$message = "$1$value$3" if defined $value and $value ne ''; |
2571
|
|
|
|
|
|
|
} |
2572
|
|
|
|
|
|
|
|
2573
|
45
|
|
|
|
|
76
|
return $message; |
2574
|
|
|
|
|
|
|
} |
2575
|
|
|
|
|
|
|
|
2576
|
|
|
|
|
|
|
|
2577
|
|
|
|
|
|
|
# Generate a list of quoted strings from the specified values. |
2578
|
|
|
|
|
|
|
|
2579
|
|
|
|
|
|
|
sub name_list { |
2580
|
|
|
|
|
|
|
|
2581
|
42
|
|
|
42
|
0
|
53
|
my @names = @_; |
2582
|
|
|
|
|
|
|
|
2583
|
42
|
50
|
|
|
|
66
|
return unless @names; |
2584
|
42
|
|
|
|
|
111
|
return "'" . join("', '", @names) . "'"; |
2585
|
|
|
|
|
|
|
}; |
2586
|
|
|
|
|
|
|
|
2587
|
|
|
|
|
|
|
|
2588
|
|
|
|
|
|
|
package HTTP::Validate::Result; |
2589
|
|
|
|
|
|
|
|
2590
|
|
|
|
|
|
|
=head1 OTHER METHODS |
2591
|
|
|
|
|
|
|
|
2592
|
|
|
|
|
|
|
The result object returned by L provides the following |
2593
|
|
|
|
|
|
|
methods: |
2594
|
|
|
|
|
|
|
|
2595
|
|
|
|
|
|
|
=head3 passed |
2596
|
|
|
|
|
|
|
|
2597
|
|
|
|
|
|
|
Returns true if the validation passed, false otherwise. |
2598
|
|
|
|
|
|
|
|
2599
|
|
|
|
|
|
|
=cut |
2600
|
|
|
|
|
|
|
|
2601
|
|
|
|
|
|
|
sub passed { |
2602
|
|
|
|
|
|
|
|
2603
|
7
|
|
|
7
|
|
265
|
my ($self) = @_; |
2604
|
|
|
|
|
|
|
|
2605
|
|
|
|
|
|
|
# If any errors occurred, then the validation failed. |
2606
|
|
|
|
|
|
|
|
2607
|
7
|
100
|
66
|
|
|
22
|
return if ref $self->{er} eq 'ARRAY' && @{$self->{er}}; |
|
2
|
|
|
|
|
14
|
|
2608
|
|
|
|
|
|
|
|
2609
|
|
|
|
|
|
|
# Otherwise, it passed. |
2610
|
|
|
|
|
|
|
|
2611
|
5
|
|
|
|
|
14
|
return 1; |
2612
|
|
|
|
|
|
|
} |
2613
|
|
|
|
|
|
|
|
2614
|
|
|
|
|
|
|
|
2615
|
|
|
|
|
|
|
=head3 errors |
2616
|
|
|
|
|
|
|
|
2617
|
|
|
|
|
|
|
In a scalar context, this returns the number of errors generated by this |
2618
|
|
|
|
|
|
|
validation. In a list context, it returns a list of error messages. If an |
2619
|
|
|
|
|
|
|
argument is given, only messages whose key equals the argument are returned. |
2620
|
|
|
|
|
|
|
|
2621
|
|
|
|
|
|
|
=cut |
2622
|
|
|
|
|
|
|
|
2623
|
|
|
|
|
|
|
sub errors { |
2624
|
|
|
|
|
|
|
|
2625
|
50
|
|
|
50
|
|
885
|
my ($self, $key) = @_; |
2626
|
|
|
|
|
|
|
|
2627
|
|
|
|
|
|
|
# In scalar context, just return the count. |
2628
|
|
|
|
|
|
|
|
2629
|
50
|
100
|
|
|
|
92
|
if ( ! wantarray ) |
|
|
100
|
|
|
|
|
|
2630
|
|
|
|
|
|
|
{ |
2631
|
20
|
100
|
|
|
|
86
|
return 0 unless defined $key ? ref $self->{ec} : ref $self->{er}; |
|
|
100
|
|
|
|
|
|
2632
|
8
|
100
|
50
|
|
|
19
|
return defined $key ? ($self->{ec}{$key} || 0) : scalar @{$self->{er}}; |
|
5
|
|
|
|
|
18
|
|
2633
|
|
|
|
|
|
|
} |
2634
|
|
|
|
|
|
|
|
2635
|
|
|
|
|
|
|
# In list context, if a key is given then return just the matching error |
2636
|
|
|
|
|
|
|
# messages or an empty list if there are none. |
2637
|
|
|
|
|
|
|
|
2638
|
|
|
|
|
|
|
elsif ( defined $key ) |
2639
|
|
|
|
|
|
|
{ |
2640
|
4
|
100
|
|
|
|
10
|
return unless ref $self->{ec}; |
2641
|
3
|
|
|
|
|
3
|
return map { $_->[1] } grep { $_->[0] eq $key } @{$self->{er}}; |
|
3
|
|
|
|
|
8
|
|
|
3
|
|
|
|
|
7
|
|
|
3
|
|
|
|
|
5
|
|
2642
|
|
|
|
|
|
|
} |
2643
|
|
|
|
|
|
|
|
2644
|
|
|
|
|
|
|
# If no key is given, just return all of the messages. |
2645
|
|
|
|
|
|
|
|
2646
|
|
|
|
|
|
|
else |
2647
|
|
|
|
|
|
|
{ |
2648
|
26
|
|
|
|
|
22
|
return map { $_->[1] } @{$self->{er}}; |
|
17
|
|
|
|
|
78
|
|
|
26
|
|
|
|
|
47
|
|
2649
|
|
|
|
|
|
|
} |
2650
|
|
|
|
|
|
|
} |
2651
|
|
|
|
|
|
|
|
2652
|
|
|
|
|
|
|
=head3 error_keys |
2653
|
|
|
|
|
|
|
|
2654
|
|
|
|
|
|
|
Returns the list of keys for which error messages were generated. |
2655
|
|
|
|
|
|
|
|
2656
|
|
|
|
|
|
|
=cut |
2657
|
|
|
|
|
|
|
|
2658
|
|
|
|
|
|
|
sub error_keys { |
2659
|
|
|
|
|
|
|
|
2660
|
6
|
|
|
6
|
|
547
|
my ($self) = @_; |
2661
|
6
|
|
|
|
|
5
|
return keys %{$self->{ec}}; |
|
6
|
|
|
|
|
46
|
|
2662
|
|
|
|
|
|
|
} |
2663
|
|
|
|
|
|
|
|
2664
|
|
|
|
|
|
|
|
2665
|
|
|
|
|
|
|
=head3 warnings |
2666
|
|
|
|
|
|
|
|
2667
|
|
|
|
|
|
|
In a scalar context, this returns the number of warnings generated by the |
2668
|
|
|
|
|
|
|
validation. In a list context, it returns a list of warning messages. If an |
2669
|
|
|
|
|
|
|
argument is given, only messages whose key equals the argument are returned. |
2670
|
|
|
|
|
|
|
|
2671
|
|
|
|
|
|
|
=cut |
2672
|
|
|
|
|
|
|
|
2673
|
|
|
|
|
|
|
sub warnings { |
2674
|
|
|
|
|
|
|
|
2675
|
29
|
|
|
29
|
|
1538
|
my ($self, $key) = @_; |
2676
|
|
|
|
|
|
|
|
2677
|
|
|
|
|
|
|
# In scalar context, just return the count. |
2678
|
|
|
|
|
|
|
|
2679
|
29
|
100
|
|
|
|
56
|
if ( ! wantarray ) |
|
|
100
|
|
|
|
|
|
2680
|
|
|
|
|
|
|
{ |
2681
|
18
|
100
|
|
|
|
75
|
return 0 unless defined $key ? ref $self->{wc} : ref $self->{wn}; |
|
|
100
|
|
|
|
|
|
2682
|
6
|
100
|
50
|
|
|
15
|
return defined $key ? ($self->{wc}{$key} || 0) : scalar @{$self->{wn}}; |
|
4
|
|
|
|
|
12
|
|
2683
|
|
|
|
|
|
|
} |
2684
|
|
|
|
|
|
|
|
2685
|
|
|
|
|
|
|
# In list context, if a key is given then return just the matching warning |
2686
|
|
|
|
|
|
|
# messages or an empty list if there are none. |
2687
|
|
|
|
|
|
|
|
2688
|
|
|
|
|
|
|
elsif ( defined $key ) |
2689
|
|
|
|
|
|
|
{ |
2690
|
2
|
50
|
|
|
|
7
|
return unless ref $self->{wn}; |
2691
|
2
|
|
|
|
|
1
|
return map { $_->[1] } grep { $_->[0] eq $key } @{$self->{wn}}; |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
5
|
|
2692
|
|
|
|
|
|
|
} |
2693
|
|
|
|
|
|
|
|
2694
|
|
|
|
|
|
|
# If no key is given, just return all of the messages. |
2695
|
|
|
|
|
|
|
|
2696
|
|
|
|
|
|
|
else |
2697
|
|
|
|
|
|
|
{ |
2698
|
9
|
|
|
|
|
5
|
return map { $_->[1] } @{$self->{wn}}; |
|
6
|
|
|
|
|
14
|
|
|
9
|
|
|
|
|
18
|
|
2699
|
|
|
|
|
|
|
} |
2700
|
|
|
|
|
|
|
} |
2701
|
|
|
|
|
|
|
|
2702
|
|
|
|
|
|
|
|
2703
|
|
|
|
|
|
|
=head3 warning_keys |
2704
|
|
|
|
|
|
|
|
2705
|
|
|
|
|
|
|
Returns the list of keys for which warning messages were generated. |
2706
|
|
|
|
|
|
|
|
2707
|
|
|
|
|
|
|
=cut |
2708
|
|
|
|
|
|
|
|
2709
|
|
|
|
|
|
|
sub warning_keys { |
2710
|
|
|
|
|
|
|
|
2711
|
1
|
|
|
1
|
|
2
|
my ($self) = @_; |
2712
|
1
|
|
|
|
|
2
|
return keys %{$self->{wc}}; |
|
1
|
|
|
|
|
8
|
|
2713
|
|
|
|
|
|
|
} |
2714
|
|
|
|
|
|
|
|
2715
|
|
|
|
|
|
|
|
2716
|
|
|
|
|
|
|
=head3 keys |
2717
|
|
|
|
|
|
|
|
2718
|
|
|
|
|
|
|
In a scalar context, this returns the number of parameters that had valid values. In a list |
2719
|
|
|
|
|
|
|
context, it returns a list of parameter names in the order they were recognized. Individual |
2720
|
|
|
|
|
|
|
parameter values can be gotten by using either L or L. |
2721
|
|
|
|
|
|
|
|
2722
|
|
|
|
|
|
|
=cut |
2723
|
|
|
|
|
|
|
|
2724
|
|
|
|
|
|
|
sub keys { |
2725
|
|
|
|
|
|
|
|
2726
|
5
|
|
|
5
|
|
12
|
my ($self) = @_; |
2727
|
|
|
|
|
|
|
|
2728
|
|
|
|
|
|
|
# Return the list of parameter keys in the order they were recognized. |
2729
|
|
|
|
|
|
|
|
2730
|
5
|
|
|
|
|
5
|
return @{$self->{clean_list}}; |
|
5
|
|
|
|
|
16
|
|
2731
|
|
|
|
|
|
|
} |
2732
|
|
|
|
|
|
|
|
2733
|
|
|
|
|
|
|
|
2734
|
|
|
|
|
|
|
=head3 values |
2735
|
|
|
|
|
|
|
|
2736
|
|
|
|
|
|
|
Returns the hash of clean parameter values. This is not a copy, so any |
2737
|
|
|
|
|
|
|
modifications you make to it will be reflected in subsequent calls to L. |
2738
|
|
|
|
|
|
|
|
2739
|
|
|
|
|
|
|
=cut |
2740
|
|
|
|
|
|
|
|
2741
|
|
|
|
|
|
|
sub values { |
2742
|
|
|
|
|
|
|
|
2743
|
2
|
|
|
2
|
|
7
|
my ($self) = @_; |
2744
|
|
|
|
|
|
|
|
2745
|
|
|
|
|
|
|
# Return the clean value hash. |
2746
|
|
|
|
|
|
|
|
2747
|
2
|
|
|
|
|
3
|
return $self->{clean}; |
2748
|
|
|
|
|
|
|
} |
2749
|
|
|
|
|
|
|
|
2750
|
|
|
|
|
|
|
=head3 value |
2751
|
|
|
|
|
|
|
|
2752
|
|
|
|
|
|
|
Returns the value of the specified parameter, or undef if that parameter was |
2753
|
|
|
|
|
|
|
not specified in the request or if its value was invalid. |
2754
|
|
|
|
|
|
|
|
2755
|
|
|
|
|
|
|
=cut |
2756
|
|
|
|
|
|
|
|
2757
|
|
|
|
|
|
|
sub value { |
2758
|
|
|
|
|
|
|
|
2759
|
54
|
|
|
54
|
|
4064
|
my ($self, $param) = @_; |
2760
|
|
|
|
|
|
|
|
2761
|
54
|
|
|
|
|
171
|
return $self->{clean}{$param}; |
2762
|
|
|
|
|
|
|
} |
2763
|
|
|
|
|
|
|
|
2764
|
|
|
|
|
|
|
|
2765
|
|
|
|
|
|
|
=head3 specified |
2766
|
|
|
|
|
|
|
|
2767
|
|
|
|
|
|
|
Returns true if the specified parameter was specified in the request with at least |
2768
|
|
|
|
|
|
|
one value, whether or not that value was valid. Returns false otherwise. |
2769
|
|
|
|
|
|
|
|
2770
|
|
|
|
|
|
|
=cut |
2771
|
|
|
|
|
|
|
|
2772
|
|
|
|
|
|
|
sub specified { |
2773
|
|
|
|
|
|
|
|
2774
|
5
|
|
|
5
|
|
320
|
my ($self, $param) = @_; |
2775
|
|
|
|
|
|
|
|
2776
|
5
|
|
|
|
|
13
|
return exists $self->{clean}{$param}; |
2777
|
|
|
|
|
|
|
} |
2778
|
|
|
|
|
|
|
|
2779
|
|
|
|
|
|
|
|
2780
|
|
|
|
|
|
|
=head3 raw |
2781
|
|
|
|
|
|
|
|
2782
|
|
|
|
|
|
|
Returns a hash of the raw parameter values as originally provided to |
2783
|
|
|
|
|
|
|
L. Multiple values are represented by array refs. The |
2784
|
|
|
|
|
|
|
result of this method can be used, for example, to redisplay a web form if the |
2785
|
|
|
|
|
|
|
submission resulted in errors. |
2786
|
|
|
|
|
|
|
|
2787
|
|
|
|
|
|
|
=cut |
2788
|
|
|
|
|
|
|
|
2789
|
|
|
|
|
|
|
sub raw { |
2790
|
|
|
|
|
|
|
|
2791
|
1
|
|
|
1
|
|
3
|
my ($self, $param) = @_; |
2792
|
|
|
|
|
|
|
|
2793
|
1
|
|
|
|
|
3
|
return $self->{raw}; |
2794
|
|
|
|
|
|
|
} |
2795
|
|
|
|
|
|
|
|
2796
|
|
|
|
|
|
|
|
2797
|
|
|
|
|
|
|
=head3 content_type |
2798
|
|
|
|
|
|
|
|
2799
|
|
|
|
|
|
|
This returns the content type specified by the request parameters. If none |
2800
|
|
|
|
|
|
|
was specified, or if no content_type rule was included in the validation, it |
2801
|
|
|
|
|
|
|
returns undef. |
2802
|
|
|
|
|
|
|
|
2803
|
|
|
|
|
|
|
=cut |
2804
|
|
|
|
|
|
|
|
2805
|
|
|
|
|
|
|
sub content_type { |
2806
|
|
|
|
|
|
|
|
2807
|
3
|
|
|
3
|
|
262
|
my ($self) = @_; |
2808
|
|
|
|
|
|
|
|
2809
|
3
|
|
|
|
|
12
|
return $self->{content_type}; |
2810
|
|
|
|
|
|
|
} |
2811
|
|
|
|
|
|
|
|
2812
|
|
|
|
|
|
|
|
2813
|
|
|
|
|
|
|
package HTTP::Validate; |
2814
|
|
|
|
|
|
|
|
2815
|
|
|
|
|
|
|
# At the very end, we have the validator functions |
2816
|
|
|
|
|
|
|
# ================================================ |
2817
|
|
|
|
|
|
|
|
2818
|
|
|
|
|
|
|
=head1 VALIDATORS |
2819
|
|
|
|
|
|
|
|
2820
|
|
|
|
|
|
|
Parameter rules can each include one or more validator functions under the key |
2821
|
|
|
|
|
|
|
C. The job of these functions is two-fold: first to check for good |
2822
|
|
|
|
|
|
|
parameter values, and second to generate cleaned values. |
2823
|
|
|
|
|
|
|
|
2824
|
|
|
|
|
|
|
There are a number of validators provided by this module, or you can specify a |
2825
|
|
|
|
|
|
|
reference to a function of your own. |
2826
|
|
|
|
|
|
|
|
2827
|
|
|
|
|
|
|
=head2 Predefined validators |
2828
|
|
|
|
|
|
|
|
2829
|
|
|
|
|
|
|
=head3 INT_VALUE |
2830
|
|
|
|
|
|
|
|
2831
|
|
|
|
|
|
|
This validator accepts any integer, and rejects all other values. It |
2832
|
|
|
|
|
|
|
returns a numeric value, generated by adding 0 to the raw parameter value. |
2833
|
|
|
|
|
|
|
|
2834
|
|
|
|
|
|
|
=head3 INT_VALUE(min,max) |
2835
|
|
|
|
|
|
|
|
2836
|
|
|
|
|
|
|
This validator accepts any integer between C and C (inclusive). If either C |
2837
|
|
|
|
|
|
|
or C is undefined, that bound will not be tested. |
2838
|
|
|
|
|
|
|
|
2839
|
|
|
|
|
|
|
=head3 POS_VALUE |
2840
|
|
|
|
|
|
|
|
2841
|
|
|
|
|
|
|
This is an alias for C. |
2842
|
|
|
|
|
|
|
|
2843
|
|
|
|
|
|
|
=head3 POS_ZERO_VALUE |
2844
|
|
|
|
|
|
|
|
2845
|
|
|
|
|
|
|
This is an alias for C. |
2846
|
|
|
|
|
|
|
|
2847
|
|
|
|
|
|
|
=cut |
2848
|
|
|
|
|
|
|
|
2849
|
|
|
|
|
|
|
sub int_value { |
2850
|
|
|
|
|
|
|
|
2851
|
43
|
|
|
43
|
0
|
48
|
my ($value, $context, $min, $max) = @_; |
2852
|
|
|
|
|
|
|
|
2853
|
43
|
100
|
|
|
|
143
|
unless ( $value =~ /^([+-]?\d+)$/ ) |
2854
|
|
|
|
|
|
|
{ |
2855
|
9
|
|
|
|
|
31
|
return { error => "bad value '$value' for {param}: must be an integer" }; |
2856
|
|
|
|
|
|
|
} |
2857
|
|
|
|
|
|
|
|
2858
|
34
|
100
|
100
|
|
|
125
|
if ( defined $min and $value < $min ) |
2859
|
|
|
|
|
|
|
{ |
2860
|
7
|
50
|
|
|
|
29
|
my $criterion = defined $max ? "between $min and $max" |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
2861
|
|
|
|
|
|
|
: $min == 0 ? "nonnegative" |
2862
|
|
|
|
|
|
|
: $min == 1 ? "positive" |
2863
|
|
|
|
|
|
|
: "at least $min"; |
2864
|
|
|
|
|
|
|
|
2865
|
7
|
|
|
|
|
24
|
return { error => "bad value '$value' for {param}: must be $criterion" }; |
2866
|
|
|
|
|
|
|
} |
2867
|
|
|
|
|
|
|
|
2868
|
27
|
100
|
100
|
|
|
52
|
if ( defined $max and $value > $max ) |
2869
|
|
|
|
|
|
|
{ |
2870
|
1
|
50
|
|
|
|
5
|
my $criterion = defined $min ? "between $min and $max" : "at most $max"; |
2871
|
|
|
|
|
|
|
|
2872
|
1
|
|
|
|
|
4
|
return { error => "bad value '$value' for {param} must be $criterion" }; |
2873
|
|
|
|
|
|
|
} |
2874
|
|
|
|
|
|
|
|
2875
|
26
|
|
|
|
|
59
|
return { value => $value + 0 }; |
2876
|
|
|
|
|
|
|
} |
2877
|
|
|
|
|
|
|
|
2878
|
|
|
|
|
|
|
sub INT_VALUE { |
2879
|
|
|
|
|
|
|
|
2880
|
15
|
|
|
15
|
1
|
1886
|
my ($min, $max) = @_; |
2881
|
|
|
|
|
|
|
|
2882
|
15
|
100
|
100
|
|
|
133
|
croak "lower bound must be an integer (was '$min')" unless !defined $min || $min =~ /^[+-]?\d+$/; |
2883
|
14
|
50
|
66
|
|
|
40
|
croak "upper bound must be an integer (was '$max')" unless !defined $max || $max =~ /^[+-]?\d+$/; |
2884
|
|
|
|
|
|
|
|
2885
|
14
|
100
|
66
|
|
|
72
|
return \&int_value unless defined $min or defined $max; |
2886
|
6
|
|
|
5
|
|
24
|
return sub { return int_value(shift, shift, $min, $max) }; |
|
5
|
|
|
|
|
7
|
|
2887
|
|
|
|
|
|
|
}; |
2888
|
|
|
|
|
|
|
|
2889
|
|
|
|
|
|
|
sub POS_VALUE { |
2890
|
|
|
|
|
|
|
|
2891
|
17
|
|
|
17
|
1
|
2534
|
return sub { return int_value(shift, shift, 1) }; |
|
29
|
|
|
29
|
|
44
|
|
2892
|
|
|
|
|
|
|
}; |
2893
|
|
|
|
|
|
|
|
2894
|
|
|
|
|
|
|
sub POS_ZERO_VALUE { |
2895
|
|
|
|
|
|
|
|
2896
|
4
|
|
|
4
|
1
|
21
|
return sub { return int_value(shift, shift, 0) }; |
|
3
|
|
|
3
|
|
4
|
|
2897
|
|
|
|
|
|
|
}; |
2898
|
|
|
|
|
|
|
|
2899
|
|
|
|
|
|
|
|
2900
|
|
|
|
|
|
|
=head3 DECI_VALUE |
2901
|
|
|
|
|
|
|
|
2902
|
|
|
|
|
|
|
This validator accepts any decimal number, including exponential notation, and |
2903
|
|
|
|
|
|
|
rejects all other values. It returns a numeric value, generated by adding 0 |
2904
|
|
|
|
|
|
|
to the parameter value. |
2905
|
|
|
|
|
|
|
|
2906
|
|
|
|
|
|
|
=head3 DECI_VALUE(min,max) |
2907
|
|
|
|
|
|
|
|
2908
|
|
|
|
|
|
|
This validator accepts any real number between C and C (inclusive). |
2909
|
|
|
|
|
|
|
Specify these bounds in quotes (i.e. as string arguments) if non-zero so that |
2910
|
|
|
|
|
|
|
they will appear properly in error messages. If either C or C is |
2911
|
|
|
|
|
|
|
undefined, that bound will not be tested. |
2912
|
|
|
|
|
|
|
|
2913
|
|
|
|
|
|
|
=cut |
2914
|
|
|
|
|
|
|
|
2915
|
|
|
|
|
|
|
sub deci_value { |
2916
|
|
|
|
|
|
|
|
2917
|
14
|
|
|
14
|
0
|
15
|
my ($value, $context, $min, $max) = @_; |
2918
|
|
|
|
|
|
|
|
2919
|
14
|
100
|
|
|
|
70
|
unless ( $value =~ /^[+-]?(?:\d+\.\d*|\d*\.\d+|\d+)(?:[eE][+-]?\d+)?$/ ) |
2920
|
|
|
|
|
|
|
{ |
2921
|
1
|
|
|
|
|
3
|
return { error => "bad value '$value' for {param}: must be a decimal number" }; |
2922
|
|
|
|
|
|
|
} |
2923
|
|
|
|
|
|
|
|
2924
|
13
|
100
|
66
|
|
|
55
|
if ( defined $min and defined $max and ($value < $min or $value > $max) ) |
|
|
|
100
|
|
|
|
|
|
|
|
66
|
|
|
|
|
2925
|
|
|
|
|
|
|
{ |
2926
|
4
|
|
|
|
|
24
|
return { error => "bad value '$value' for {param}: must be between $min and $max" }; |
2927
|
|
|
|
|
|
|
} |
2928
|
|
|
|
|
|
|
|
2929
|
9
|
50
|
66
|
|
|
17
|
if ( defined $min and $value < $min ) |
2930
|
|
|
|
|
|
|
{ |
2931
|
0
|
|
|
|
|
0
|
return { error => "bad value '$value' for {param}: must be at least $min" }; |
2932
|
|
|
|
|
|
|
} |
2933
|
|
|
|
|
|
|
|
2934
|
9
|
50
|
66
|
|
|
19
|
if ( defined $max and $value > $max ) |
2935
|
|
|
|
|
|
|
{ |
2936
|
0
|
|
|
|
|
0
|
return { error => "bad value '$value' for {param}: must be at most $max" }; |
2937
|
|
|
|
|
|
|
} |
2938
|
|
|
|
|
|
|
|
2939
|
9
|
|
|
|
|
21
|
return { value => $value + 0 }; |
2940
|
|
|
|
|
|
|
} |
2941
|
|
|
|
|
|
|
|
2942
|
|
|
|
|
|
|
sub DECI_VALUE { |
2943
|
|
|
|
|
|
|
|
2944
|
15
|
|
|
15
|
1
|
368
|
my ($min, $max) = @_; |
2945
|
|
|
|
|
|
|
|
2946
|
15
|
100
|
100
|
|
|
107
|
croak "lower bound must be numeric" if defined $min && !looks_like_number($min); |
2947
|
14
|
50
|
66
|
|
|
35
|
croak "upper bound must be numeric" if defined $max && !looks_like_number($max); |
2948
|
|
|
|
|
|
|
|
2949
|
14
|
100
|
66
|
|
|
57
|
return \&deci_value unless defined $min or defined $max; |
2950
|
6
|
|
|
8
|
|
18
|
return sub { return deci_value(shift, shift, $min, $max) }; |
|
8
|
|
|
|
|
11
|
|
2951
|
|
|
|
|
|
|
}; |
2952
|
|
|
|
|
|
|
|
2953
|
|
|
|
|
|
|
|
2954
|
|
|
|
|
|
|
=head3 MATCH_VALUE |
2955
|
|
|
|
|
|
|
|
2956
|
|
|
|
|
|
|
This validator accepts any string that matches the specified pattern, and |
2957
|
|
|
|
|
|
|
rejects any that does not. If you specify the pattern as a string, it will be |
2958
|
|
|
|
|
|
|
converted into a regexp and will have ^ prepended and $ appended, and also the |
2959
|
|
|
|
|
|
|
modifier "i". If you specify the pattern using C, then it is used unchanged. |
2960
|
|
|
|
|
|
|
Any rule that uses this validator should be provided with an error directive, since the |
2961
|
|
|
|
|
|
|
default error message is by necessity not very informative. The value is not |
2962
|
|
|
|
|
|
|
cleaned in any way. |
2963
|
|
|
|
|
|
|
|
2964
|
|
|
|
|
|
|
=cut |
2965
|
|
|
|
|
|
|
|
2966
|
|
|
|
|
|
|
sub match_value { |
2967
|
|
|
|
|
|
|
|
2968
|
7
|
|
|
7
|
0
|
10
|
my ($value, $context, $pattern) = @_; |
2969
|
|
|
|
|
|
|
|
2970
|
7
|
100
|
|
|
|
41
|
return if $value =~ $pattern; |
2971
|
3
|
|
|
|
|
12
|
return { error => "bad value '$value' for {param}: did not match the proper pattern" }; |
2972
|
|
|
|
|
|
|
} |
2973
|
|
|
|
|
|
|
|
2974
|
|
|
|
|
|
|
sub MATCH_VALUE { |
2975
|
|
|
|
|
|
|
|
2976
|
10
|
|
|
10
|
1
|
3146
|
my ($pattern) = @_; |
2977
|
|
|
|
|
|
|
|
2978
|
10
|
100
|
100
|
|
|
185
|
croak "MATCH_VALUE requires a regular expression" unless |
|
|
|
66
|
|
|
|
|
2979
|
|
|
|
|
|
|
defined $pattern && (!ref $pattern || ref $pattern eq 'Regexp'); |
2980
|
|
|
|
|
|
|
|
2981
|
8
|
100
|
|
|
|
84
|
my $re = ref $pattern ? $pattern : qr{^$pattern$}oi; |
2982
|
|
|
|
|
|
|
|
2983
|
8
|
|
|
7
|
|
40
|
return sub { return match_value(shift, shift, $re) }; |
|
7
|
|
|
|
|
13
|
|
2984
|
|
|
|
|
|
|
}; |
2985
|
|
|
|
|
|
|
|
2986
|
|
|
|
|
|
|
|
2987
|
|
|
|
|
|
|
=head3 ENUM_VALUE(string,...) |
2988
|
|
|
|
|
|
|
|
2989
|
|
|
|
|
|
|
This validator accepts any of the specified string values, and rejects all |
2990
|
|
|
|
|
|
|
others. Comparisons are case insensitive. If the version of Perl is 5.016 or |
2991
|
|
|
|
|
|
|
greater, or if the module C is available and has been |
2992
|
|
|
|
|
|
|
required, then the C function will be used instead of the usual C when |
2993
|
|
|
|
|
|
|
comparing values. The cleaned value will be the matching string value from |
2994
|
|
|
|
|
|
|
this call. |
2995
|
|
|
|
|
|
|
|
2996
|
|
|
|
|
|
|
If any of the strings is '#', then subsequent values will be accepted but not |
2997
|
|
|
|
|
|
|
reported in the standard error message as allowable values. This allows for |
2998
|
|
|
|
|
|
|
undocumented values to be accepted. |
2999
|
|
|
|
|
|
|
|
3000
|
|
|
|
|
|
|
=cut |
3001
|
|
|
|
|
|
|
|
3002
|
|
|
|
|
|
|
sub enum_value { |
3003
|
|
|
|
|
|
|
|
3004
|
5
|
|
|
5
|
0
|
7
|
my ($value, $context, $accepted, $good_list) = @_; |
3005
|
|
|
|
|
|
|
|
3006
|
5
|
|
|
|
|
87
|
my $folded = $case_fold->($value); |
3007
|
|
|
|
|
|
|
|
3008
|
|
|
|
|
|
|
# If the value is found in the $accepted hash, then we're good. Return |
3009
|
|
|
|
|
|
|
# the value as originally given, not the case-folded version. |
3010
|
|
|
|
|
|
|
|
3011
|
5
|
100
|
|
|
|
21
|
return { value => $accepted->{$folded} } if exists $accepted->{$folded}; |
3012
|
|
|
|
|
|
|
|
3013
|
|
|
|
|
|
|
# Otherwise, then we have an error. |
3014
|
|
|
|
|
|
|
|
3015
|
1
|
|
|
|
|
4
|
return { error => "bad value '$value' for {param}: must be one of $good_list" }; |
3016
|
|
|
|
|
|
|
} |
3017
|
|
|
|
|
|
|
|
3018
|
|
|
|
|
|
|
sub ENUM_VALUE { |
3019
|
|
|
|
|
|
|
|
3020
|
5
|
|
|
5
|
1
|
1888
|
my (%accepted, @documented, $undoc); |
3021
|
|
|
|
|
|
|
|
3022
|
5
|
|
|
|
|
10
|
foreach my $k ( @_ ) |
3023
|
|
|
|
|
|
|
{ |
3024
|
9
|
50
|
33
|
|
|
40
|
next unless defined $k && $k ne ''; |
3025
|
|
|
|
|
|
|
|
3026
|
9
|
50
|
|
|
|
18
|
if ( $k eq '#' ) |
3027
|
|
|
|
|
|
|
{ |
3028
|
0
|
|
|
|
|
0
|
$undoc = 1; |
3029
|
0
|
|
|
|
|
0
|
next; |
3030
|
|
|
|
|
|
|
} |
3031
|
|
|
|
|
|
|
|
3032
|
9
|
|
|
|
|
117
|
$accepted{ $case_fold->($k) } = $k; |
3033
|
9
|
50
|
|
|
|
24
|
push @documented, $k unless $undoc; |
3034
|
|
|
|
|
|
|
} |
3035
|
|
|
|
|
|
|
|
3036
|
|
|
|
|
|
|
#my @non_empty = grep { defined $_ && $_ ne '' } @_; |
3037
|
5
|
100
|
|
|
|
77
|
croak "ENUM_VALUE requires at least one value" unless keys %accepted; |
3038
|
|
|
|
|
|
|
|
3039
|
|
|
|
|
|
|
# my %accepted = map { $case_fold->($_) => $_ } @non_empty; |
3040
|
4
|
|
|
|
|
12
|
my $good_list = "'" . join("', '", @documented) . "'"; |
3041
|
|
|
|
|
|
|
|
3042
|
4
|
|
|
5
|
|
23
|
return sub { return enum_value(shift, shift, \%accepted, $good_list) }; |
|
5
|
|
|
|
|
11
|
|
3043
|
|
|
|
|
|
|
}; |
3044
|
|
|
|
|
|
|
|
3045
|
|
|
|
|
|
|
|
3046
|
|
|
|
|
|
|
=head3 BOOLEAN_VALUE |
3047
|
|
|
|
|
|
|
|
3048
|
|
|
|
|
|
|
This validator is used for parameters that take a true/false value. It |
3049
|
|
|
|
|
|
|
accepts any of the following values: "yes", "no", "true", "false", "on", |
3050
|
|
|
|
|
|
|
"off", "1", "0", compared case insensitively. It returns an error if any |
3051
|
|
|
|
|
|
|
other value is specified. The cleaned value will be 1 or 0. |
3052
|
|
|
|
|
|
|
|
3053
|
|
|
|
|
|
|
=cut |
3054
|
|
|
|
|
|
|
|
3055
|
|
|
|
|
|
|
sub boolean_value { |
3056
|
|
|
|
|
|
|
|
3057
|
2
|
|
|
2
|
0
|
2
|
my ($value, $context) = @_; |
3058
|
|
|
|
|
|
|
|
3059
|
2
|
50
|
|
|
|
6
|
unless ( ref $value ) |
3060
|
|
|
|
|
|
|
{ |
3061
|
2
|
50
|
|
|
|
8
|
if ( $value =~ /^(?:1|yes|true|on)$/i ) |
|
|
0
|
|
|
|
|
|
3062
|
|
|
|
|
|
|
{ |
3063
|
2
|
|
|
|
|
5
|
return { value => 1 }; |
3064
|
|
|
|
|
|
|
} |
3065
|
|
|
|
|
|
|
|
3066
|
|
|
|
|
|
|
elsif ( $value =~ /^(?:0|no|false|off)$/i ) |
3067
|
|
|
|
|
|
|
{ |
3068
|
0
|
|
|
|
|
0
|
return { value => 0 }; |
3069
|
|
|
|
|
|
|
} |
3070
|
|
|
|
|
|
|
} |
3071
|
|
|
|
|
|
|
|
3072
|
0
|
|
|
|
|
0
|
return { error => "the value of {param} must be one of: yes, no, true, false, on, off, 1, 0" }; |
3073
|
|
|
|
|
|
|
} |
3074
|
|
|
|
|
|
|
|
3075
|
1
|
|
|
1
|
1
|
3
|
sub BOOLEAN_VALUE { return \&boolean_value; }; |
3076
|
|
|
|
|
|
|
|
3077
|
|
|
|
|
|
|
|
3078
|
|
|
|
|
|
|
=head3 FLAG_VALUE |
3079
|
|
|
|
|
|
|
|
3080
|
|
|
|
|
|
|
This validator should be used for parameters that are considered to be "true" |
3081
|
|
|
|
|
|
|
if present with an empty value. The validator returns a value of 1 in this case, |
3082
|
|
|
|
|
|
|
and behaves like 'BOOLEAN_VALUE' otherwise. |
3083
|
|
|
|
|
|
|
|
3084
|
|
|
|
|
|
|
=cut |
3085
|
|
|
|
|
|
|
|
3086
|
2
|
|
|
2
|
1
|
11
|
sub FLAG_VALUE { return 'FLAG_VALUE'; }; |
3087
|
|
|
|
|
|
|
|
3088
|
|
|
|
|
|
|
|
3089
|
|
|
|
|
|
|
# =head3 EMPTY_VALUE |
3090
|
|
|
|
|
|
|
|
3091
|
|
|
|
|
|
|
# This validator accepts only the empty value. You can use this when you want a |
3092
|
|
|
|
|
|
|
# ruleset to be fulfilled even if the specified parameter is given an empty |
3093
|
|
|
|
|
|
|
# value. This will typically be used along with at least one other validator for the |
3094
|
|
|
|
|
|
|
# same parameter. For example: |
3095
|
|
|
|
|
|
|
|
3096
|
|
|
|
|
|
|
# define_ruleset foo => |
3097
|
|
|
|
|
|
|
# { param => 'bar', valid => [EMPTY_VALUE, POS_VALUE] }; |
3098
|
|
|
|
|
|
|
|
3099
|
|
|
|
|
|
|
# This rule would be satisfied if the parameter 'bar' is given either an empty |
3100
|
|
|
|
|
|
|
# value or a value that is a positive integer. The ruleset will be fulfilled in |
3101
|
|
|
|
|
|
|
# either case, but will not be fulfilled if 'bar' is not mentioned at all. For |
3102
|
|
|
|
|
|
|
# best results EMPTY_VALUE should not be the last validator in the list, because |
3103
|
|
|
|
|
|
|
# if a value fails all of the validators then the last error message is reported |
3104
|
|
|
|
|
|
|
# and its error message is by necessity not very helpful. |
3105
|
|
|
|
|
|
|
|
3106
|
|
|
|
|
|
|
# =cut |
3107
|
|
|
|
|
|
|
|
3108
|
|
|
|
|
|
|
# sub empty_value { |
3109
|
|
|
|
|
|
|
|
3110
|
|
|
|
|
|
|
# my ($value, $context) = @_; |
3111
|
|
|
|
|
|
|
|
3112
|
|
|
|
|
|
|
# return if !defined $value || $value eq ''; |
3113
|
|
|
|
|
|
|
# return { error => "parameter {param} must be empty unless it is given a valid value" }; |
3114
|
|
|
|
|
|
|
# } |
3115
|
|
|
|
|
|
|
|
3116
|
|
|
|
|
|
|
# sub EMPTY_VALUE { |
3117
|
|
|
|
|
|
|
|
3118
|
|
|
|
|
|
|
# return 'EMPTY_VALUE'; |
3119
|
|
|
|
|
|
|
# }; |
3120
|
|
|
|
|
|
|
|
3121
|
|
|
|
|
|
|
|
3122
|
|
|
|
|
|
|
=head3 ANY_VALUE |
3123
|
|
|
|
|
|
|
|
3124
|
|
|
|
|
|
|
This validator accepts any non-empty value. Using this validator |
3125
|
|
|
|
|
|
|
is equivalent to not specifying any validator at all. |
3126
|
|
|
|
|
|
|
|
3127
|
|
|
|
|
|
|
=cut |
3128
|
|
|
|
|
|
|
|
3129
|
|
|
|
|
|
|
sub ANY_VALUE { |
3130
|
|
|
|
|
|
|
|
3131
|
4
|
|
|
4
|
1
|
13
|
return 'ANY_VALUE'; |
3132
|
|
|
|
|
|
|
}; |
3133
|
|
|
|
|
|
|
|
3134
|
|
|
|
|
|
|
|
3135
|
|
|
|
|
|
|
=head2 Reusing validators |
3136
|
|
|
|
|
|
|
|
3137
|
|
|
|
|
|
|
Every time you use a parametrized validator such as C, a new |
3138
|
|
|
|
|
|
|
closure is generated. If you are repeating a particular set of parameters |
3139
|
|
|
|
|
|
|
many times, to save space you may want to instantiate the validator just once: |
3140
|
|
|
|
|
|
|
|
3141
|
|
|
|
|
|
|
my $zero_to_ten = INT_VALUE(0,10); |
3142
|
|
|
|
|
|
|
|
3143
|
|
|
|
|
|
|
define_ruleset( 'foo' => |
3144
|
|
|
|
|
|
|
{ param => 'bar', valid => $zero_to_ten }, |
3145
|
|
|
|
|
|
|
{ param => 'baz', valid => $zero_to_ten }); |
3146
|
|
|
|
|
|
|
|
3147
|
|
|
|
|
|
|
=head2 Writing your own validator functions |
3148
|
|
|
|
|
|
|
|
3149
|
|
|
|
|
|
|
If you wish to validate parameters which do not match any of the validators |
3150
|
|
|
|
|
|
|
described above, you can write your own validator function. Validator |
3151
|
|
|
|
|
|
|
functions are called with two arguments: |
3152
|
|
|
|
|
|
|
|
3153
|
|
|
|
|
|
|
($value, $context) |
3154
|
|
|
|
|
|
|
|
3155
|
|
|
|
|
|
|
Where $value is the raw parameter value and $context is a hash ref provided |
3156
|
|
|
|
|
|
|
when the validation process is initiated (or an empty hashref if none is |
3157
|
|
|
|
|
|
|
provided). This allows the passing of information such as database handles to |
3158
|
|
|
|
|
|
|
the validator functions. |
3159
|
|
|
|
|
|
|
|
3160
|
|
|
|
|
|
|
If your function decides that the parameter value is valid and does not need |
3161
|
|
|
|
|
|
|
to be cleaned, it can indicate this by returning an empty result. |
3162
|
|
|
|
|
|
|
|
3163
|
|
|
|
|
|
|
Otherwise, it must return a hash reference with one or more of the following |
3164
|
|
|
|
|
|
|
keys: |
3165
|
|
|
|
|
|
|
|
3166
|
|
|
|
|
|
|
=over 4 |
3167
|
|
|
|
|
|
|
|
3168
|
|
|
|
|
|
|
=item error |
3169
|
|
|
|
|
|
|
|
3170
|
|
|
|
|
|
|
If the parameter value is not valid, the value of this key should be an error |
3171
|
|
|
|
|
|
|
message that states I. This message should |
3172
|
|
|
|
|
|
|
contain the placeholder {param}, which will be substituted with the parameter |
3173
|
|
|
|
|
|
|
name. Use this placeholder, and do not hard-code the parameter name. |
3174
|
|
|
|
|
|
|
|
3175
|
|
|
|
|
|
|
Here is an example of a good message: |
3176
|
|
|
|
|
|
|
|
3177
|
|
|
|
|
|
|
"the value of {param} must be a positive integer (was {value})". |
3178
|
|
|
|
|
|
|
|
3179
|
|
|
|
|
|
|
Here is an example of a bad message: |
3180
|
|
|
|
|
|
|
|
3181
|
|
|
|
|
|
|
"bad value for 'foo'". |
3182
|
|
|
|
|
|
|
|
3183
|
|
|
|
|
|
|
=item warn |
3184
|
|
|
|
|
|
|
|
3185
|
|
|
|
|
|
|
If the parameter value is acceptable but questionable in some way, the value |
3186
|
|
|
|
|
|
|
of this key should be a message that states what a good value should look |
3187
|
|
|
|
|
|
|
like. All such messages will be made available through the result object that |
3188
|
|
|
|
|
|
|
is returned by the validation routine. The code that handles the request may |
3189
|
|
|
|
|
|
|
then choose to display these messages as part of the response. Your code may |
3190
|
|
|
|
|
|
|
also make use of this information during the process of responding to the |
3191
|
|
|
|
|
|
|
request. |
3192
|
|
|
|
|
|
|
|
3193
|
|
|
|
|
|
|
=item value |
3194
|
|
|
|
|
|
|
|
3195
|
|
|
|
|
|
|
If the parameter value represents anything other than a simple string (i.e. a |
3196
|
|
|
|
|
|
|
number, list, or more complicated data structure), then the value of this key |
3197
|
|
|
|
|
|
|
should be the converted or "cleaned" form of the parameter value. For |
3198
|
|
|
|
|
|
|
example, a numeric parameter might be converted into an actual number by |
3199
|
|
|
|
|
|
|
adding zero to it, or a pair of values might be split apart and converted into |
3200
|
|
|
|
|
|
|
an array ref. The value of this key will be returned as the "cleaned" value |
3201
|
|
|
|
|
|
|
of the parameter, in place of the raw parameter value provided in the request. |
3202
|
|
|
|
|
|
|
|
3203
|
|
|
|
|
|
|
=back |
3204
|
|
|
|
|
|
|
|
3205
|
|
|
|
|
|
|
=head3 Parametrized validators |
3206
|
|
|
|
|
|
|
|
3207
|
|
|
|
|
|
|
If you want to write your own parametrized validator, write a function that |
3208
|
|
|
|
|
|
|
generates and returns a closure. For example: |
3209
|
|
|
|
|
|
|
|
3210
|
|
|
|
|
|
|
sub integer_multiple { |
3211
|
|
|
|
|
|
|
|
3212
|
|
|
|
|
|
|
my ($value, $context, $base) = @_; |
3213
|
|
|
|
|
|
|
|
3214
|
|
|
|
|
|
|
return { value => $value + 0 } if $value % $base == 0; |
3215
|
|
|
|
|
|
|
return { error => "the value of {param} must be a multiple of $base (was {value})" }; |
3216
|
|
|
|
|
|
|
} |
3217
|
|
|
|
|
|
|
|
3218
|
|
|
|
|
|
|
sub INTEGER_MULTIPLE { |
3219
|
|
|
|
|
|
|
|
3220
|
|
|
|
|
|
|
my ($base) = $_[0] + 0; |
3221
|
|
|
|
|
|
|
|
3222
|
|
|
|
|
|
|
croak "INTEGER_MULTIPLE requires a numeric parameter greater than zero" |
3223
|
|
|
|
|
|
|
unless defined $base and $base > 0; |
3224
|
|
|
|
|
|
|
|
3225
|
|
|
|
|
|
|
return sub { return integer_multiple(shift, shift, $base) }; |
3226
|
|
|
|
|
|
|
} |
3227
|
|
|
|
|
|
|
|
3228
|
|
|
|
|
|
|
define_ruleset( 'foo' => |
3229
|
|
|
|
|
|
|
{ param => foo, valid => INTEGER_MULTIPLE(3) }); |
3230
|
|
|
|
|
|
|
|
3231
|
|
|
|
|
|
|
=cut |
3232
|
|
|
|
|
|
|
|
3233
|
|
|
|
|
|
|
|
3234
|
|
|
|
|
|
|
|
3235
|
|
|
|
|
|
|
=head1 AUTHOR |
3236
|
|
|
|
|
|
|
|
3237
|
|
|
|
|
|
|
Michael McClennen, C<< >> |
3238
|
|
|
|
|
|
|
|
3239
|
|
|
|
|
|
|
=head1 SUPPORT |
3240
|
|
|
|
|
|
|
|
3241
|
|
|
|
|
|
|
Please report any bugs or feature requests to C, or through |
3242
|
|
|
|
|
|
|
the web interface at L. I will be notified, and then you'll |
3243
|
|
|
|
|
|
|
automatically be notified of progress on your bug as I make changes. |
3244
|
|
|
|
|
|
|
|
3245
|
|
|
|
|
|
|
=head1 LICENSE AND COPYRIGHT |
3246
|
|
|
|
|
|
|
|
3247
|
|
|
|
|
|
|
Copyright 2014 Michael McClennen. |
3248
|
|
|
|
|
|
|
|
3249
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it |
3250
|
|
|
|
|
|
|
under the terms of either: the GNU General Public License as published |
3251
|
|
|
|
|
|
|
by the Free Software Foundation; or the Artistic License. |
3252
|
|
|
|
|
|
|
|
3253
|
|
|
|
|
|
|
See http://dev.perl.org/licenses/ for more information. |
3254
|
|
|
|
|
|
|
|
3255
|
|
|
|
|
|
|
|
3256
|
|
|
|
|
|
|
=cut |
3257
|
|
|
|
|
|
|
|
3258
|
|
|
|
|
|
|
1; # End of HTTP::Validate |