| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package HTTP::Validate; |
|
2
|
|
|
|
|
|
|
|
|
3
|
7
|
|
|
7
|
|
99262
|
use strict; |
|
|
7
|
|
|
|
|
13
|
|
|
|
7
|
|
|
|
|
170
|
|
|
4
|
7
|
|
|
7
|
|
22
|
use warnings; |
|
|
7
|
|
|
|
|
7
|
|
|
|
7
|
|
|
|
|
165
|
|
|
5
|
|
|
|
|
|
|
|
|
6
|
7
|
|
|
7
|
|
21
|
use Exporter qw( import ); |
|
|
7
|
|
|
|
|
9
|
|
|
|
7
|
|
|
|
|
197
|
|
|
7
|
7
|
|
|
7
|
|
22
|
use Carp qw( carp croak ); |
|
|
7
|
|
|
|
|
8
|
|
|
|
7
|
|
|
|
|
367
|
|
|
8
|
7
|
|
|
7
|
|
24
|
use Scalar::Util qw( reftype weaken looks_like_number ); |
|
|
7
|
|
|
|
|
5
|
|
|
|
7
|
|
|
|
|
1798
|
|
|
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.981'; |
|
18
|
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
=head1 NAME |
|
20
|
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
HTTP::Validate - validate and clean HTTP parameter values according to a set of rules |
|
22
|
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
Version 0.981 |
|
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
|
|
55
|
@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
|
|
|
|
|
14
|
@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
|
|
|
|
|
43181
|
%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
|
2733
|
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
|
|
|
|
|
25
|
my $self = bless { RULESETS => {}, SETTINGS => {} }, $class; |
|
735
|
|
|
|
|
|
|
|
|
736
|
|
|
|
|
|
|
# Set the requested settings |
|
737
|
|
|
|
|
|
|
|
|
738
|
9
|
|
|
|
|
19
|
$self->validation_settings(@settings); |
|
739
|
|
|
|
|
|
|
|
|
740
|
|
|
|
|
|
|
# Return the new object |
|
741
|
|
|
|
|
|
|
|
|
742
|
7
|
|
|
|
|
14
|
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
|
12848
|
my $self = ref $_[0] eq 'HTTP::Validate' ? shift : $DEFAULT_INSTANCE; |
|
761
|
|
|
|
|
|
|
|
|
762
|
77
|
|
|
|
|
109
|
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
|
|
|
|
|
146
|
my ($package, $filename, $line) = caller; |
|
768
|
|
|
|
|
|
|
|
|
769
|
|
|
|
|
|
|
# Check the arguments, then create a new ruleset object. |
|
770
|
|
|
|
|
|
|
|
|
771
|
77
|
100
|
100
|
|
|
586
|
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
|
|
|
|
|
120
|
my $rs = $self->create_ruleset($ruleset_name, $filename, $line); |
|
775
|
|
|
|
|
|
|
|
|
776
|
|
|
|
|
|
|
# Then add the rules. |
|
777
|
|
|
|
|
|
|
|
|
778
|
72
|
|
|
|
|
114
|
$self->add_rules($rs, @rules); |
|
779
|
|
|
|
|
|
|
|
|
780
|
|
|
|
|
|
|
# If we get here without any errors, install the ruleset and return. |
|
781
|
|
|
|
|
|
|
|
|
782
|
61
|
|
|
|
|
91
|
$self->{RULESETS}{$ruleset_name} = $rs; |
|
783
|
61
|
|
|
|
|
104
|
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
|
17820
|
my $self = ref $_[0] eq 'HTTP::Validate' ? shift : $DEFAULT_INSTANCE; |
|
834
|
|
|
|
|
|
|
|
|
835
|
60
|
|
|
|
|
86
|
my ($ruleset_name, $context, $parameters) = @_; |
|
836
|
|
|
|
|
|
|
|
|
837
|
|
|
|
|
|
|
# Create a new validation-execution object using the specified context |
|
838
|
|
|
|
|
|
|
# and parameters. |
|
839
|
|
|
|
|
|
|
|
|
840
|
60
|
|
|
|
|
104
|
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
|
|
|
|
|
93
|
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
|
1748
|
my $self = ref $_[0] eq 'HTTP::Validate' ? shift : $DEFAULT_INSTANCE; |
|
891
|
|
|
|
|
|
|
|
|
892
|
15
|
|
|
|
|
31
|
while (@_) |
|
893
|
|
|
|
|
|
|
{ |
|
894
|
34
|
|
|
|
|
22
|
my $key = shift; |
|
895
|
34
|
|
|
|
|
26
|
my $value = shift; |
|
896
|
|
|
|
|
|
|
|
|
897
|
34
|
100
|
|
|
|
64
|
if ( $key eq 'allow_unrecognized' ) |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
898
|
|
|
|
|
|
|
{ |
|
899
|
5
|
50
|
|
|
|
20
|
$self->{SETTINGS}{permissive} = $value ? 1 : 0; |
|
900
|
|
|
|
|
|
|
} |
|
901
|
|
|
|
|
|
|
|
|
902
|
|
|
|
|
|
|
elsif ( $key eq 'ignore_unrecognized' ) |
|
903
|
|
|
|
|
|
|
{ |
|
904
|
2
|
50
|
|
|
|
7
|
$self->{SETTINGS}{ignore_unrecognized} = $value ? 1 : 0; |
|
905
|
|
|
|
|
|
|
} |
|
906
|
|
|
|
|
|
|
|
|
907
|
|
|
|
|
|
|
elsif ( $ERROR_MSG{$key} ) |
|
908
|
|
|
|
|
|
|
{ |
|
909
|
24
|
|
|
|
|
54
|
$self->{SETTINGS}{$key} = $value; |
|
910
|
|
|
|
|
|
|
} |
|
911
|
|
|
|
|
|
|
|
|
912
|
|
|
|
|
|
|
else |
|
913
|
|
|
|
|
|
|
{ |
|
914
|
3
|
|
|
|
|
368
|
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
|
739
|
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
|
|
|
|
|
7
|
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
|
585
|
my $self = ref $_[0] eq 'HTTP::Validate' ? shift : $DEFAULT_INSTANCE; |
|
977
|
|
|
|
|
|
|
|
|
978
|
4
|
|
|
|
|
4
|
my ($ruleset_name) = @_; |
|
979
|
|
|
|
|
|
|
|
|
980
|
|
|
|
|
|
|
# Make sure we have a valid ruleset, or else return false. |
|
981
|
|
|
|
|
|
|
|
|
982
|
4
|
50
|
|
|
|
13
|
return unless defined $ruleset_name; |
|
983
|
|
|
|
|
|
|
|
|
984
|
4
|
|
|
|
|
4
|
my $rs = $self->{RULESETS}{$ruleset_name}; |
|
985
|
4
|
50
|
|
|
|
5
|
return unless $rs; |
|
986
|
|
|
|
|
|
|
|
|
987
|
|
|
|
|
|
|
# Now generate the requested documentation. |
|
988
|
|
|
|
|
|
|
|
|
989
|
4
|
|
|
|
|
18
|
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
|
4
|
my $self = ref $_[0] eq 'HTTP::Validate' ? shift : $DEFAULT_INSTANCE; |
|
1012
|
|
|
|
|
|
|
|
|
1013
|
1
|
|
|
|
|
1
|
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
|
|
|
|
2
|
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
|
79
|
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
|
|
|
|
109
|
croak "you must provide a non-empty name for the ruleset" if $ruleset_name eq ''; |
|
1044
|
|
|
|
|
|
|
|
|
1045
|
74
|
100
|
|
|
|
134
|
if ( exists $validator->{RULESETS}{$ruleset_name} ) |
|
1046
|
|
|
|
|
|
|
{ |
|
1047
|
2
|
|
|
|
|
3
|
my $filename = $validator->{RULESETS}{$ruleset_name}{filename}; |
|
1048
|
2
|
|
|
|
|
1
|
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
|
|
|
|
|
308
|
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
|
|
|
|
|
209
|
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
|
59
|
my ($self) = shift; |
|
1111
|
72
|
|
|
|
|
66
|
my ($rs) = shift; |
|
1112
|
|
|
|
|
|
|
|
|
1113
|
72
|
|
|
|
|
72
|
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
|
|
|
|
|
96
|
foreach my $rule (@_) |
|
1120
|
|
|
|
|
|
|
{ |
|
1121
|
|
|
|
|
|
|
# If the item is a scalar, then it is a documentation string. |
|
1122
|
|
|
|
|
|
|
|
|
1123
|
200
|
100
|
|
|
|
526
|
unless ( ref $rule ) |
|
|
|
50
|
|
|
|
|
|
|
1124
|
|
|
|
|
|
|
{ |
|
1125
|
|
|
|
|
|
|
# If the string starts with >, !, ^, or ? then treat it specially. |
|
1126
|
|
|
|
|
|
|
|
|
1127
|
16
|
100
|
|
|
|
69
|
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
|
|
|
|
22
|
if ( $1 eq '>>' ) |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
1135
|
|
|
|
|
|
|
{ |
|
1136
|
1
|
50
|
33
|
|
|
5
|
$self->add_doc($rs, $doc_rule, @doc_lines) if $doc_rule || @doc_lines; |
|
1137
|
1
|
|
|
|
|
3
|
@doc_lines = $2; |
|
1138
|
1
|
|
|
|
|
2
|
$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
|
|
|
|
|
3
|
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
|
|
|
|
|
1
|
$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
|
|
|
|
|
12
|
push @doc_lines, $rule; |
|
1186
|
|
|
|
|
|
|
} |
|
1187
|
|
|
|
|
|
|
|
|
1188
|
16
|
|
|
|
|
22
|
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
|
|
|
|
|
121
|
my $rr = { rs => $rs, rn => scalar(@{$rs->{rules}}) + 1 }; |
|
|
184
|
|
|
|
|
342
|
|
|
1202
|
184
|
|
|
|
|
122
|
push @{$rs->{rules}}, $rr; |
|
|
184
|
|
|
|
|
214
|
|
|
1203
|
|
|
|
|
|
|
|
|
1204
|
184
|
|
|
|
|
261
|
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
|
|
|
|
|
123
|
my $type; |
|
1210
|
|
|
|
|
|
|
|
|
1211
|
|
|
|
|
|
|
KEY: |
|
1212
|
184
|
|
|
|
|
311
|
foreach my $key (keys %$rule) |
|
1213
|
|
|
|
|
|
|
{ |
|
1214
|
324
|
100
|
66
|
|
|
594
|
croak "unknown attribute '$key' found in rule" unless $DIRECTIVE{$key} || $ERROR_MSG{$key}; |
|
1215
|
|
|
|
|
|
|
|
|
1216
|
322
|
100
|
100
|
|
|
879
|
if ( defined $DIRECTIVE{$key} && $DIRECTIVE{$key} == 2 ) |
|
1217
|
|
|
|
|
|
|
{ |
|
1218
|
183
|
100
|
|
|
|
298
|
croak "a rule definition cannot contain the attributes '$key' and '$type' together, because they indicate different rule types" |
|
1219
|
|
|
|
|
|
|
if $type; |
|
1220
|
182
|
|
|
|
|
157
|
$type = $key; |
|
1221
|
182
|
|
|
|
|
180
|
$rr->{$type} = $rule->{$type}; |
|
1222
|
182
|
|
|
|
|
212
|
next KEY; |
|
1223
|
|
|
|
|
|
|
} |
|
1224
|
|
|
|
|
|
|
} |
|
1225
|
|
|
|
|
|
|
|
|
1226
|
|
|
|
|
|
|
# Then process the other keys. |
|
1227
|
|
|
|
|
|
|
|
|
1228
|
181
|
|
|
|
|
227
|
foreach my $key (keys %$rule) |
|
1229
|
|
|
|
|
|
|
{ |
|
1230
|
320
|
|
|
|
|
251
|
my $value = $rule->{$key}; |
|
1231
|
|
|
|
|
|
|
|
|
1232
|
320
|
100
|
100
|
|
|
1460
|
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
|
|
|
204
|
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
|
|
|
16
|
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
|
|
|
|
16
|
$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
|
|
|
|
71
|
unless $CATEGORY{$type} eq 'param'; |
|
1253
|
|
|
|
|
|
|
|
|
1254
|
4
|
|
66
|
|
|
11
|
$rr->{cleaner} = $CLEANER_DEF{$value} || $value; |
|
1255
|
|
|
|
|
|
|
|
|
1256
|
|
|
|
|
|
|
croak "invalid value '$value' for 'clean'" |
|
1257
|
4
|
50
|
|
|
|
10
|
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
|
|
|
|
8
|
unless $CATEGORY{$type} eq 'param'; |
|
1264
|
|
|
|
|
|
|
|
|
1265
|
3
|
|
|
|
|
9
|
$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
|
|
|
|
12
|
unless $CATEGORY{$type} eq 'param'; |
|
1272
|
|
|
|
|
|
|
|
|
1273
|
8
|
50
|
66
|
|
|
19
|
croak "the value of '$key' must be a string or a regexp" |
|
1274
|
|
|
|
|
|
|
if ref $value and ref $value ne 'Regexp'; |
|
1275
|
|
|
|
|
|
|
|
|
1276
|
8
|
|
|
|
|
10
|
$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
|
|
|
|
16
|
unless ( ref $value ) |
|
1283
|
|
|
|
|
|
|
{ |
|
1284
|
7
|
|
|
|
|
85
|
$value = qr{ \s* $value \s* }oxs; |
|
1285
|
|
|
|
|
|
|
} |
|
1286
|
|
|
|
|
|
|
|
|
1287
|
8
|
|
|
|
|
11
|
$rr->{split} = $value; |
|
1288
|
8
|
100
|
|
|
|
24
|
$rr->{warn} = 1 if $key eq 'list'; |
|
1289
|
|
|
|
|
|
|
} |
|
1290
|
|
|
|
|
|
|
|
|
1291
|
|
|
|
|
|
|
elsif ( $key eq 'error' || $key eq 'errmsg' ) |
|
1292
|
|
|
|
|
|
|
{ |
|
1293
|
7
|
|
|
|
|
8
|
$rr->{errmsg} = $value; |
|
1294
|
|
|
|
|
|
|
} |
|
1295
|
|
|
|
|
|
|
|
|
1296
|
|
|
|
|
|
|
elsif ( $key ne $type ) |
|
1297
|
|
|
|
|
|
|
{ |
|
1298
|
19
|
50
|
|
|
|
26
|
croak "the value of '$key' must be a string" if ref $value; |
|
1299
|
|
|
|
|
|
|
|
|
1300
|
19
|
|
|
|
|
22
|
$rr->{$key} = $value; |
|
1301
|
|
|
|
|
|
|
} |
|
1302
|
|
|
|
|
|
|
} |
|
1303
|
|
|
|
|
|
|
|
|
1304
|
181
|
50
|
|
|
|
238
|
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
|
|
|
|
233
|
if ( $CATEGORY{$type} ne 'modifier' ) |
|
1312
|
|
|
|
|
|
|
{ |
|
1313
|
176
|
|
|
|
|
233
|
$self->add_doc($rs, $doc_rule, @doc_lines); |
|
1314
|
176
|
|
|
|
|
133
|
$doc_rule = $rr; |
|
1315
|
176
|
|
|
|
|
142
|
@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
|
|
|
|
|
146
|
my $typevalue = $rule->{$type}; |
|
1334
|
|
|
|
|
|
|
|
|
1335
|
181
|
100
|
|
|
|
281
|
if ( $CATEGORY{$type} eq 'param' ) |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
1336
|
|
|
|
|
|
|
{ |
|
1337
|
131
|
|
|
|
|
129
|
$rr->{type} = 'param'; |
|
1338
|
131
|
|
|
|
|
108
|
$rr->{param} = $typevalue; |
|
1339
|
|
|
|
|
|
|
|
|
1340
|
|
|
|
|
|
|
# Do some basic sanity checking. |
|
1341
|
|
|
|
|
|
|
|
|
1342
|
131
|
100
|
66
|
|
|
602
|
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
|
|
|
|
227
|
my @validators = ref $rule->{valid} eq 'ARRAY' ? @{$rule->{valid}} : $rule->{valid}; |
|
|
3
|
|
|
|
|
8
|
|
|
1348
|
|
|
|
|
|
|
|
|
1349
|
130
|
|
|
|
|
126
|
foreach my $v (@validators) |
|
1350
|
|
|
|
|
|
|
{ |
|
1351
|
132
|
100
|
66
|
|
|
364
|
if ( defined $v && $VALIDATOR_DEF{$v} ) |
|
|
|
100
|
|
|
|
|
|
|
1352
|
|
|
|
|
|
|
{ |
|
1353
|
6
|
100
|
|
|
|
10
|
$rr->{flag} = 1 if $v eq 'FLAG_VALUE'; |
|
1354
|
6
|
100
|
|
|
|
16
|
push @{$rr->{validators}}, \&boolean_value if $v eq 'FLAG_VALUE'; |
|
|
2
|
|
|
|
|
5
|
|
|
1355
|
|
|
|
|
|
|
} |
|
1356
|
|
|
|
|
|
|
|
|
1357
|
|
|
|
|
|
|
elsif ( defined $v ) |
|
1358
|
|
|
|
|
|
|
{ |
|
1359
|
87
|
100
|
100
|
|
|
440
|
croak "invalid validator '$v': must be a code ref" |
|
1360
|
|
|
|
|
|
|
unless ref $v && reftype $v eq 'CODE'; |
|
1361
|
|
|
|
|
|
|
|
|
1362
|
85
|
|
|
|
|
47
|
push @{$rr->{validators}}, $v; |
|
|
85
|
|
|
|
|
165
|
|
|
1363
|
|
|
|
|
|
|
} |
|
1364
|
|
|
|
|
|
|
} |
|
1365
|
|
|
|
|
|
|
|
|
1366
|
128
|
100
|
100
|
|
|
331
|
$rr->{$type} = 1 if $type eq 'optional' || $type eq 'mandatory'; |
|
1367
|
|
|
|
|
|
|
|
|
1368
|
128
|
100
|
|
|
|
212
|
if ( $type ne 'optional' ) |
|
1369
|
|
|
|
|
|
|
{ |
|
1370
|
104
|
50
|
|
|
|
156
|
push @{$rs->{fulfill_order}}, $typevalue unless $rs->{params}{$typevalue}; |
|
|
104
|
|
|
|
|
134
|
|
|
1371
|
|
|
|
|
|
|
} |
|
1372
|
|
|
|
|
|
|
|
|
1373
|
128
|
|
|
|
|
163
|
$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
|
|
|
|
242
|
if ( defined $rr->{default} ) |
|
1381
|
|
|
|
|
|
|
{ |
|
1382
|
3
|
50
|
|
|
|
7
|
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
|
|
|
12
|
@{$rr->{validators}}; |
|
|
2
|
|
|
|
|
6
|
|
|
1386
|
|
|
|
|
|
|
|
|
1387
|
2
|
|
|
|
|
3
|
foreach my $v ( @{$rr->{validators}} ) |
|
|
2
|
|
|
|
|
8
|
|
|
1388
|
|
|
|
|
|
|
{ |
|
1389
|
2
|
|
|
|
|
8
|
my $result = $v->($rr->{default}, {}); |
|
1390
|
|
|
|
|
|
|
|
|
1391
|
2
|
50
|
|
|
|
5
|
next RULE unless defined $result; |
|
1392
|
|
|
|
|
|
|
|
|
1393
|
2
|
100
|
|
|
|
7
|
if ( exists $result->{value} ) |
|
1394
|
|
|
|
|
|
|
{ |
|
1395
|
1
|
|
|
|
|
1
|
$rr->{default} = $result->{value}; |
|
1396
|
1
|
50
|
|
|
|
3
|
croak "cleaned default value must be a scalar\n" if ref $rr->{default}; |
|
1397
|
1
|
|
|
|
|
2
|
next RULE; |
|
1398
|
|
|
|
|
|
|
} |
|
1399
|
|
|
|
|
|
|
} |
|
1400
|
|
|
|
|
|
|
|
|
1401
|
1
|
|
|
|
|
160
|
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
|
|
|
|
10
|
my @params = ref $typevalue eq 'ARRAY' ? @$typevalue : $typevalue; |
|
1411
|
|
|
|
|
|
|
|
|
1412
|
5
|
|
|
|
|
10
|
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
|
|
|
|
|
12
|
|
|
1417
|
|
|
|
|
|
|
} |
|
1418
|
|
|
|
|
|
|
|
|
1419
|
|
|
|
|
|
|
croak "a rule of type '$type' requires at least one parameter name" |
|
1420
|
5
|
50
|
|
|
|
6
|
unless @{$rr->{param}} > 0; |
|
|
5
|
|
|
|
|
14
|
|
|
1421
|
|
|
|
|
|
|
} |
|
1422
|
|
|
|
|
|
|
|
|
1423
|
|
|
|
|
|
|
elsif ( $CATEGORY{$type} eq 'include' ) |
|
1424
|
|
|
|
|
|
|
{ |
|
1425
|
31
|
|
|
|
|
30
|
$rr->{type} = 'include'; |
|
1426
|
31
|
100
|
|
|
|
48
|
$rr->{require} = 1 if $type eq 'require'; |
|
1427
|
31
|
|
|
|
|
34
|
$rr->{ruleset} = $typevalue; |
|
1428
|
|
|
|
|
|
|
|
|
1429
|
31
|
100
|
100
|
|
|
299
|
croak "the value of '$type' must be a ruleset name" |
|
|
|
|
66
|
|
|
|
|
|
1430
|
|
|
|
|
|
|
unless defined $typevalue && !ref $typevalue && $typevalue ne ''; |
|
1431
|
|
|
|
|
|
|
|
|
1432
|
29
|
100
|
|
|
|
115
|
croak "ruleset '$typevalue' not found" unless defined $self->{RULESETS}{$typevalue}; |
|
1433
|
|
|
|
|
|
|
|
|
1434
|
28
|
|
|
|
|
89
|
$rs->{includes}{$typevalue} = 1; |
|
1435
|
|
|
|
|
|
|
} |
|
1436
|
|
|
|
|
|
|
|
|
1437
|
|
|
|
|
|
|
elsif ( $CATEGORY{$type} eq 'constraint' ) |
|
1438
|
|
|
|
|
|
|
{ |
|
1439
|
10
|
|
|
|
|
9
|
$rr->{type} = 'constraint'; |
|
1440
|
10
|
|
|
|
|
11
|
$rr->{constraint} = $type; |
|
1441
|
10
|
|
|
|
|
13
|
$rr->{ruleset} = []; |
|
1442
|
|
|
|
|
|
|
|
|
1443
|
10
|
50
|
33
|
|
|
36
|
croak "the value of '$type' must be a list of ruleset names" |
|
1444
|
|
|
|
|
|
|
unless defined $typevalue && ref $typevalue eq 'ARRAY'; |
|
1445
|
|
|
|
|
|
|
|
|
1446
|
10
|
|
|
|
|
14
|
foreach my $arg (@$typevalue) |
|
1447
|
|
|
|
|
|
|
{ |
|
1448
|
20
|
50
|
33
|
|
|
63
|
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
|
|
|
|
6
|
unless @{$rr->{ruleset}} > 0; |
|
|
10
|
|
|
|
|
23
|
|
|
1456
|
|
|
|
|
|
|
} |
|
1457
|
|
|
|
|
|
|
|
|
1458
|
|
|
|
|
|
|
elsif ( $type eq 'content_type' ) |
|
1459
|
|
|
|
|
|
|
{ |
|
1460
|
4
|
|
|
|
|
4
|
$rr->{type} = 'content_type'; |
|
1461
|
4
|
|
|
|
|
7
|
$rr->{param} = $typevalue; |
|
1462
|
|
|
|
|
|
|
|
|
1463
|
4
|
|
|
|
|
4
|
my %map; |
|
1464
|
|
|
|
|
|
|
|
|
1465
|
4
|
50
|
33
|
|
|
32
|
croak "invalid parameter name '$typevalue'" if ref $typevalue || $typevalue !~ /\w/; |
|
1466
|
|
|
|
|
|
|
|
|
1467
|
4
|
50
|
|
|
|
15
|
my @types = ref $rule->{valid} eq 'ARRAY' ? @{$rule->{valid}} : $rule->{valid}; |
|
|
4
|
|
|
|
|
11
|
|
|
1468
|
|
|
|
|
|
|
|
|
1469
|
4
|
|
|
|
|
8
|
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
|
|
|
|
|
24
|
my ($short, $long) = split /\s*=\s*/, $t; |
|
1478
|
10
|
|
100
|
|
|
28
|
$long ||= $MEDIA_TYPE{$short}; |
|
1479
|
|
|
|
|
|
|
|
|
1480
|
10
|
100
|
|
|
|
95
|
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
|
|
|
|
|
10
|
$rr->{type_map}{$short} = $long; |
|
1486
|
9
|
|
|
|
|
7
|
push @{$rr->{type_list}}, $short; |
|
|
9
|
|
|
|
|
20
|
|
|
1487
|
|
|
|
|
|
|
} |
|
1488
|
|
|
|
|
|
|
|
|
1489
|
3
|
50
|
|
|
|
10
|
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
|
|
|
|
|
90
|
$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
|
645
|
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
|
|
|
473
|
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
|
|
|
310
|
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
|
|
|
342
|
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
|
|
|
|
|
119
|
my $body = ''; |
|
1544
|
170
|
|
|
|
|
107
|
my $last_pod; |
|
1545
|
|
|
|
|
|
|
my $this_pod; |
|
1546
|
|
|
|
|
|
|
|
|
1547
|
170
|
|
|
|
|
159
|
foreach my $line (@lines) |
|
1548
|
|
|
|
|
|
|
{ |
|
1549
|
|
|
|
|
|
|
# If this line starts with =, then it needs extra spacing. |
|
1550
|
|
|
|
|
|
|
|
|
1551
|
15
|
|
|
|
|
41
|
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
|
|
|
|
25
|
if ( $body ne '' ) |
|
1558
|
|
|
|
|
|
|
{ |
|
1559
|
4
|
50
|
33
|
|
|
12
|
$body .= "\n" if $last_pod || $this_pod; |
|
1560
|
4
|
|
|
|
|
3
|
$body .= "\n"; |
|
1561
|
|
|
|
|
|
|
} |
|
1562
|
|
|
|
|
|
|
|
|
1563
|
15
|
|
|
|
|
29
|
$body .= $line; |
|
1564
|
15
|
|
|
|
|
14
|
$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
|
|
|
632
|
unless ( defined $rr ) |
|
|
|
100
|
66
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
1572
|
|
|
|
|
|
|
{ |
|
1573
|
5
|
|
|
|
|
2
|
push @{$rs->{doc_items}}, "=ORDINARY"; |
|
|
5
|
|
|
|
|
11
|
|
|
1574
|
5
|
50
|
|
|
|
8
|
push @{$rs->{doc_items}}, process_doc($body) if defined $body; |
|
|
5
|
|
|
|
|
9
|
|
|
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
|
|
|
|
|
84
|
push @{$rs->{doc_items}}, $rr; |
|
|
125
|
|
|
|
|
144
|
|
|
1582
|
125
|
|
|
|
|
190
|
weaken $rs->{doc_items}[-1]; |
|
1583
|
125
|
50
|
|
|
|
148
|
push @{$rs->{doc_items}}, process_doc($body, 1) if defined $body; |
|
|
125
|
|
|
|
|
163
|
|
|
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
|
|
|
|
|
19
|
push @{$rs->{doc_items}}, "=INCLUDE $rr->{ruleset}"; |
|
|
27
|
|
|
|
|
51
|
|
|
1592
|
|
|
|
|
|
|
|
|
1593
|
|
|
|
|
|
|
# If any body text was specified, then add it as an ordinary paragraph |
|
1594
|
|
|
|
|
|
|
# after the inclusion. |
|
1595
|
|
|
|
|
|
|
|
|
1596
|
27
|
100
|
|
|
|
49
|
if ( $body ne '' ) |
|
1597
|
|
|
|
|
|
|
{ |
|
1598
|
1
|
|
|
|
|
1
|
push @{$rs->{doc_items}}, "=ORDINARY"; |
|
|
1
|
|
|
|
|
2
|
|
|
1599
|
1
|
50
|
|
|
|
2
|
push @{$rs->{doc_items}}, process_doc($body) if defined $body; |
|
|
1
|
|
|
|
|
3
|
|
|
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
|
119
|
my ($docstring, $item_body) = @_; |
|
1614
|
|
|
|
|
|
|
|
|
1615
|
131
|
|
|
|
|
96
|
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
|
|
|
|
|
239
|
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
|
7
|
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
|
|
|
|
10
|
return '' if $state->{processed}{$rs->{name}}; |
|
1660
|
|
|
|
|
|
|
|
|
1661
|
6
|
|
|
|
|
8
|
$state->{processed}{$rs->{name}} = 1; |
|
1662
|
6
|
|
|
|
|
5
|
$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
|
|
|
|
|
10
|
foreach my $item ( @{$rs->{doc_items}} ) |
|
|
6
|
|
|
|
|
9
|
|
|
1675
|
|
|
|
|
|
|
{ |
|
1676
|
|
|
|
|
|
|
# An item record starts a list if not already in one. |
|
1677
|
|
|
|
|
|
|
|
|
1678
|
38
|
100
|
66
|
|
|
156
|
if ( ref $item && defined $item->{param} ) |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
1679
|
|
|
|
|
|
|
{ |
|
1680
|
10
|
100
|
|
|
|
14
|
unless ( $state->{in_list} ) |
|
1681
|
|
|
|
|
|
|
{ |
|
1682
|
5
|
100
|
|
|
|
7
|
$doc .= "\n\n" if $doc ne ''; |
|
1683
|
5
|
|
|
|
|
5
|
$doc .= "=over"; |
|
1684
|
5
|
|
|
|
|
6
|
$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
|
|
|
|
6
|
$doc .= "\n\n" if $doc ne ''; |
|
1697
|
3
|
|
|
|
|
2
|
$doc .= "=back"; |
|
1698
|
3
|
|
|
|
|
5
|
$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
|
|
|
|
|
4
|
my $included_rs = $self->{RULESETS}{$1}; |
|
1707
|
|
|
|
|
|
|
|
|
1708
|
2
|
50
|
|
|
|
5
|
if ( ref $included_rs eq 'HTTP::Validate::Ruleset' ) |
|
1709
|
|
|
|
|
|
|
{ |
|
1710
|
2
|
|
|
|
|
9
|
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
|
|
|
|
5
|
$doc .= $subdoc if $subdoc ne ''; |
|
1714
|
|
|
|
|
|
|
} |
|
1715
|
|
|
|
|
|
|
} |
|
1716
|
|
|
|
|
|
|
|
|
1717
|
|
|
|
|
|
|
# All other strings are added as-is. |
|
1718
|
|
|
|
|
|
|
|
|
1719
|
|
|
|
|
|
|
else |
|
1720
|
|
|
|
|
|
|
{ |
|
1721
|
18
|
100
|
100
|
|
|
44
|
$doc .= "\n\n" if $doc ne '' && $item ne ''; |
|
1722
|
18
|
|
|
|
|
32
|
$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
|
|
|
|
7
|
$doc .= "\n\n=back" if $state->{in_list}; |
|
1733
|
4
|
|
|
|
|
3
|
$state->{in_list} = 0; |
|
1734
|
4
|
|
|
|
|
3
|
$doc .= "\n"; |
|
1735
|
|
|
|
|
|
|
} |
|
1736
|
|
|
|
|
|
|
|
|
1737
|
6
|
|
|
|
|
12
|
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
|
|
|
7
|
$uniq ||= {}; |
|
1751
|
|
|
|
|
|
|
|
|
1752
|
3
|
50
|
|
|
|
5
|
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
|
|
|
|
|
6
|
|
|
1757
|
|
|
|
|
|
|
{ |
|
1758
|
7
|
100
|
|
|
|
11
|
if ( $rule->{type} eq 'param' ) |
|
|
|
50
|
|
|
|
|
|
|
1759
|
|
|
|
|
|
|
{ |
|
1760
|
5
|
|
|
|
|
6
|
push @params, $rule->{param}; |
|
1761
|
|
|
|
|
|
|
} |
|
1762
|
|
|
|
|
|
|
|
|
1763
|
|
|
|
|
|
|
elsif ( $rule->{type} eq 'include' ) |
|
1764
|
|
|
|
|
|
|
{ |
|
1765
|
2
|
|
|
|
|
5
|
push @params, $self->generate_param_list($rule->{ruleset}, $uniq); |
|
1766
|
|
|
|
|
|
|
} |
|
1767
|
|
|
|
|
|
|
} |
|
1768
|
|
|
|
|
|
|
|
|
1769
|
3
|
|
|
|
|
8
|
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
|
48
|
my ($self, $context, $input_params) = @_; |
|
1781
|
|
|
|
|
|
|
|
|
1782
|
|
|
|
|
|
|
# First check the types of the arguments to this function. |
|
1783
|
|
|
|
|
|
|
|
|
1784
|
60
|
50
|
33
|
|
|
346
|
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
|
|
|
|
79
|
$context = {} unless defined $context; |
|
1788
|
|
|
|
|
|
|
|
|
1789
|
60
|
50
|
|
|
|
105
|
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
|
|
|
|
|
46
|
my $unpacked_params = {}; |
|
1795
|
|
|
|
|
|
|
|
|
1796
|
60
|
100
|
|
|
|
142
|
if ( reftype $input_params eq 'HASH' ) |
|
|
|
50
|
|
|
|
|
|
|
1797
|
|
|
|
|
|
|
{ |
|
1798
|
29
|
|
|
|
|
65
|
%$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
|
|
|
74
|
while ( ref $input_params->[0] && reftype $input_params->[0] eq 'HASH' ) |
|
1809
|
|
|
|
|
|
|
{ |
|
1810
|
3
|
|
|
|
|
3
|
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
|
|
|
|
|
50
|
while ( @$input_params ) |
|
1821
|
|
|
|
|
|
|
{ |
|
1822
|
72
|
|
|
|
|
56
|
my $p = shift @$input_params; |
|
1823
|
|
|
|
|
|
|
|
|
1824
|
72
|
50
|
|
|
|
75
|
if ( ref $p ) |
|
1825
|
|
|
|
|
|
|
{ |
|
1826
|
0
|
|
|
|
|
0
|
croak "invalid parameter '$p'"; |
|
1827
|
|
|
|
|
|
|
} |
|
1828
|
|
|
|
|
|
|
|
|
1829
|
|
|
|
|
|
|
else |
|
1830
|
|
|
|
|
|
|
{ |
|
1831
|
72
|
|
|
|
|
75
|
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
|
|
|
|
|
44
|
my %settings = %{$self->{SETTINGS}}; |
|
|
60
|
|
|
|
|
178
|
|
|
1846
|
|
|
|
|
|
|
|
|
1847
|
60
|
|
|
|
|
205
|
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
|
|
|
|
|
113
|
return bless $vr, 'HTTP::Validate::Progress'; |
|
1857
|
|
|
|
|
|
|
} |
|
1858
|
|
|
|
|
|
|
|
|
1859
|
|
|
|
|
|
|
|
|
1860
|
|
|
|
|
|
|
sub add_param { |
|
1861
|
|
|
|
|
|
|
|
|
1862
|
78
|
|
|
78
|
0
|
59
|
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
|
|
|
205
|
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
|
|
|
17
|
$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
|
|
|
|
|
152
|
$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
|
54
|
my ($self, $vr, $ruleset_name) = @_; |
|
1899
|
|
|
|
|
|
|
|
|
1900
|
60
|
50
|
33
|
|
|
184
|
croak "you must provide a ruleset name" unless defined $ruleset_name && $ruleset_name ne ''; |
|
1901
|
60
|
50
|
33
|
|
|
270
|
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
|
|
|
|
|
85
|
$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
|
|
|
|
101
|
if ( $vr->{rs}{$ruleset_name} != 2 ) |
|
1913
|
|
|
|
|
|
|
{ |
|
1914
|
1
|
|
|
|
|
2
|
my @names = @{$self->{RULESETS}{$ruleset_name}{fulfill_order}}; |
|
|
1
|
|
|
|
|
2
|
|
|
1915
|
1
|
50
|
|
|
|
3
|
my $msg = @names == 1 ? 'ERR_REQ_SINGLE': 'ERR_REQ_MULT'; |
|
1916
|
1
|
|
|
|
|
5
|
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
|
|
|
|
|
83
|
my $result = bless {}, 'HTTP::Validate::Result'; |
|
1922
|
|
|
|
|
|
|
|
|
1923
|
|
|
|
|
|
|
# Add the clean-value hash and the raw-value hash |
|
1924
|
|
|
|
|
|
|
|
|
1925
|
60
|
|
|
|
|
89
|
$result->{clean} = $vr->{clean}; |
|
1926
|
60
|
|
|
|
|
71
|
$result->{clean_list} = $vr->{clean_list}; |
|
1927
|
60
|
|
|
|
|
52
|
$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
|
|
|
|
|
56
|
$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
|
|
|
|
|
54
|
$result->{ec} = $vr->{ec}; |
|
1944
|
60
|
|
|
|
|
44
|
$result->{er} = $vr->{er}; |
|
1945
|
60
|
|
|
|
|
49
|
$result->{wc} = $vr->{wc}; |
|
1946
|
60
|
|
|
|
|
84
|
$result->{wn} = $vr->{wn}; |
|
1947
|
60
|
|
|
|
|
65
|
$result->{ig} = $vr->{ig}; |
|
1948
|
|
|
|
|
|
|
|
|
1949
|
|
|
|
|
|
|
# Now check for unrecognized parameters, and generate errors or warnings |
|
1950
|
|
|
|
|
|
|
# for them. |
|
1951
|
|
|
|
|
|
|
|
|
1952
|
60
|
100
|
|
|
|
108
|
return $result if $self->{SETTINGS}{ignore_unrecognized}; |
|
1953
|
|
|
|
|
|
|
|
|
1954
|
52
|
|
|
|
|
36
|
foreach my $key (keys %{$vr->{raw}}) |
|
|
52
|
|
|
|
|
108
|
|
|
1955
|
|
|
|
|
|
|
{ |
|
1956
|
109
|
100
|
66
|
|
|
199
|
next if exists $vr->{ps}{$key} or exists $vr->{ig}{$key}; |
|
1957
|
|
|
|
|
|
|
|
|
1958
|
4
|
100
|
|
|
|
8
|
if ( $self->{SETTINGS}{permissive} ) |
|
1959
|
|
|
|
|
|
|
{ |
|
1960
|
2
|
|
|
|
|
2
|
unshift @{$result->{wn}}, [$key, "unknown parameter '$key'"]; |
|
|
2
|
|
|
|
|
7
|
|
|
1961
|
2
|
|
|
|
|
3
|
$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
|
|
|
|
|
204
|
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
|
62
|
my ($self, $vr, $ruleset_name) = @_; |
|
1983
|
|
|
|
|
|
|
|
|
1984
|
82
|
50
|
|
|
|
126
|
die "Missing ruleset" unless defined $ruleset_name; |
|
1985
|
|
|
|
|
|
|
|
|
1986
|
82
|
|
|
|
|
86
|
my $rs = $self->{RULESETS}{$ruleset_name}; |
|
1987
|
|
|
|
|
|
|
|
|
1988
|
|
|
|
|
|
|
# Throw an error if this ruleset does not exist. |
|
1989
|
|
|
|
|
|
|
|
|
1990
|
82
|
50
|
|
|
|
123
|
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
|
|
|
|
109
|
return if exists $vr->{rs}{$ruleset_name}; |
|
1996
|
82
|
|
|
|
|
93
|
$vr->{rs}{$ruleset_name} = 1; |
|
1997
|
|
|
|
|
|
|
|
|
1998
|
|
|
|
|
|
|
# Mark the ruleset as fulfilled if it has no non-optional parameters. |
|
1999
|
|
|
|
|
|
|
|
|
2000
|
82
|
100
|
66
|
|
|
138
|
$vr->{rs}{$ruleset_name} = 2 unless ref $rs->{fulfill_order} && @{$rs->{fulfill_order}}; |
|
|
82
|
|
|
|
|
226
|
|
|
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
|
|
|
|
|
64
|
foreach my $rr (@{$rs->{rules}}) |
|
|
82
|
|
|
|
|
106
|
|
|
2007
|
|
|
|
|
|
|
{ |
|
2008
|
214
|
|
|
|
|
182
|
my $type = $rr->{type}; |
|
2009
|
214
|
|
|
|
|
154
|
my $param = $rr->{param}; |
|
2010
|
214
|
|
100
|
|
|
445
|
my $key = $rr->{key} || $param; |
|
2011
|
214
|
|
|
|
|
135
|
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
|
|
|
362
|
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
|
|
|
|
278
|
next RULE if $vr->{ig}{$key}; |
|
2023
|
|
|
|
|
|
|
|
|
2024
|
|
|
|
|
|
|
# Otherwise check to see if the parameter or any of its aliases were specified. If |
|
2025
|
|
|
|
|
|
|
# so, then collect up their values. |
|
2026
|
|
|
|
|
|
|
|
|
2027
|
170
|
|
|
|
|
128
|
foreach my $name ( $rr->{param}, @{$rr->{alias}} ) |
|
|
170
|
|
|
|
|
224
|
|
|
2028
|
|
|
|
|
|
|
{ |
|
2029
|
177
|
100
|
|
|
|
255
|
next unless exists $vr->{raw}{$name}; |
|
2030
|
115
|
|
|
|
|
96
|
$names_found{$name} = 1; |
|
2031
|
115
|
|
|
|
|
108
|
my $v = $vr->{raw}{$name}; |
|
2032
|
115
|
100
|
|
|
|
165
|
push @raw_values, grep { defined $_ && $_ ne '' } ref $v eq 'ARRAY' ? @$v : $v; |
|
|
118
|
100
|
|
|
|
415
|
|
|
2033
|
|
|
|
|
|
|
# Make sure this parameter exists in {ps}, but don't |
|
2034
|
|
|
|
|
|
|
# change its status if any. |
|
2035
|
115
|
50
|
|
|
|
255
|
$vr->{ps}{$name} = undef unless exists $vr->{ps}{$name}; |
|
2036
|
|
|
|
|
|
|
} |
|
2037
|
|
|
|
|
|
|
|
|
2038
|
|
|
|
|
|
|
# If more than one of the aliases for this parameter was specified, and the 'multiple' |
|
2039
|
|
|
|
|
|
|
# option was not specified, then generate an error and go on to the next rule. We |
|
2040
|
|
|
|
|
|
|
# mark the parameter status as "error" (0), and we also mark the ruleset as fulfilled (2) |
|
2041
|
|
|
|
|
|
|
# if this was a 'param' or 'mandatory' rule. This last is done to avoid generating a |
|
2042
|
|
|
|
|
|
|
# spurious error message if the ruleset is not fulfilled by any other parameters. |
|
2043
|
|
|
|
|
|
|
|
|
2044
|
170
|
100
|
66
|
|
|
847
|
if ( keys(%names_found) > 1 && ! $rr->{multiple} ) |
|
|
|
50
|
66
|
|
|
|
|
|
|
|
100
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
2045
|
|
|
|
|
|
|
{ |
|
2046
|
1
|
|
|
|
|
8
|
add_error($vr, $rr, 'ERR_MULT_NAMES', { param => [ sort keys %names_found ] }); |
|
2047
|
1
|
|
|
|
|
3
|
$vr->{ps}{$param} = 0; |
|
2048
|
1
|
50
|
|
|
|
3
|
$vr->{rs}{$ruleset_name} = 2 unless $rr->{optional}; |
|
2049
|
1
|
|
|
|
|
3
|
next RULE; |
|
2050
|
|
|
|
|
|
|
} |
|
2051
|
|
|
|
|
|
|
|
|
2052
|
|
|
|
|
|
|
# If a clean value has already been determined for this parameter, then it was already |
|
2053
|
|
|
|
|
|
|
# recognized by some other rule. Consequently, this rule can be ignored. |
|
2054
|
|
|
|
|
|
|
|
|
2055
|
|
|
|
|
|
|
elsif ( exists $vr->{clean}{$key} ) |
|
2056
|
|
|
|
|
|
|
{ |
|
2057
|
0
|
|
|
|
|
0
|
next RULE; |
|
2058
|
|
|
|
|
|
|
} |
|
2059
|
|
|
|
|
|
|
|
|
2060
|
|
|
|
|
|
|
# If no values were specified for this parameter, check to see if the rule includes a |
|
2061
|
|
|
|
|
|
|
# default value. If so, use that instead and go on to the next rule. |
|
2062
|
|
|
|
|
|
|
|
|
2063
|
|
|
|
|
|
|
elsif ( ! @raw_values && exists $rr->{default} ) |
|
2064
|
|
|
|
|
|
|
{ |
|
2065
|
1
|
|
|
|
|
2
|
$vr->{clean}{$key} = $rr->{default}; |
|
2066
|
1
|
|
|
|
|
1
|
push @{$vr->{clean_list}}, $key; |
|
|
1
|
|
|
|
|
2
|
|
|
2067
|
1
|
|
|
|
|
3
|
next RULE; |
|
2068
|
|
|
|
|
|
|
} |
|
2069
|
|
|
|
|
|
|
|
|
2070
|
|
|
|
|
|
|
# If more than one value was given and the rule does not include the 'multiple' |
|
2071
|
|
|
|
|
|
|
# directive, signal an error. We mark the parameter status as "error" (0), and we |
|
2072
|
|
|
|
|
|
|
# also mark the ruleset as fulfilled (2) if this was a 'param' or 'mandatory' rule. |
|
2073
|
|
|
|
|
|
|
# This last is done to avoid generating a spurious error message if the ruleset is not |
|
2074
|
|
|
|
|
|
|
# fulfilled by any other parameters. |
|
2075
|
|
|
|
|
|
|
|
|
2076
|
|
|
|
|
|
|
elsif ( @raw_values > 1 && ! $rr->{multiple} ) |
|
2077
|
|
|
|
|
|
|
{ |
|
2078
|
2
|
|
|
|
|
10
|
add_error($vr, $rr, 'ERR_MULT_VALUES', |
|
2079
|
|
|
|
|
|
|
{ param => [ sort keys %names_found ], value => \@raw_values }); |
|
2080
|
2
|
|
|
|
|
4
|
$vr->{ps}{$param} = 0; |
|
2081
|
2
|
50
|
|
|
|
5
|
$vr->{rs}{$ruleset_name} = 2 unless $rr->{optional}; |
|
2082
|
2
|
|
|
|
|
5
|
next RULE; |
|
2083
|
|
|
|
|
|
|
} |
|
2084
|
|
|
|
|
|
|
|
|
2085
|
|
|
|
|
|
|
# Now we can process the rule. If the 'split' directive was |
|
2086
|
|
|
|
|
|
|
# given, split the value(s) using the specified regexp. |
|
2087
|
|
|
|
|
|
|
|
|
2088
|
166
|
100
|
|
|
|
212
|
if ( $rr->{split} ) |
|
2089
|
|
|
|
|
|
|
{ |
|
2090
|
|
|
|
|
|
|
# Split all of the raw values, and discard empty strings. |
|
2091
|
|
|
|
|
|
|
|
|
2092
|
22
|
50
|
|
|
|
64
|
my @new_values = grep { defined $_ && $_ ne '' } |
|
2093
|
20
|
|
|
|
|
22
|
map { split $rr->{split}, $_ } @raw_values; |
|
|
9
|
|
|
|
|
53
|
|
|
2094
|
20
|
|
|
|
|
26
|
@raw_values = @new_values; |
|
2095
|
|
|
|
|
|
|
} |
|
2096
|
|
|
|
|
|
|
|
|
2097
|
|
|
|
|
|
|
# If this is a 'flag' parameter and the parameter was present but |
|
2098
|
|
|
|
|
|
|
# no values were given, assume the value '1'. |
|
2099
|
|
|
|
|
|
|
|
|
2100
|
166
|
100
|
100
|
|
|
254
|
if ( $rr->{flag} && keys(%names_found) && ! @raw_values ) |
|
|
|
|
66
|
|
|
|
|
|
2101
|
|
|
|
|
|
|
{ |
|
2102
|
2
|
|
|
|
|
3
|
@raw_values = (1); |
|
2103
|
|
|
|
|
|
|
} |
|
2104
|
|
|
|
|
|
|
|
|
2105
|
|
|
|
|
|
|
# At this point, if there are no values then generate an error if |
|
2106
|
|
|
|
|
|
|
# the parameter is mandatory. Otherwise just skip this rule. |
|
2107
|
|
|
|
|
|
|
|
|
2108
|
166
|
100
|
|
|
|
214
|
unless ( @raw_values ) |
|
2109
|
|
|
|
|
|
|
{ |
|
2110
|
67
|
100
|
|
|
|
87
|
if ( $rr->{mandatory} ) |
|
2111
|
|
|
|
|
|
|
{ |
|
2112
|
2
|
|
|
|
|
8
|
add_error($vr, $rr, 'ERR_MANDATORY', { param => $rr->{param} }); |
|
2113
|
2
|
|
|
|
|
5
|
$vr->{ps}{$param} = 0; |
|
2114
|
2
|
50
|
|
|
|
11
|
$vr->{rs}{$ruleset_name} = 2 unless $rr->{optional}; |
|
2115
|
|
|
|
|
|
|
} |
|
2116
|
|
|
|
|
|
|
|
|
2117
|
67
|
|
|
|
|
107
|
next RULE; |
|
2118
|
|
|
|
|
|
|
} |
|
2119
|
|
|
|
|
|
|
|
|
2120
|
|
|
|
|
|
|
# Now indicate that at least one value was found for this |
|
2121
|
|
|
|
|
|
|
# parameter, even though we don't yet know if it is a good one. |
|
2122
|
|
|
|
|
|
|
# This will be necessary for properly handling 'together' and |
|
2123
|
|
|
|
|
|
|
# 'at_most_one' rules. |
|
2124
|
|
|
|
|
|
|
|
|
2125
|
99
|
|
|
|
|
93
|
$vr->{clean}{$key} = undef; |
|
2126
|
|
|
|
|
|
|
|
|
2127
|
|
|
|
|
|
|
# Now we process each value in turn. |
|
2128
|
|
|
|
|
|
|
|
|
2129
|
99
|
|
|
|
|
70
|
my @clean_values; |
|
2130
|
|
|
|
|
|
|
my $error_flag; |
|
2131
|
|
|
|
|
|
|
|
|
2132
|
|
|
|
|
|
|
VALUE: |
|
2133
|
99
|
|
|
|
|
91
|
foreach my $raw_val ( @raw_values ) |
|
2134
|
|
|
|
|
|
|
{ |
|
2135
|
|
|
|
|
|
|
# If no validators were defined, just pass all of the values |
|
2136
|
|
|
|
|
|
|
# that are not empty. |
|
2137
|
|
|
|
|
|
|
|
|
2138
|
111
|
100
|
|
|
|
144
|
unless ( $rr->{validators} ) |
|
2139
|
|
|
|
|
|
|
{ |
|
2140
|
40
|
50
|
33
|
|
|
108
|
if ( defined $raw_val && $raw_val ne '' ) |
|
2141
|
|
|
|
|
|
|
{ |
|
2142
|
40
|
100
|
|
|
|
99
|
$raw_val = $rr->{cleaner}($raw_val) if ref $rr->{cleaner} eq 'CODE'; |
|
2143
|
40
|
|
|
|
|
39
|
push @clean_values, $raw_val; |
|
2144
|
|
|
|
|
|
|
} |
|
2145
|
|
|
|
|
|
|
|
|
2146
|
40
|
|
|
|
|
42
|
next VALUE; |
|
2147
|
|
|
|
|
|
|
} |
|
2148
|
|
|
|
|
|
|
|
|
2149
|
|
|
|
|
|
|
# Otherwise, check each value against the validators in turn until |
|
2150
|
|
|
|
|
|
|
# one of them passes the value or until we have tried them |
|
2151
|
|
|
|
|
|
|
# all. |
|
2152
|
|
|
|
|
|
|
|
|
2153
|
71
|
|
|
|
|
53
|
my $result; |
|
2154
|
|
|
|
|
|
|
|
|
2155
|
|
|
|
|
|
|
VALIDATOR: |
|
2156
|
71
|
|
|
|
|
46
|
foreach my $validator ( @{$rr->{validators}} ) |
|
|
71
|
|
|
|
|
76
|
|
|
2157
|
|
|
|
|
|
|
{ |
|
2158
|
71
|
|
|
|
|
106
|
$result = $validator->($raw_val, $vr->{context}); |
|
2159
|
|
|
|
|
|
|
|
|
2160
|
|
|
|
|
|
|
# If the result is not a hash ref, then the value passes |
|
2161
|
|
|
|
|
|
|
# the test. |
|
2162
|
|
|
|
|
|
|
|
|
2163
|
71
|
100
|
66
|
|
|
267
|
last VALIDATOR unless ref $result && reftype $result eq 'HASH'; |
|
2164
|
|
|
|
|
|
|
|
|
2165
|
|
|
|
|
|
|
# If the result contains an 'error' key, then we need to |
|
2166
|
|
|
|
|
|
|
# try the next validator (if any). Otherwise, the value |
|
2167
|
|
|
|
|
|
|
# passes the test. |
|
2168
|
|
|
|
|
|
|
|
|
2169
|
67
|
100
|
|
|
|
124
|
last VALIDATOR unless $result->{error}; |
|
2170
|
|
|
|
|
|
|
} |
|
2171
|
|
|
|
|
|
|
|
|
2172
|
|
|
|
|
|
|
# If the last validator to be tried generated an error, then |
|
2173
|
|
|
|
|
|
|
# the value is bad. We must report it and skip to the next value. |
|
2174
|
|
|
|
|
|
|
|
|
2175
|
71
|
100
|
66
|
|
|
209
|
if ( ref $result and $result->{error} ) |
|
2176
|
|
|
|
|
|
|
{ |
|
2177
|
|
|
|
|
|
|
# If the rule contains a 'warn' directive, then generate a |
|
2178
|
|
|
|
|
|
|
# warning. But the value is still bad, and will be |
|
2179
|
|
|
|
|
|
|
# ignored. |
|
2180
|
|
|
|
|
|
|
|
|
2181
|
25
|
100
|
|
|
|
37
|
if ( $rr->{warn} ) |
|
2182
|
|
|
|
|
|
|
{ |
|
2183
|
|
|
|
|
|
|
my $msg = $rr->{warn} ne '1' ? $rr->{warn} : |
|
2184
|
8
|
50
|
33
|
|
|
36
|
$rr->{ERR_INVALID} || $rr->{errmsg} || $result->{error}; |
|
2185
|
8
|
|
|
|
|
28
|
add_warning($vr, $rr, $msg, { param => [ keys %names_found ], value => $raw_val }); |
|
2186
|
|
|
|
|
|
|
} |
|
2187
|
|
|
|
|
|
|
|
|
2188
|
|
|
|
|
|
|
# Otherwise, generate an error. |
|
2189
|
|
|
|
|
|
|
|
|
2190
|
|
|
|
|
|
|
else |
|
2191
|
|
|
|
|
|
|
{ |
|
2192
|
17
|
|
33
|
|
|
41
|
my $msg = $rr->{ERR_INVALID} || $rr->{errmsg} || $result->{error}; |
|
2193
|
17
|
|
|
|
|
54
|
add_error($vr, $rr, $msg, { param => [ sort keys %names_found ], value => $raw_val }); |
|
2194
|
|
|
|
|
|
|
} |
|
2195
|
|
|
|
|
|
|
|
|
2196
|
25
|
|
|
|
|
37
|
$error_flag = 1; |
|
2197
|
25
|
|
|
|
|
37
|
next VALUE; |
|
2198
|
|
|
|
|
|
|
} |
|
2199
|
|
|
|
|
|
|
|
|
2200
|
|
|
|
|
|
|
# If the result contains a 'warn' field, then generate a |
|
2201
|
|
|
|
|
|
|
# warning. In this case, the value is still assumed to be |
|
2202
|
|
|
|
|
|
|
# good. |
|
2203
|
|
|
|
|
|
|
|
|
2204
|
46
|
100
|
66
|
|
|
103
|
if ( ref $result and $result->{warn} ) |
|
2205
|
|
|
|
|
|
|
{ |
|
2206
|
1
|
|
|
|
|
5
|
add_warning($vr, $rr, $result->{warn}, { param => [ sort keys %names_found ], value => $raw_val }); |
|
2207
|
|
|
|
|
|
|
} |
|
2208
|
|
|
|
|
|
|
|
|
2209
|
|
|
|
|
|
|
# If we get here, then the value is good. If the result was a |
|
2210
|
|
|
|
|
|
|
# hash ref with a 'value' field, we use that for the clean |
|
2211
|
|
|
|
|
|
|
# value. Otherwise, we use the raw value. |
|
2212
|
|
|
|
|
|
|
|
|
2213
|
46
|
100
|
66
|
|
|
95
|
my $value = ref $result && exists $result->{value} ? $result->{value} : $raw_val; |
|
2214
|
|
|
|
|
|
|
|
|
2215
|
|
|
|
|
|
|
# If a cleaning subroutine was defined, pass the value through |
|
2216
|
|
|
|
|
|
|
# it and save the cleaned value. |
|
2217
|
|
|
|
|
|
|
|
|
2218
|
46
|
50
|
|
|
|
71
|
$value = $rr->{cleaner}($value) if ref $rr->{cleaner} eq 'CODE'; |
|
2219
|
|
|
|
|
|
|
|
|
2220
|
46
|
|
|
|
|
76
|
push @clean_values, $value; |
|
2221
|
|
|
|
|
|
|
} |
|
2222
|
|
|
|
|
|
|
|
|
2223
|
|
|
|
|
|
|
# If clean values were found, store them. If multiple values are |
|
2224
|
|
|
|
|
|
|
# allowed, then we store them as a list. Otherwise, there should |
|
2225
|
|
|
|
|
|
|
# only be one clean value and so we just store it as a scalar. |
|
2226
|
|
|
|
|
|
|
|
|
2227
|
99
|
100
|
|
|
|
125
|
if ( @clean_values ) |
|
2228
|
|
|
|
|
|
|
{ |
|
2229
|
78
|
|
|
|
|
51
|
push @{$vr->{clean_list}}, $key; |
|
|
78
|
|
|
|
|
93
|
|
|
2230
|
|
|
|
|
|
|
|
|
2231
|
78
|
100
|
|
|
|
98
|
if ( $rr->{multiple} ) |
|
2232
|
|
|
|
|
|
|
{ |
|
2233
|
7
|
|
|
|
|
9
|
$vr->{clean}{$key} = \@clean_values; |
|
2234
|
|
|
|
|
|
|
} |
|
2235
|
|
|
|
|
|
|
|
|
2236
|
|
|
|
|
|
|
else |
|
2237
|
|
|
|
|
|
|
{ |
|
2238
|
71
|
|
|
|
|
79
|
$vr->{clean}{$key} = $clean_values[0]; |
|
2239
|
|
|
|
|
|
|
} |
|
2240
|
|
|
|
|
|
|
} |
|
2241
|
|
|
|
|
|
|
|
|
2242
|
|
|
|
|
|
|
# If raw values were found for this parameter, but none of them |
|
2243
|
|
|
|
|
|
|
# pass the validators, then we need to indicate this condition. |
|
2244
|
|
|
|
|
|
|
|
|
2245
|
|
|
|
|
|
|
else |
|
2246
|
|
|
|
|
|
|
{ |
|
2247
|
21
|
|
|
|
|
12
|
push @{$vr->{clean_list}}, $key; |
|
|
21
|
|
|
|
|
33
|
|
|
2248
|
|
|
|
|
|
|
|
|
2249
|
21
|
100
|
100
|
|
|
61
|
if ( defined $rr->{bad_value} && $rr->{bad_value} eq 'ERROR' ) |
|
|
|
100
|
|
|
|
|
|
|
2250
|
|
|
|
|
|
|
{ |
|
2251
|
2
|
|
|
|
|
19
|
add_error($vr, $rr, 'ERR_BAD_VALUES', |
|
2252
|
|
|
|
|
|
|
{ param => [ sort keys %names_found ], value => \@raw_values }); |
|
2253
|
2
|
|
|
|
|
5
|
$vr->{clean}{$key} = undef; |
|
2254
|
2
|
|
|
|
|
2
|
$error_flag = 1; |
|
2255
|
|
|
|
|
|
|
} |
|
2256
|
|
|
|
|
|
|
|
|
2257
|
|
|
|
|
|
|
elsif ( defined $rr->{bad_value} ) |
|
2258
|
|
|
|
|
|
|
{ |
|
2259
|
1
|
50
|
|
|
|
6
|
$vr->{clean}{$key} = $rr->{multiple} ? [ $rr->{bad_value} ] : $rr->{bad_value}; |
|
2260
|
|
|
|
|
|
|
} |
|
2261
|
|
|
|
|
|
|
|
|
2262
|
|
|
|
|
|
|
else |
|
2263
|
|
|
|
|
|
|
{ |
|
2264
|
18
|
|
|
|
|
18
|
$vr->{clean}{$key} = undef; |
|
2265
|
|
|
|
|
|
|
} |
|
2266
|
|
|
|
|
|
|
} |
|
2267
|
|
|
|
|
|
|
|
|
2268
|
|
|
|
|
|
|
# Set the status of this parameter to 1 (passed) unless an error |
|
2269
|
|
|
|
|
|
|
# was generated, 0 (failed) otherwise. |
|
2270
|
|
|
|
|
|
|
|
|
2271
|
99
|
100
|
|
|
|
129
|
$vr->{ps}{$param} = $error_flag ? 0 : 1; |
|
2272
|
|
|
|
|
|
|
|
|
2273
|
|
|
|
|
|
|
# If this rule is not 'optional', then set the status of this |
|
2274
|
|
|
|
|
|
|
# ruleset to 'fulfilled' (2). That does not mean that the validation |
|
2275
|
|
|
|
|
|
|
# passes, because the parameter value may still have generated an |
|
2276
|
|
|
|
|
|
|
# error. |
|
2277
|
|
|
|
|
|
|
|
|
2278
|
99
|
100
|
|
|
|
163
|
unless ( $rr->{optional} ) |
|
2279
|
|
|
|
|
|
|
{ |
|
2280
|
77
|
|
|
|
|
173
|
$vr->{rs}{$ruleset_name} = 2; |
|
2281
|
|
|
|
|
|
|
} |
|
2282
|
|
|
|
|
|
|
} |
|
2283
|
|
|
|
|
|
|
|
|
2284
|
|
|
|
|
|
|
# An 'ignore' directive causes the parameter to be recognized, but no |
|
2285
|
|
|
|
|
|
|
# cleaned value is generated and the containing ruleset is not |
|
2286
|
|
|
|
|
|
|
# triggered. No error messages will be generated for this parameter, |
|
2287
|
|
|
|
|
|
|
# either. |
|
2288
|
|
|
|
|
|
|
|
|
2289
|
|
|
|
|
|
|
elsif ( $rr->{type} eq 'ignore' ) |
|
2290
|
|
|
|
|
|
|
{ |
|
2291
|
|
|
|
|
|
|
# Make sure that the parameter is counted as having been |
|
2292
|
|
|
|
|
|
|
# recognized. |
|
2293
|
|
|
|
|
|
|
|
|
2294
|
0
|
|
|
|
|
0
|
foreach my $param ( @{$rr->{param}} ) |
|
|
0
|
|
|
|
|
0
|
|
|
2295
|
|
|
|
|
|
|
{ |
|
2296
|
0
|
|
|
|
|
0
|
$vr->{ps}{$param} = undef; |
|
2297
|
|
|
|
|
|
|
|
|
2298
|
|
|
|
|
|
|
# Make sure that errors, warnings, and cleaned values for this key |
|
2299
|
|
|
|
|
|
|
# are ignored. |
|
2300
|
|
|
|
|
|
|
|
|
2301
|
0
|
|
0
|
|
|
0
|
my $key = $rr->{key} || $param; |
|
2302
|
0
|
|
|
|
|
0
|
$vr->{ig}{$key} = 1; |
|
2303
|
0
|
|
|
|
|
0
|
delete $vr->{clean}{$param}; |
|
2304
|
|
|
|
|
|
|
} |
|
2305
|
|
|
|
|
|
|
} |
|
2306
|
|
|
|
|
|
|
|
|
2307
|
|
|
|
|
|
|
# A 'together' or 'at_most_one' rule requires checking the presence |
|
2308
|
|
|
|
|
|
|
# of each of the specified parameters. This kind of rule does not |
|
2309
|
|
|
|
|
|
|
# affect the status of any parameters or rulesets, but if violated |
|
2310
|
|
|
|
|
|
|
# will generate an error message and cause the entire validation to |
|
2311
|
|
|
|
|
|
|
# fail. |
|
2312
|
|
|
|
|
|
|
|
|
2313
|
|
|
|
|
|
|
elsif ( $rr->{type} eq 'together' or $rr->{type} eq 'at_most_one' ) |
|
2314
|
|
|
|
|
|
|
{ |
|
2315
|
|
|
|
|
|
|
# We start by listing those that are present in the parameter set. |
|
2316
|
|
|
|
|
|
|
|
|
2317
|
12
|
|
|
|
|
10
|
my @present = grep exists $vr->{clean}{$_}, @{$rr->{param}}; |
|
|
12
|
|
|
|
|
30
|
|
|
2318
|
|
|
|
|
|
|
|
|
2319
|
|
|
|
|
|
|
# For a 'together' rule, the count must equal the number of |
|
2320
|
|
|
|
|
|
|
# arguments to this rule, or must be zero. In other words, there |
|
2321
|
|
|
|
|
|
|
# must be none present or all present. |
|
2322
|
|
|
|
|
|
|
|
|
2323
|
12
|
100
|
100
|
|
|
68
|
if ( $rr->{type} eq 'together' and @present > 0 and @present < @{$rr->{param}} ) |
|
|
1
|
100
|
66
|
|
|
3
|
|
|
|
|
|
100
|
|
|
|
|
|
2324
|
|
|
|
|
|
|
{ |
|
2325
|
1
|
|
|
|
|
5
|
add_error_warn($vr, $rr, 'ERR_TOGETHER', { param => $rr->{param} }); |
|
2326
|
|
|
|
|
|
|
} |
|
2327
|
|
|
|
|
|
|
|
|
2328
|
|
|
|
|
|
|
# For a 'at_most_one' rule, the count must be less than or equal |
|
2329
|
|
|
|
|
|
|
# to one (i.e. not more than one must have been specified). |
|
2330
|
|
|
|
|
|
|
|
|
2331
|
|
|
|
|
|
|
elsif ( $rr->{type} eq 'at_most_one' and @present > 1 ) |
|
2332
|
|
|
|
|
|
|
{ |
|
2333
|
2
|
|
|
|
|
5
|
add_error_warn($vr, $rr, 'ERR_AT_MOST', { param => \@present }); |
|
2334
|
|
|
|
|
|
|
} |
|
2335
|
|
|
|
|
|
|
} |
|
2336
|
|
|
|
|
|
|
|
|
2337
|
|
|
|
|
|
|
# For an 'include' rule, we immediately check the given ruleset |
|
2338
|
|
|
|
|
|
|
# (unless it has already been checked). This statement essentially |
|
2339
|
|
|
|
|
|
|
# includes one ruleset within another. It is very powerful, because |
|
2340
|
|
|
|
|
|
|
# it allows different route handlers to to validate their parameters |
|
2341
|
|
|
|
|
|
|
# using common rulesets. |
|
2342
|
|
|
|
|
|
|
|
|
2343
|
|
|
|
|
|
|
elsif ( $rr->{type} eq 'include' ) |
|
2344
|
|
|
|
|
|
|
{ |
|
2345
|
22
|
|
|
|
|
17
|
my $rs_name = $rr->{ruleset}; |
|
2346
|
|
|
|
|
|
|
|
|
2347
|
|
|
|
|
|
|
# First try to validate the given ruleset. |
|
2348
|
|
|
|
|
|
|
|
|
2349
|
22
|
|
|
|
|
43
|
$self->validate_ruleset($vr, $rs_name); |
|
2350
|
|
|
|
|
|
|
|
|
2351
|
|
|
|
|
|
|
# If it was a 'require' rule, check to see if the ruleset was |
|
2352
|
|
|
|
|
|
|
# fulfilled. |
|
2353
|
|
|
|
|
|
|
|
|
2354
|
22
|
100
|
100
|
|
|
68
|
if ( $rr->{require} and not $vr->{rs}{$rs_name} == 2 ) |
|
2355
|
|
|
|
|
|
|
{ |
|
2356
|
1
|
|
|
|
|
1
|
my (@missing, %found); |
|
2357
|
|
|
|
|
|
|
|
|
2358
|
1
|
|
|
|
|
1
|
@missing = grep { unique($_, \%found) } @{$self->{RULESETS}{$rs_name}{fulfill_order}}; |
|
|
2
|
|
|
|
|
4
|
|
|
|
1
|
|
|
|
|
6
|
|
|
2359
|
|
|
|
|
|
|
|
|
2360
|
1
|
50
|
|
|
|
3
|
my $msg = @missing == 1 ? 'ERR_REQ_SINGLE' : 'ERR_REQ_MULT'; |
|
2361
|
1
|
|
|
|
|
3
|
add_error_warn($vr, $rr, $msg, { param => \@missing }); |
|
2362
|
|
|
|
|
|
|
} |
|
2363
|
|
|
|
|
|
|
} |
|
2364
|
|
|
|
|
|
|
|
|
2365
|
|
|
|
|
|
|
elsif ( $rr->{type} eq 'constraint' ) |
|
2366
|
|
|
|
|
|
|
{ |
|
2367
|
|
|
|
|
|
|
# From the list of rulesets specified in this rule, check how many |
|
2368
|
|
|
|
|
|
|
# were and were not fulfilled. |
|
2369
|
|
|
|
|
|
|
|
|
2370
|
6
|
|
|
|
|
6
|
my @fulfilled = grep { $vr->{rs}{$_} == 2 } @{$rr->{ruleset}}; |
|
|
12
|
|
|
|
|
21
|
|
|
|
6
|
|
|
|
|
7
|
|
|
2371
|
6
|
|
|
|
|
7
|
my @not_fulfilled = grep { $vr->{rs}{$_} != 2 } @{$rr->{ruleset}}; |
|
|
12
|
|
|
|
|
16
|
|
|
|
6
|
|
|
|
|
7
|
|
|
2372
|
|
|
|
|
|
|
|
|
2373
|
|
|
|
|
|
|
# For a 'require_one' or 'require_any' rule, generate an error if |
|
2374
|
|
|
|
|
|
|
# not enough of the rulesets are fulfilled. List all of the |
|
2375
|
|
|
|
|
|
|
# parameters which could be given in order to fulfill these |
|
2376
|
|
|
|
|
|
|
# rulesets. |
|
2377
|
|
|
|
|
|
|
|
|
2378
|
6
|
100
|
66
|
|
|
35
|
if ( @fulfilled == 0 and ( $rr->{constraint} eq 'require_one' or |
|
|
|
50
|
66
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
2379
|
|
|
|
|
|
|
$rr->{constraint} eq 'require_any' ) ) |
|
2380
|
|
|
|
|
|
|
{ |
|
2381
|
4
|
|
|
|
|
5
|
my (@missing, %found); |
|
2382
|
|
|
|
|
|
|
|
|
2383
|
12
|
|
|
|
|
13
|
@missing = grep { unique($_, \%found) } |
|
2384
|
4
|
|
|
|
|
3
|
map { @{$self->{RULESETS}{$_}{fulfill_order}} } @not_fulfilled; |
|
|
8
|
|
|
|
|
3
|
|
|
|
8
|
|
|
|
|
16
|
|
|
2385
|
|
|
|
|
|
|
|
|
2386
|
4
|
50
|
|
|
|
6
|
my $msg = @missing == 1 ? 'ERR_REQ_SINGLE' : 'ERR_REQ_MULT'; |
|
2387
|
4
|
|
|
|
|
8
|
add_error_warn($vr, $rr, $msg, { param => \@missing }); |
|
2388
|
|
|
|
|
|
|
} |
|
2389
|
|
|
|
|
|
|
|
|
2390
|
|
|
|
|
|
|
# For an 'allow_one' or 'require_one' rule, generate an error if |
|
2391
|
|
|
|
|
|
|
# more than one of the rulesets was fulfilled. |
|
2392
|
|
|
|
|
|
|
|
|
2393
|
|
|
|
|
|
|
elsif ( @fulfilled > 1 and ($rr->{constraint} eq 'allow_one' or |
|
2394
|
|
|
|
|
|
|
$rr->{constraint} eq 'require_one') ) |
|
2395
|
|
|
|
|
|
|
{ |
|
2396
|
2
|
|
|
|
|
1
|
my @params; |
|
2397
|
2
|
|
|
|
|
3
|
my ($label) = "A"; |
|
2398
|
|
|
|
|
|
|
|
|
2399
|
2
|
|
|
|
|
3
|
foreach my $rs ( @fulfilled ) |
|
2400
|
|
|
|
|
|
|
{ |
|
2401
|
4
|
|
|
|
|
6
|
push @params, "($label)"; $label++; |
|
|
4
|
|
|
|
|
3
|
|
|
2402
|
4
|
|
|
|
|
6
|
push @params, @{$self->{RULESETS}{$rs}{fulfill_order}} |
|
2403
|
4
|
50
|
|
|
|
9
|
if ref $self->{RULESETS}{$rs}{fulfill_order} eq 'ARRAY'; |
|
2404
|
|
|
|
|
|
|
} |
|
2405
|
|
|
|
|
|
|
|
|
2406
|
2
|
|
|
|
|
3
|
my $message = 'ERR_REQ_ONE'; |
|
2407
|
|
|
|
|
|
|
|
|
2408
|
2
|
|
|
|
|
4
|
add_error_warn($vr, $rr, 'ERR_REQ_ONE', { param => \@params }); |
|
2409
|
|
|
|
|
|
|
} |
|
2410
|
|
|
|
|
|
|
} |
|
2411
|
|
|
|
|
|
|
|
|
2412
|
|
|
|
|
|
|
# For a 'content_type' rule, we set the content type of the response |
|
2413
|
|
|
|
|
|
|
# according to the given parameter. |
|
2414
|
|
|
|
|
|
|
|
|
2415
|
|
|
|
|
|
|
elsif ( $type eq 'content_type' ) |
|
2416
|
|
|
|
|
|
|
{ |
|
2417
|
4
|
|
|
|
|
4
|
my $param = $rr->{param}; |
|
2418
|
4
|
|
100
|
|
|
16
|
my $value = $vr->{raw}{$param} || ''; |
|
2419
|
4
|
|
33
|
|
|
11
|
my $clean_name = $rr->{key} || $rr->{param}; |
|
2420
|
4
|
|
|
|
|
4
|
my ($selected, $selected_type); |
|
2421
|
|
|
|
|
|
|
|
|
2422
|
4
|
|
|
|
|
4
|
push @{$vr->{clean_list}}, $key; |
|
|
4
|
|
|
|
|
7
|
|
|
2423
|
|
|
|
|
|
|
|
|
2424
|
4
|
100
|
|
|
|
7
|
if ( $rr->{type_map}{$value} ) |
|
2425
|
|
|
|
|
|
|
{ |
|
2426
|
3
|
|
|
|
|
5
|
$vr->{content_type} = $rr->{type_map}{$value}; |
|
2427
|
3
|
|
|
|
|
3
|
$vr->{clean}{$clean_name} = $value; |
|
2428
|
3
|
|
|
|
|
7
|
$vr->{ps}{$param} = 1; |
|
2429
|
|
|
|
|
|
|
} |
|
2430
|
|
|
|
|
|
|
|
|
2431
|
|
|
|
|
|
|
else |
|
2432
|
|
|
|
|
|
|
{ |
|
2433
|
1
|
|
|
|
|
2
|
$vr->{content_type} = 'unknown'; |
|
2434
|
1
|
|
|
|
|
2
|
$vr->{clean}{$clean_name} = undef; |
|
2435
|
1
|
|
|
|
|
2
|
$vr->{ps}{$param} = 1; |
|
2436
|
1
|
|
50
|
|
|
4
|
$rr->{key} ||= '_content_type'; |
|
2437
|
1
|
|
|
|
|
3
|
add_error_warn($vr, $rr, 'ERR_MEDIA_TYPE', { param => $param, value => $rr->{type_list} }); |
|
2438
|
|
|
|
|
|
|
} |
|
2439
|
|
|
|
|
|
|
} |
|
2440
|
|
|
|
|
|
|
} |
|
2441
|
|
|
|
|
|
|
}; |
|
2442
|
|
|
|
|
|
|
|
|
2443
|
|
|
|
|
|
|
|
|
2444
|
|
|
|
|
|
|
# Helper function - given a hashref to use as a scratchpad, returns true the |
|
2445
|
|
|
|
|
|
|
# first time a given argument is encountered and false each subsequent time. |
|
2446
|
|
|
|
|
|
|
# This can be reset by calling it with a newly emptied scratchpad. |
|
2447
|
|
|
|
|
|
|
|
|
2448
|
|
|
|
|
|
|
sub unique { |
|
2449
|
|
|
|
|
|
|
|
|
2450
|
14
|
|
|
14
|
0
|
14
|
my ($arg, $scratch) = @_; |
|
2451
|
|
|
|
|
|
|
|
|
2452
|
14
|
50
|
|
|
|
19
|
return if exists $scratch->{$arg}; |
|
2453
|
14
|
|
|
|
|
23
|
$scratch->{$arg} = 1; |
|
2454
|
|
|
|
|
|
|
} |
|
2455
|
|
|
|
|
|
|
|
|
2456
|
|
|
|
|
|
|
|
|
2457
|
|
|
|
|
|
|
# Add an error message to the current validation. |
|
2458
|
|
|
|
|
|
|
|
|
2459
|
|
|
|
|
|
|
sub add_error { |
|
2460
|
|
|
|
|
|
|
|
|
2461
|
34
|
|
|
34
|
0
|
38
|
my ($vr, $rr, $msg, $subst) = @_; |
|
2462
|
|
|
|
|
|
|
|
|
2463
|
|
|
|
|
|
|
# If no message was given, use a default one. It's not a very good |
|
2464
|
|
|
|
|
|
|
# message, but what can we do? |
|
2465
|
|
|
|
|
|
|
|
|
2466
|
34
|
|
50
|
|
|
53
|
$msg ||= 'ERR_DEFAULT'; |
|
2467
|
|
|
|
|
|
|
|
|
2468
|
|
|
|
|
|
|
# If the given message starts with 'ERR_', assume it is an error code. If |
|
2469
|
|
|
|
|
|
|
# the code is present as an attribute of the rule record, use the |
|
2470
|
|
|
|
|
|
|
# corresponding value as the message. Otherwise, use the global value. |
|
2471
|
|
|
|
|
|
|
|
|
2472
|
34
|
100
|
|
|
|
168
|
if ( $msg =~ qr{^ERR_} ) |
|
2473
|
|
|
|
|
|
|
{ |
|
2474
|
17
|
|
33
|
|
|
63
|
$msg = $rr->{$msg} || $vr->{settings}{$msg} || $ERROR_MSG{$msg} || $ERROR_MSG{ERR_DEFAULT}; |
|
2475
|
|
|
|
|
|
|
} |
|
2476
|
|
|
|
|
|
|
|
|
2477
|
|
|
|
|
|
|
# Next, figure out the error key. If the rule has a 'key' directive, use |
|
2478
|
|
|
|
|
|
|
# that. Otherwise determine it according to the rule type, ruleset name, |
|
2479
|
|
|
|
|
|
|
# and rule number. |
|
2480
|
|
|
|
|
|
|
|
|
2481
|
|
|
|
|
|
|
my $err_key = $rr->{key} ? $rr->{key} |
|
2482
|
|
|
|
|
|
|
: $rr->{type} eq 'param' ? $rr->{param} |
|
2483
|
34
|
50
|
|
|
|
117
|
: $rr->{type} eq 'content_type' ? '_content_type' |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
2484
|
|
|
|
|
|
|
: "_$rr->{rs}{name}_$rr->{rn}"; |
|
2485
|
|
|
|
|
|
|
|
|
2486
|
|
|
|
|
|
|
# Record the error message under the key, and add the key to the error |
|
2487
|
|
|
|
|
|
|
# list. Other rules might later remove or alter the error |
|
2488
|
|
|
|
|
|
|
# message. |
|
2489
|
|
|
|
|
|
|
|
|
2490
|
34
|
|
|
|
|
20
|
push @{$vr->{er}}, [$err_key, subst_error($msg, $subst)]; |
|
|
34
|
|
|
|
|
68
|
|
|
2491
|
34
|
|
|
|
|
95
|
$vr->{ec}{$err_key}++; |
|
2492
|
|
|
|
|
|
|
} |
|
2493
|
|
|
|
|
|
|
|
|
2494
|
|
|
|
|
|
|
|
|
2495
|
|
|
|
|
|
|
# Add a warning message to the current validation. The $subst hash if |
|
2496
|
|
|
|
|
|
|
# given specifies placeholder substitutions. |
|
2497
|
|
|
|
|
|
|
|
|
2498
|
|
|
|
|
|
|
sub add_warning { |
|
2499
|
|
|
|
|
|
|
|
|
2500
|
11
|
|
|
11
|
0
|
14
|
my ($vr, $rr, $msg, $subst) = @_; |
|
2501
|
|
|
|
|
|
|
|
|
2502
|
|
|
|
|
|
|
# If no message was given, use a default one. It's not a very good |
|
2503
|
|
|
|
|
|
|
# message, but what can we do? |
|
2504
|
|
|
|
|
|
|
|
|
2505
|
11
|
|
50
|
|
|
18
|
$msg ||= 'ERR_DEFAULT'; |
|
2506
|
|
|
|
|
|
|
|
|
2507
|
|
|
|
|
|
|
# If the given message starts with 'ERR_', assume it is an error code. If |
|
2508
|
|
|
|
|
|
|
# the code is present as an attribute of the rule record, use the |
|
2509
|
|
|
|
|
|
|
# corresponding value as the message. Otherwise, use the global value. |
|
2510
|
|
|
|
|
|
|
|
|
2511
|
11
|
100
|
|
|
|
47
|
if ( $msg =~ qr{^ERR_} ) |
|
2512
|
|
|
|
|
|
|
{ |
|
2513
|
1
|
|
0
|
|
|
12
|
$msg = $rr->{$msg} || $vr->{settings}{$msg} || $ERROR_MSG{$msg} || $ERROR_MSG{ERR_DEFAULT}; |
|
2514
|
|
|
|
|
|
|
} |
|
2515
|
|
|
|
|
|
|
|
|
2516
|
|
|
|
|
|
|
# Next, figure out the warning key. If the rule has a 'key' directive, use |
|
2517
|
|
|
|
|
|
|
# that. Otherwise determine it according to the rule type, ruleset name, |
|
2518
|
|
|
|
|
|
|
# and rule number. |
|
2519
|
|
|
|
|
|
|
|
|
2520
|
|
|
|
|
|
|
my $warn_key = $rr->{key} ? $rr->{key} |
|
2521
|
|
|
|
|
|
|
: $rr->{type} eq 'param' ? $rr->{param} |
|
2522
|
11
|
50
|
|
|
|
60
|
: $rr->{type} eq 'content_type' ? '_content_type' |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
2523
|
|
|
|
|
|
|
: "_$rr->{rs}{name}_$rr->{rn}"; |
|
2524
|
|
|
|
|
|
|
|
|
2525
|
|
|
|
|
|
|
# Record the warning message under the key. Other rules might later |
|
2526
|
|
|
|
|
|
|
# alter the warning message if they use the same key. |
|
2527
|
|
|
|
|
|
|
|
|
2528
|
11
|
|
|
|
|
11
|
push @{$vr->{wn}}, [$warn_key, subst_error($msg, $subst)]; |
|
|
11
|
|
|
|
|
23
|
|
|
2529
|
11
|
|
|
|
|
33
|
$vr->{wc}{$warn_key}++; |
|
2530
|
|
|
|
|
|
|
} |
|
2531
|
|
|
|
|
|
|
|
|
2532
|
|
|
|
|
|
|
|
|
2533
|
|
|
|
|
|
|
# Add an error or warning message to the current validation. If the rule has |
|
2534
|
|
|
|
|
|
|
# a 'warn' attribute, add a warning. Otherwise, add an error. If the rule |
|
2535
|
|
|
|
|
|
|
# has an 'errmsg' attribute, use its value instead of the error message given. |
|
2536
|
|
|
|
|
|
|
|
|
2537
|
|
|
|
|
|
|
sub add_error_warn { |
|
2538
|
|
|
|
|
|
|
|
|
2539
|
11
|
|
|
11
|
0
|
13
|
my ($vr, $rr, $msg, $subst) = @_; |
|
2540
|
|
|
|
|
|
|
|
|
2541
|
11
|
50
|
|
|
|
18
|
$msg = $rr->{errmsg} if $rr->{errmsg}; |
|
2542
|
|
|
|
|
|
|
|
|
2543
|
11
|
100
|
|
|
|
16
|
if ( $rr->{warn} ) |
|
2544
|
|
|
|
|
|
|
{ |
|
2545
|
2
|
100
|
|
|
|
5
|
$msg = $rr->{warn} if $rr->{warn} ne '1'; |
|
2546
|
2
|
|
|
|
|
4
|
return add_warning($vr, $rr, $msg, $subst); |
|
2547
|
|
|
|
|
|
|
} |
|
2548
|
|
|
|
|
|
|
|
|
2549
|
|
|
|
|
|
|
else |
|
2550
|
|
|
|
|
|
|
{ |
|
2551
|
9
|
|
|
|
|
11
|
return add_error($vr, $rr, $msg, $subst); |
|
2552
|
|
|
|
|
|
|
} |
|
2553
|
|
|
|
|
|
|
} |
|
2554
|
|
|
|
|
|
|
|
|
2555
|
|
|
|
|
|
|
|
|
2556
|
|
|
|
|
|
|
# Substitute placeholders in an error or warning message. |
|
2557
|
|
|
|
|
|
|
|
|
2558
|
|
|
|
|
|
|
sub subst_error { |
|
2559
|
|
|
|
|
|
|
|
|
2560
|
45
|
|
|
45
|
0
|
61
|
my ($message, $subst) = @_; |
|
2561
|
|
|
|
|
|
|
|
|
2562
|
45
|
|
|
|
|
159
|
while ( $message =~ /^(.*)\{(\w+)\}(.*)$/ ) |
|
2563
|
|
|
|
|
|
|
{ |
|
2564
|
46
|
|
|
|
|
78
|
my $value = $subst->{$2}; |
|
2565
|
|
|
|
|
|
|
|
|
2566
|
46
|
100
|
33
|
|
|
79
|
if ( ref $value ) |
|
|
|
50
|
|
|
|
|
|
|
2567
|
|
|
|
|
|
|
{ |
|
2568
|
42
|
50
|
|
|
|
69
|
if ( reftype $value eq 'ARRAY' ) |
|
|
|
0
|
|
|
|
|
|
|
2569
|
|
|
|
|
|
|
{ |
|
2570
|
42
|
|
|
|
|
55
|
$value = name_list(@$value); |
|
2571
|
|
|
|
|
|
|
} |
|
2572
|
|
|
|
|
|
|
elsif ( reftype $value eq 'HASH' ) |
|
2573
|
|
|
|
|
|
|
{ |
|
2574
|
0
|
|
|
|
|
0
|
$value = name_list(sort keys %$value); |
|
2575
|
|
|
|
|
|
|
} |
|
2576
|
|
|
|
|
|
|
} |
|
2577
|
|
|
|
|
|
|
|
|
2578
|
|
|
|
|
|
|
elsif ( defined $value && $value !~ /^'/ ) |
|
2579
|
|
|
|
|
|
|
{ |
|
2580
|
4
|
|
|
|
|
8
|
$value = "'$value'"; |
|
2581
|
|
|
|
|
|
|
} |
|
2582
|
|
|
|
|
|
|
|
|
2583
|
|
|
|
|
|
|
else |
|
2584
|
|
|
|
|
|
|
{ |
|
2585
|
0
|
|
|
|
|
0
|
$value = "''"; |
|
2586
|
|
|
|
|
|
|
} |
|
2587
|
|
|
|
|
|
|
|
|
2588
|
46
|
50
|
33
|
|
|
274
|
$message = "$1$value$3" if defined $value and $value ne ''; |
|
2589
|
|
|
|
|
|
|
} |
|
2590
|
|
|
|
|
|
|
|
|
2591
|
45
|
|
|
|
|
71
|
return $message; |
|
2592
|
|
|
|
|
|
|
} |
|
2593
|
|
|
|
|
|
|
|
|
2594
|
|
|
|
|
|
|
|
|
2595
|
|
|
|
|
|
|
# Generate a list of quoted strings from the specified values. |
|
2596
|
|
|
|
|
|
|
|
|
2597
|
|
|
|
|
|
|
sub name_list { |
|
2598
|
|
|
|
|
|
|
|
|
2599
|
42
|
|
|
42
|
0
|
54
|
my @names = @_; |
|
2600
|
|
|
|
|
|
|
|
|
2601
|
42
|
50
|
|
|
|
66
|
return unless @names; |
|
2602
|
42
|
|
|
|
|
98
|
return "'" . join("', '", @names) . "'"; |
|
2603
|
|
|
|
|
|
|
}; |
|
2604
|
|
|
|
|
|
|
|
|
2605
|
|
|
|
|
|
|
|
|
2606
|
|
|
|
|
|
|
package HTTP::Validate::Result; |
|
2607
|
|
|
|
|
|
|
|
|
2608
|
|
|
|
|
|
|
=head1 OTHER METHODS |
|
2609
|
|
|
|
|
|
|
|
|
2610
|
|
|
|
|
|
|
The result object returned by L provides the following |
|
2611
|
|
|
|
|
|
|
methods: |
|
2612
|
|
|
|
|
|
|
|
|
2613
|
|
|
|
|
|
|
=head3 passed |
|
2614
|
|
|
|
|
|
|
|
|
2615
|
|
|
|
|
|
|
Returns true if the validation passed, false otherwise. |
|
2616
|
|
|
|
|
|
|
|
|
2617
|
|
|
|
|
|
|
=cut |
|
2618
|
|
|
|
|
|
|
|
|
2619
|
|
|
|
|
|
|
sub passed { |
|
2620
|
|
|
|
|
|
|
|
|
2621
|
7
|
|
|
7
|
|
266
|
my ($self) = @_; |
|
2622
|
|
|
|
|
|
|
|
|
2623
|
|
|
|
|
|
|
# If any errors occurred, then the validation failed. |
|
2624
|
|
|
|
|
|
|
|
|
2625
|
7
|
100
|
66
|
|
|
24
|
return if ref $self->{er} eq 'ARRAY' && @{$self->{er}}; |
|
|
2
|
|
|
|
|
11
|
|
|
2626
|
|
|
|
|
|
|
|
|
2627
|
|
|
|
|
|
|
# Otherwise, it passed. |
|
2628
|
|
|
|
|
|
|
|
|
2629
|
5
|
|
|
|
|
14
|
return 1; |
|
2630
|
|
|
|
|
|
|
} |
|
2631
|
|
|
|
|
|
|
|
|
2632
|
|
|
|
|
|
|
|
|
2633
|
|
|
|
|
|
|
=head3 errors |
|
2634
|
|
|
|
|
|
|
|
|
2635
|
|
|
|
|
|
|
In a scalar context, this returns the number of errors generated by this |
|
2636
|
|
|
|
|
|
|
validation. In a list context, it returns a list of error messages. If an |
|
2637
|
|
|
|
|
|
|
argument is given, only messages whose key equals the argument are returned. |
|
2638
|
|
|
|
|
|
|
|
|
2639
|
|
|
|
|
|
|
=cut |
|
2640
|
|
|
|
|
|
|
|
|
2641
|
|
|
|
|
|
|
sub errors { |
|
2642
|
|
|
|
|
|
|
|
|
2643
|
50
|
|
|
50
|
|
990
|
my ($self, $key) = @_; |
|
2644
|
|
|
|
|
|
|
|
|
2645
|
|
|
|
|
|
|
# In scalar context, just return the count. |
|
2646
|
|
|
|
|
|
|
|
|
2647
|
50
|
100
|
|
|
|
112
|
if ( ! wantarray ) |
|
|
|
100
|
|
|
|
|
|
|
2648
|
|
|
|
|
|
|
{ |
|
2649
|
20
|
100
|
|
|
|
82
|
return 0 unless defined $key ? ref $self->{ec} : ref $self->{er}; |
|
|
|
100
|
|
|
|
|
|
|
2650
|
8
|
100
|
50
|
|
|
21
|
return defined $key ? ($self->{ec}{$key} || 0) : scalar @{$self->{er}}; |
|
|
5
|
|
|
|
|
15
|
|
|
2651
|
|
|
|
|
|
|
} |
|
2652
|
|
|
|
|
|
|
|
|
2653
|
|
|
|
|
|
|
# In list context, if a key is given then return just the matching error |
|
2654
|
|
|
|
|
|
|
# messages or an empty list if there are none. |
|
2655
|
|
|
|
|
|
|
|
|
2656
|
|
|
|
|
|
|
elsif ( defined $key ) |
|
2657
|
|
|
|
|
|
|
{ |
|
2658
|
4
|
100
|
|
|
|
11
|
return unless ref $self->{ec}; |
|
2659
|
3
|
|
|
|
|
4
|
return map { $_->[1] } grep { $_->[0] eq $key } @{$self->{er}}; |
|
|
3
|
|
|
|
|
6
|
|
|
|
3
|
|
|
|
|
8
|
|
|
|
3
|
|
|
|
|
6
|
|
|
2660
|
|
|
|
|
|
|
} |
|
2661
|
|
|
|
|
|
|
|
|
2662
|
|
|
|
|
|
|
# If no key is given, just return all of the messages. |
|
2663
|
|
|
|
|
|
|
|
|
2664
|
|
|
|
|
|
|
else |
|
2665
|
|
|
|
|
|
|
{ |
|
2666
|
26
|
|
|
|
|
16
|
return map { $_->[1] } @{$self->{er}}; |
|
|
17
|
|
|
|
|
52
|
|
|
|
26
|
|
|
|
|
56
|
|
|
2667
|
|
|
|
|
|
|
} |
|
2668
|
|
|
|
|
|
|
} |
|
2669
|
|
|
|
|
|
|
|
|
2670
|
|
|
|
|
|
|
=head3 error_keys |
|
2671
|
|
|
|
|
|
|
|
|
2672
|
|
|
|
|
|
|
Returns the list of keys for which error messages were generated. |
|
2673
|
|
|
|
|
|
|
|
|
2674
|
|
|
|
|
|
|
=cut |
|
2675
|
|
|
|
|
|
|
|
|
2676
|
|
|
|
|
|
|
sub error_keys { |
|
2677
|
|
|
|
|
|
|
|
|
2678
|
6
|
|
|
6
|
|
573
|
my ($self) = @_; |
|
2679
|
6
|
|
|
|
|
5
|
return keys %{$self->{ec}}; |
|
|
6
|
|
|
|
|
62
|
|
|
2680
|
|
|
|
|
|
|
} |
|
2681
|
|
|
|
|
|
|
|
|
2682
|
|
|
|
|
|
|
|
|
2683
|
|
|
|
|
|
|
=head3 warnings |
|
2684
|
|
|
|
|
|
|
|
|
2685
|
|
|
|
|
|
|
In a scalar context, this returns the number of warnings generated by the |
|
2686
|
|
|
|
|
|
|
validation. In a list context, it returns a list of warning messages. If an |
|
2687
|
|
|
|
|
|
|
argument is given, only messages whose key equals the argument are returned. |
|
2688
|
|
|
|
|
|
|
|
|
2689
|
|
|
|
|
|
|
=cut |
|
2690
|
|
|
|
|
|
|
|
|
2691
|
|
|
|
|
|
|
sub warnings { |
|
2692
|
|
|
|
|
|
|
|
|
2693
|
29
|
|
|
29
|
|
1925
|
my ($self, $key) = @_; |
|
2694
|
|
|
|
|
|
|
|
|
2695
|
|
|
|
|
|
|
# In scalar context, just return the count. |
|
2696
|
|
|
|
|
|
|
|
|
2697
|
29
|
100
|
|
|
|
60
|
if ( ! wantarray ) |
|
|
|
100
|
|
|
|
|
|
|
2698
|
|
|
|
|
|
|
{ |
|
2699
|
18
|
100
|
|
|
|
74
|
return 0 unless defined $key ? ref $self->{wc} : ref $self->{wn}; |
|
|
|
100
|
|
|
|
|
|
|
2700
|
6
|
100
|
50
|
|
|
16
|
return defined $key ? ($self->{wc}{$key} || 0) : scalar @{$self->{wn}}; |
|
|
4
|
|
|
|
|
15
|
|
|
2701
|
|
|
|
|
|
|
} |
|
2702
|
|
|
|
|
|
|
|
|
2703
|
|
|
|
|
|
|
# In list context, if a key is given then return just the matching warning |
|
2704
|
|
|
|
|
|
|
# messages or an empty list if there are none. |
|
2705
|
|
|
|
|
|
|
|
|
2706
|
|
|
|
|
|
|
elsif ( defined $key ) |
|
2707
|
|
|
|
|
|
|
{ |
|
2708
|
2
|
50
|
|
|
|
5
|
return unless ref $self->{wn}; |
|
2709
|
2
|
|
|
|
|
2
|
return map { $_->[1] } grep { $_->[0] eq $key } @{$self->{wn}}; |
|
|
2
|
|
|
|
|
6
|
|
|
|
2
|
|
|
|
|
6
|
|
|
|
2
|
|
|
|
|
4
|
|
|
2710
|
|
|
|
|
|
|
} |
|
2711
|
|
|
|
|
|
|
|
|
2712
|
|
|
|
|
|
|
# If no key is given, just return all of the messages. |
|
2713
|
|
|
|
|
|
|
|
|
2714
|
|
|
|
|
|
|
else |
|
2715
|
|
|
|
|
|
|
{ |
|
2716
|
9
|
|
|
|
|
7
|
return map { $_->[1] } @{$self->{wn}}; |
|
|
6
|
|
|
|
|
22
|
|
|
|
9
|
|
|
|
|
16
|
|
|
2717
|
|
|
|
|
|
|
} |
|
2718
|
|
|
|
|
|
|
} |
|
2719
|
|
|
|
|
|
|
|
|
2720
|
|
|
|
|
|
|
|
|
2721
|
|
|
|
|
|
|
=head3 warning_keys |
|
2722
|
|
|
|
|
|
|
|
|
2723
|
|
|
|
|
|
|
Returns the list of keys for which warning messages were generated. |
|
2724
|
|
|
|
|
|
|
|
|
2725
|
|
|
|
|
|
|
=cut |
|
2726
|
|
|
|
|
|
|
|
|
2727
|
|
|
|
|
|
|
sub warning_keys { |
|
2728
|
|
|
|
|
|
|
|
|
2729
|
1
|
|
|
1
|
|
2
|
my ($self) = @_; |
|
2730
|
1
|
|
|
|
|
1
|
return keys %{$self->{wc}}; |
|
|
1
|
|
|
|
|
11
|
|
|
2731
|
|
|
|
|
|
|
} |
|
2732
|
|
|
|
|
|
|
|
|
2733
|
|
|
|
|
|
|
|
|
2734
|
|
|
|
|
|
|
=head3 keys |
|
2735
|
|
|
|
|
|
|
|
|
2736
|
|
|
|
|
|
|
In a scalar context, this returns the number of parameters that had valid values. In a list |
|
2737
|
|
|
|
|
|
|
context, it returns a list of parameter names in the order they were recognized. Individual |
|
2738
|
|
|
|
|
|
|
parameter values can be gotten by using either L or L. |
|
2739
|
|
|
|
|
|
|
|
|
2740
|
|
|
|
|
|
|
=cut |
|
2741
|
|
|
|
|
|
|
|
|
2742
|
|
|
|
|
|
|
sub keys { |
|
2743
|
|
|
|
|
|
|
|
|
2744
|
5
|
|
|
5
|
|
9
|
my ($self) = @_; |
|
2745
|
|
|
|
|
|
|
|
|
2746
|
|
|
|
|
|
|
# Return the list of parameter keys in the order they were recognized. |
|
2747
|
|
|
|
|
|
|
|
|
2748
|
5
|
|
|
|
|
4
|
return @{$self->{clean_list}}; |
|
|
5
|
|
|
|
|
15
|
|
|
2749
|
|
|
|
|
|
|
} |
|
2750
|
|
|
|
|
|
|
|
|
2751
|
|
|
|
|
|
|
|
|
2752
|
|
|
|
|
|
|
=head3 values |
|
2753
|
|
|
|
|
|
|
|
|
2754
|
|
|
|
|
|
|
Returns the hash of clean parameter values. This is not a copy, so any |
|
2755
|
|
|
|
|
|
|
modifications you make to it will be reflected in subsequent calls to L. |
|
2756
|
|
|
|
|
|
|
|
|
2757
|
|
|
|
|
|
|
=cut |
|
2758
|
|
|
|
|
|
|
|
|
2759
|
|
|
|
|
|
|
sub values { |
|
2760
|
|
|
|
|
|
|
|
|
2761
|
2
|
|
|
2
|
|
4
|
my ($self) = @_; |
|
2762
|
|
|
|
|
|
|
|
|
2763
|
|
|
|
|
|
|
# Return the clean value hash. |
|
2764
|
|
|
|
|
|
|
|
|
2765
|
2
|
|
|
|
|
3
|
return $self->{clean}; |
|
2766
|
|
|
|
|
|
|
} |
|
2767
|
|
|
|
|
|
|
|
|
2768
|
|
|
|
|
|
|
=head3 value |
|
2769
|
|
|
|
|
|
|
|
|
2770
|
|
|
|
|
|
|
Returns the value of the specified parameter, or undef if that parameter was |
|
2771
|
|
|
|
|
|
|
not specified in the request or if its value was invalid. |
|
2772
|
|
|
|
|
|
|
|
|
2773
|
|
|
|
|
|
|
=cut |
|
2774
|
|
|
|
|
|
|
|
|
2775
|
|
|
|
|
|
|
sub value { |
|
2776
|
|
|
|
|
|
|
|
|
2777
|
54
|
|
|
54
|
|
3933
|
my ($self, $param) = @_; |
|
2778
|
|
|
|
|
|
|
|
|
2779
|
54
|
|
|
|
|
174
|
return $self->{clean}{$param}; |
|
2780
|
|
|
|
|
|
|
} |
|
2781
|
|
|
|
|
|
|
|
|
2782
|
|
|
|
|
|
|
|
|
2783
|
|
|
|
|
|
|
=head3 specified |
|
2784
|
|
|
|
|
|
|
|
|
2785
|
|
|
|
|
|
|
Returns true if the specified parameter was specified in the request with at least |
|
2786
|
|
|
|
|
|
|
one value, whether or not that value was valid. Returns false otherwise. |
|
2787
|
|
|
|
|
|
|
|
|
2788
|
|
|
|
|
|
|
=cut |
|
2789
|
|
|
|
|
|
|
|
|
2790
|
|
|
|
|
|
|
sub specified { |
|
2791
|
|
|
|
|
|
|
|
|
2792
|
5
|
|
|
5
|
|
319
|
my ($self, $param) = @_; |
|
2793
|
|
|
|
|
|
|
|
|
2794
|
5
|
|
|
|
|
16
|
return exists $self->{clean}{$param}; |
|
2795
|
|
|
|
|
|
|
} |
|
2796
|
|
|
|
|
|
|
|
|
2797
|
|
|
|
|
|
|
|
|
2798
|
|
|
|
|
|
|
=head3 raw |
|
2799
|
|
|
|
|
|
|
|
|
2800
|
|
|
|
|
|
|
Returns a hash of the raw parameter values as originally provided to |
|
2801
|
|
|
|
|
|
|
L. Multiple values are represented by array refs. The |
|
2802
|
|
|
|
|
|
|
result of this method can be used, for example, to redisplay a web form if the |
|
2803
|
|
|
|
|
|
|
submission resulted in errors. |
|
2804
|
|
|
|
|
|
|
|
|
2805
|
|
|
|
|
|
|
=cut |
|
2806
|
|
|
|
|
|
|
|
|
2807
|
|
|
|
|
|
|
sub raw { |
|
2808
|
|
|
|
|
|
|
|
|
2809
|
1
|
|
|
1
|
|
3
|
my ($self, $param) = @_; |
|
2810
|
|
|
|
|
|
|
|
|
2811
|
1
|
|
|
|
|
2
|
return $self->{raw}; |
|
2812
|
|
|
|
|
|
|
} |
|
2813
|
|
|
|
|
|
|
|
|
2814
|
|
|
|
|
|
|
|
|
2815
|
|
|
|
|
|
|
=head3 content_type |
|
2816
|
|
|
|
|
|
|
|
|
2817
|
|
|
|
|
|
|
This returns the content type specified by the request parameters. If none |
|
2818
|
|
|
|
|
|
|
was specified, or if no content_type rule was included in the validation, it |
|
2819
|
|
|
|
|
|
|
returns undef. |
|
2820
|
|
|
|
|
|
|
|
|
2821
|
|
|
|
|
|
|
=cut |
|
2822
|
|
|
|
|
|
|
|
|
2823
|
|
|
|
|
|
|
sub content_type { |
|
2824
|
|
|
|
|
|
|
|
|
2825
|
3
|
|
|
3
|
|
251
|
my ($self) = @_; |
|
2826
|
|
|
|
|
|
|
|
|
2827
|
3
|
|
|
|
|
10
|
return $self->{content_type}; |
|
2828
|
|
|
|
|
|
|
} |
|
2829
|
|
|
|
|
|
|
|
|
2830
|
|
|
|
|
|
|
|
|
2831
|
|
|
|
|
|
|
package HTTP::Validate; |
|
2832
|
|
|
|
|
|
|
|
|
2833
|
|
|
|
|
|
|
# At the very end, we have the validator functions |
|
2834
|
|
|
|
|
|
|
# ================================================ |
|
2835
|
|
|
|
|
|
|
|
|
2836
|
|
|
|
|
|
|
=head1 VALIDATORS |
|
2837
|
|
|
|
|
|
|
|
|
2838
|
|
|
|
|
|
|
Parameter rules can each include one or more validator functions under the key |
|
2839
|
|
|
|
|
|
|
C. The job of these functions is two-fold: first to check for good |
|
2840
|
|
|
|
|
|
|
parameter values, and second to generate cleaned values. |
|
2841
|
|
|
|
|
|
|
|
|
2842
|
|
|
|
|
|
|
There are a number of validators provided by this module, or you can specify a |
|
2843
|
|
|
|
|
|
|
reference to a function of your own. |
|
2844
|
|
|
|
|
|
|
|
|
2845
|
|
|
|
|
|
|
=head2 Predefined validators |
|
2846
|
|
|
|
|
|
|
|
|
2847
|
|
|
|
|
|
|
=head3 INT_VALUE |
|
2848
|
|
|
|
|
|
|
|
|
2849
|
|
|
|
|
|
|
This validator accepts any integer, and rejects all other values. It |
|
2850
|
|
|
|
|
|
|
returns a numeric value, generated by adding 0 to the raw parameter value. |
|
2851
|
|
|
|
|
|
|
|
|
2852
|
|
|
|
|
|
|
=head3 INT_VALUE(min,max) |
|
2853
|
|
|
|
|
|
|
|
|
2854
|
|
|
|
|
|
|
This validator accepts any integer between C and C (inclusive). If either C |
|
2855
|
|
|
|
|
|
|
or C is undefined, that bound will not be tested. |
|
2856
|
|
|
|
|
|
|
|
|
2857
|
|
|
|
|
|
|
=head3 POS_VALUE |
|
2858
|
|
|
|
|
|
|
|
|
2859
|
|
|
|
|
|
|
This is an alias for C. |
|
2860
|
|
|
|
|
|
|
|
|
2861
|
|
|
|
|
|
|
=head3 POS_ZERO_VALUE |
|
2862
|
|
|
|
|
|
|
|
|
2863
|
|
|
|
|
|
|
This is an alias for C. |
|
2864
|
|
|
|
|
|
|
|
|
2865
|
|
|
|
|
|
|
=cut |
|
2866
|
|
|
|
|
|
|
|
|
2867
|
|
|
|
|
|
|
sub int_value { |
|
2868
|
|
|
|
|
|
|
|
|
2869
|
43
|
|
|
43
|
0
|
47
|
my ($value, $context, $min, $max) = @_; |
|
2870
|
|
|
|
|
|
|
|
|
2871
|
43
|
100
|
|
|
|
150
|
unless ( $value =~ /^([+-]?\d+)$/ ) |
|
2872
|
|
|
|
|
|
|
{ |
|
2873
|
9
|
|
|
|
|
33
|
return { error => "bad value '$value' for {param}: must be an integer" }; |
|
2874
|
|
|
|
|
|
|
} |
|
2875
|
|
|
|
|
|
|
|
|
2876
|
34
|
100
|
100
|
|
|
114
|
if ( defined $min and $value < $min ) |
|
2877
|
|
|
|
|
|
|
{ |
|
2878
|
7
|
50
|
|
|
|
22
|
my $criterion = defined $max ? "between $min and $max" |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
2879
|
|
|
|
|
|
|
: $min == 0 ? "nonnegative" |
|
2880
|
|
|
|
|
|
|
: $min == 1 ? "positive" |
|
2881
|
|
|
|
|
|
|
: "at least $min"; |
|
2882
|
|
|
|
|
|
|
|
|
2883
|
7
|
|
|
|
|
22
|
return { error => "bad value '$value' for {param}: must be $criterion" }; |
|
2884
|
|
|
|
|
|
|
} |
|
2885
|
|
|
|
|
|
|
|
|
2886
|
27
|
100
|
100
|
|
|
45
|
if ( defined $max and $value > $max ) |
|
2887
|
|
|
|
|
|
|
{ |
|
2888
|
1
|
50
|
|
|
|
4
|
my $criterion = defined $min ? "between $min and $max" : "at most $max"; |
|
2889
|
|
|
|
|
|
|
|
|
2890
|
1
|
|
|
|
|
3
|
return { error => "bad value '$value' for {param} must be $criterion" }; |
|
2891
|
|
|
|
|
|
|
} |
|
2892
|
|
|
|
|
|
|
|
|
2893
|
26
|
|
|
|
|
56
|
return { value => $value + 0 }; |
|
2894
|
|
|
|
|
|
|
} |
|
2895
|
|
|
|
|
|
|
|
|
2896
|
|
|
|
|
|
|
sub INT_VALUE { |
|
2897
|
|
|
|
|
|
|
|
|
2898
|
15
|
|
|
15
|
1
|
1816
|
my ($min, $max) = @_; |
|
2899
|
|
|
|
|
|
|
|
|
2900
|
15
|
100
|
100
|
|
|
130
|
croak "lower bound must be an integer (was '$min')" unless !defined $min || $min =~ /^[+-]?\d+$/; |
|
2901
|
14
|
50
|
66
|
|
|
39
|
croak "upper bound must be an integer (was '$max')" unless !defined $max || $max =~ /^[+-]?\d+$/; |
|
2902
|
|
|
|
|
|
|
|
|
2903
|
14
|
100
|
66
|
|
|
71
|
return \&int_value unless defined $min or defined $max; |
|
2904
|
6
|
|
|
5
|
|
26
|
return sub { return int_value(shift, shift, $min, $max) }; |
|
|
5
|
|
|
|
|
8
|
|
|
2905
|
|
|
|
|
|
|
}; |
|
2906
|
|
|
|
|
|
|
|
|
2907
|
|
|
|
|
|
|
sub POS_VALUE { |
|
2908
|
|
|
|
|
|
|
|
|
2909
|
17
|
|
|
17
|
1
|
2459
|
return sub { return int_value(shift, shift, 1) }; |
|
|
29
|
|
|
29
|
|
40
|
|
|
2910
|
|
|
|
|
|
|
}; |
|
2911
|
|
|
|
|
|
|
|
|
2912
|
|
|
|
|
|
|
sub POS_ZERO_VALUE { |
|
2913
|
|
|
|
|
|
|
|
|
2914
|
4
|
|
|
4
|
1
|
14
|
return sub { return int_value(shift, shift, 0) }; |
|
|
3
|
|
|
3
|
|
5
|
|
|
2915
|
|
|
|
|
|
|
}; |
|
2916
|
|
|
|
|
|
|
|
|
2917
|
|
|
|
|
|
|
|
|
2918
|
|
|
|
|
|
|
=head3 DECI_VALUE |
|
2919
|
|
|
|
|
|
|
|
|
2920
|
|
|
|
|
|
|
This validator accepts any decimal number, including exponential notation, and |
|
2921
|
|
|
|
|
|
|
rejects all other values. It returns a numeric value, generated by adding 0 |
|
2922
|
|
|
|
|
|
|
to the parameter value. |
|
2923
|
|
|
|
|
|
|
|
|
2924
|
|
|
|
|
|
|
=head3 DECI_VALUE(min,max) |
|
2925
|
|
|
|
|
|
|
|
|
2926
|
|
|
|
|
|
|
This validator accepts any real number between C and C (inclusive). |
|
2927
|
|
|
|
|
|
|
Specify these bounds in quotes (i.e. as string arguments) if non-zero so that |
|
2928
|
|
|
|
|
|
|
they will appear properly in error messages. If either C or C is |
|
2929
|
|
|
|
|
|
|
undefined, that bound will not be tested. |
|
2930
|
|
|
|
|
|
|
|
|
2931
|
|
|
|
|
|
|
=cut |
|
2932
|
|
|
|
|
|
|
|
|
2933
|
|
|
|
|
|
|
sub deci_value { |
|
2934
|
|
|
|
|
|
|
|
|
2935
|
14
|
|
|
14
|
0
|
14
|
my ($value, $context, $min, $max) = @_; |
|
2936
|
|
|
|
|
|
|
|
|
2937
|
14
|
100
|
|
|
|
68
|
unless ( $value =~ /^[+-]?(?:\d+\.\d*|\d*\.\d+|\d+)(?:[eE][+-]?\d+)?$/ ) |
|
2938
|
|
|
|
|
|
|
{ |
|
2939
|
1
|
|
|
|
|
7
|
return { error => "bad value '$value' for {param}: must be a decimal number" }; |
|
2940
|
|
|
|
|
|
|
} |
|
2941
|
|
|
|
|
|
|
|
|
2942
|
13
|
100
|
66
|
|
|
52
|
if ( defined $min and defined $max and ($value < $min or $value > $max) ) |
|
|
|
|
100
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
2943
|
|
|
|
|
|
|
{ |
|
2944
|
4
|
|
|
|
|
22
|
return { error => "bad value '$value' for {param}: must be between $min and $max" }; |
|
2945
|
|
|
|
|
|
|
} |
|
2946
|
|
|
|
|
|
|
|
|
2947
|
9
|
50
|
66
|
|
|
20
|
if ( defined $min and $value < $min ) |
|
2948
|
|
|
|
|
|
|
{ |
|
2949
|
0
|
|
|
|
|
0
|
return { error => "bad value '$value' for {param}: must be at least $min" }; |
|
2950
|
|
|
|
|
|
|
} |
|
2951
|
|
|
|
|
|
|
|
|
2952
|
9
|
50
|
66
|
|
|
21
|
if ( defined $max and $value > $max ) |
|
2953
|
|
|
|
|
|
|
{ |
|
2954
|
0
|
|
|
|
|
0
|
return { error => "bad value '$value' for {param}: must be at most $max" }; |
|
2955
|
|
|
|
|
|
|
} |
|
2956
|
|
|
|
|
|
|
|
|
2957
|
9
|
|
|
|
|
28
|
return { value => $value + 0 }; |
|
2958
|
|
|
|
|
|
|
} |
|
2959
|
|
|
|
|
|
|
|
|
2960
|
|
|
|
|
|
|
sub DECI_VALUE { |
|
2961
|
|
|
|
|
|
|
|
|
2962
|
15
|
|
|
15
|
1
|
361
|
my ($min, $max) = @_; |
|
2963
|
|
|
|
|
|
|
|
|
2964
|
15
|
100
|
100
|
|
|
109
|
croak "lower bound must be numeric" if defined $min && !looks_like_number($min); |
|
2965
|
14
|
50
|
66
|
|
|
34
|
croak "upper bound must be numeric" if defined $max && !looks_like_number($max); |
|
2966
|
|
|
|
|
|
|
|
|
2967
|
14
|
100
|
66
|
|
|
61
|
return \&deci_value unless defined $min or defined $max; |
|
2968
|
6
|
|
|
8
|
|
19
|
return sub { return deci_value(shift, shift, $min, $max) }; |
|
|
8
|
|
|
|
|
12
|
|
|
2969
|
|
|
|
|
|
|
}; |
|
2970
|
|
|
|
|
|
|
|
|
2971
|
|
|
|
|
|
|
|
|
2972
|
|
|
|
|
|
|
=head3 MATCH_VALUE |
|
2973
|
|
|
|
|
|
|
|
|
2974
|
|
|
|
|
|
|
This validator accepts any string that matches the specified pattern, and |
|
2975
|
|
|
|
|
|
|
rejects any that does not. If you specify the pattern as a string, it will be |
|
2976
|
|
|
|
|
|
|
converted into a regexp and will have ^ prepended and $ appended, and also the |
|
2977
|
|
|
|
|
|
|
modifier "i". If you specify the pattern using C, then it is used unchanged. |
|
2978
|
|
|
|
|
|
|
Any rule that uses this validator should be provided with an error directive, since the |
|
2979
|
|
|
|
|
|
|
default error message is by necessity not very informative. The value is not |
|
2980
|
|
|
|
|
|
|
cleaned in any way. |
|
2981
|
|
|
|
|
|
|
|
|
2982
|
|
|
|
|
|
|
=cut |
|
2983
|
|
|
|
|
|
|
|
|
2984
|
|
|
|
|
|
|
sub match_value { |
|
2985
|
|
|
|
|
|
|
|
|
2986
|
7
|
|
|
7
|
0
|
14
|
my ($value, $context, $pattern) = @_; |
|
2987
|
|
|
|
|
|
|
|
|
2988
|
7
|
100
|
|
|
|
38
|
return if $value =~ $pattern; |
|
2989
|
3
|
|
|
|
|
11
|
return { error => "bad value '$value' for {param}: did not match the proper pattern" }; |
|
2990
|
|
|
|
|
|
|
} |
|
2991
|
|
|
|
|
|
|
|
|
2992
|
|
|
|
|
|
|
sub MATCH_VALUE { |
|
2993
|
|
|
|
|
|
|
|
|
2994
|
10
|
|
|
10
|
1
|
2925
|
my ($pattern) = @_; |
|
2995
|
|
|
|
|
|
|
|
|
2996
|
10
|
100
|
100
|
|
|
190
|
croak "MATCH_VALUE requires a regular expression" unless |
|
|
|
|
66
|
|
|
|
|
|
2997
|
|
|
|
|
|
|
defined $pattern && (!ref $pattern || ref $pattern eq 'Regexp'); |
|
2998
|
|
|
|
|
|
|
|
|
2999
|
8
|
100
|
|
|
|
79
|
my $re = ref $pattern ? $pattern : qr{^$pattern$}oi; |
|
3000
|
|
|
|
|
|
|
|
|
3001
|
8
|
|
|
7
|
|
40
|
return sub { return match_value(shift, shift, $re) }; |
|
|
7
|
|
|
|
|
11
|
|
|
3002
|
|
|
|
|
|
|
}; |
|
3003
|
|
|
|
|
|
|
|
|
3004
|
|
|
|
|
|
|
|
|
3005
|
|
|
|
|
|
|
=head3 ENUM_VALUE(string,...) |
|
3006
|
|
|
|
|
|
|
|
|
3007
|
|
|
|
|
|
|
This validator accepts any of the specified string values, and rejects all |
|
3008
|
|
|
|
|
|
|
others. Comparisons are case insensitive. If the version of Perl is 5.016 or |
|
3009
|
|
|
|
|
|
|
greater, or if the module C is available and has been |
|
3010
|
|
|
|
|
|
|
required, then the C function will be used instead of the usual C when |
|
3011
|
|
|
|
|
|
|
comparing values. The cleaned value will be the matching string value from |
|
3012
|
|
|
|
|
|
|
this call. |
|
3013
|
|
|
|
|
|
|
|
|
3014
|
|
|
|
|
|
|
If any of the strings is '#', then subsequent values will be accepted but not |
|
3015
|
|
|
|
|
|
|
reported in the standard error message as allowable values. This allows for |
|
3016
|
|
|
|
|
|
|
undocumented values to be accepted. |
|
3017
|
|
|
|
|
|
|
|
|
3018
|
|
|
|
|
|
|
=cut |
|
3019
|
|
|
|
|
|
|
|
|
3020
|
|
|
|
|
|
|
sub enum_value { |
|
3021
|
|
|
|
|
|
|
|
|
3022
|
5
|
|
|
5
|
0
|
7
|
my ($value, $context, $accepted, $good_list) = @_; |
|
3023
|
|
|
|
|
|
|
|
|
3024
|
5
|
|
|
|
|
66
|
my $folded = $case_fold->($value); |
|
3025
|
|
|
|
|
|
|
|
|
3026
|
|
|
|
|
|
|
# If the value is found in the $accepted hash, then we're good. Return |
|
3027
|
|
|
|
|
|
|
# the value as originally given, not the case-folded version. |
|
3028
|
|
|
|
|
|
|
|
|
3029
|
5
|
100
|
|
|
|
18
|
return { value => $accepted->{$folded} } if exists $accepted->{$folded}; |
|
3030
|
|
|
|
|
|
|
|
|
3031
|
|
|
|
|
|
|
# Otherwise, then we have an error. |
|
3032
|
|
|
|
|
|
|
|
|
3033
|
1
|
|
|
|
|
4
|
return { error => "bad value '$value' for {param}: must be one of $good_list" }; |
|
3034
|
|
|
|
|
|
|
} |
|
3035
|
|
|
|
|
|
|
|
|
3036
|
|
|
|
|
|
|
sub ENUM_VALUE { |
|
3037
|
|
|
|
|
|
|
|
|
3038
|
5
|
|
|
5
|
1
|
1874
|
my (%accepted, @documented, $undoc); |
|
3039
|
|
|
|
|
|
|
|
|
3040
|
5
|
|
|
|
|
10
|
foreach my $k ( @_ ) |
|
3041
|
|
|
|
|
|
|
{ |
|
3042
|
9
|
50
|
33
|
|
|
41
|
next unless defined $k && $k ne ''; |
|
3043
|
|
|
|
|
|
|
|
|
3044
|
9
|
50
|
|
|
|
16
|
if ( $k eq '#' ) |
|
3045
|
|
|
|
|
|
|
{ |
|
3046
|
0
|
|
|
|
|
0
|
$undoc = 1; |
|
3047
|
0
|
|
|
|
|
0
|
next; |
|
3048
|
|
|
|
|
|
|
} |
|
3049
|
|
|
|
|
|
|
|
|
3050
|
9
|
|
|
|
|
127
|
$accepted{ $case_fold->($k) } = $k; |
|
3051
|
9
|
50
|
|
|
|
25
|
push @documented, $k unless $undoc; |
|
3052
|
|
|
|
|
|
|
} |
|
3053
|
|
|
|
|
|
|
|
|
3054
|
|
|
|
|
|
|
#my @non_empty = grep { defined $_ && $_ ne '' } @_; |
|
3055
|
5
|
100
|
|
|
|
74
|
croak "ENUM_VALUE requires at least one value" unless keys %accepted; |
|
3056
|
|
|
|
|
|
|
|
|
3057
|
|
|
|
|
|
|
# my %accepted = map { $case_fold->($_) => $_ } @non_empty; |
|
3058
|
4
|
|
|
|
|
13
|
my $good_list = "'" . join("', '", @documented) . "'"; |
|
3059
|
|
|
|
|
|
|
|
|
3060
|
4
|
|
|
5
|
|
19
|
return sub { return enum_value(shift, shift, \%accepted, $good_list) }; |
|
|
5
|
|
|
|
|
11
|
|
|
3061
|
|
|
|
|
|
|
}; |
|
3062
|
|
|
|
|
|
|
|
|
3063
|
|
|
|
|
|
|
|
|
3064
|
|
|
|
|
|
|
=head3 BOOLEAN_VALUE |
|
3065
|
|
|
|
|
|
|
|
|
3066
|
|
|
|
|
|
|
This validator is used for parameters that take a true/false value. It |
|
3067
|
|
|
|
|
|
|
accepts any of the following values: "yes", "no", "true", "false", "on", |
|
3068
|
|
|
|
|
|
|
"off", "1", "0", compared case insensitively. It returns an error if any |
|
3069
|
|
|
|
|
|
|
other value is specified. The cleaned value will be 1 or 0. |
|
3070
|
|
|
|
|
|
|
|
|
3071
|
|
|
|
|
|
|
=cut |
|
3072
|
|
|
|
|
|
|
|
|
3073
|
|
|
|
|
|
|
sub boolean_value { |
|
3074
|
|
|
|
|
|
|
|
|
3075
|
2
|
|
|
2
|
0
|
2
|
my ($value, $context) = @_; |
|
3076
|
|
|
|
|
|
|
|
|
3077
|
2
|
50
|
|
|
|
6
|
unless ( ref $value ) |
|
3078
|
|
|
|
|
|
|
{ |
|
3079
|
2
|
50
|
|
|
|
7
|
if ( $value =~ /^(?:1|yes|true|on)$/i ) |
|
|
|
0
|
|
|
|
|
|
|
3080
|
|
|
|
|
|
|
{ |
|
3081
|
2
|
|
|
|
|
5
|
return { value => 1 }; |
|
3082
|
|
|
|
|
|
|
} |
|
3083
|
|
|
|
|
|
|
|
|
3084
|
|
|
|
|
|
|
elsif ( $value =~ /^(?:0|no|false|off)$/i ) |
|
3085
|
|
|
|
|
|
|
{ |
|
3086
|
0
|
|
|
|
|
0
|
return { value => 0 }; |
|
3087
|
|
|
|
|
|
|
} |
|
3088
|
|
|
|
|
|
|
} |
|
3089
|
|
|
|
|
|
|
|
|
3090
|
0
|
|
|
|
|
0
|
return { error => "the value of {param} must be one of: yes, no, true, false, on, off, 1, 0" }; |
|
3091
|
|
|
|
|
|
|
} |
|
3092
|
|
|
|
|
|
|
|
|
3093
|
1
|
|
|
1
|
1
|
4
|
sub BOOLEAN_VALUE { return \&boolean_value; }; |
|
3094
|
|
|
|
|
|
|
|
|
3095
|
|
|
|
|
|
|
|
|
3096
|
|
|
|
|
|
|
=head3 FLAG_VALUE |
|
3097
|
|
|
|
|
|
|
|
|
3098
|
|
|
|
|
|
|
This validator should be used for parameters that are considered to be "true" |
|
3099
|
|
|
|
|
|
|
if present with an empty value. The validator returns a value of 1 in this case, |
|
3100
|
|
|
|
|
|
|
and behaves like 'BOOLEAN_VALUE' otherwise. |
|
3101
|
|
|
|
|
|
|
|
|
3102
|
|
|
|
|
|
|
=cut |
|
3103
|
|
|
|
|
|
|
|
|
3104
|
2
|
|
|
2
|
1
|
10
|
sub FLAG_VALUE { return 'FLAG_VALUE'; }; |
|
3105
|
|
|
|
|
|
|
|
|
3106
|
|
|
|
|
|
|
|
|
3107
|
|
|
|
|
|
|
# =head3 EMPTY_VALUE |
|
3108
|
|
|
|
|
|
|
|
|
3109
|
|
|
|
|
|
|
# This validator accepts only the empty value. You can use this when you want a |
|
3110
|
|
|
|
|
|
|
# ruleset to be fulfilled even if the specified parameter is given an empty |
|
3111
|
|
|
|
|
|
|
# value. This will typically be used along with at least one other validator for the |
|
3112
|
|
|
|
|
|
|
# same parameter. For example: |
|
3113
|
|
|
|
|
|
|
|
|
3114
|
|
|
|
|
|
|
# define_ruleset foo => |
|
3115
|
|
|
|
|
|
|
# { param => 'bar', valid => [EMPTY_VALUE, POS_VALUE] }; |
|
3116
|
|
|
|
|
|
|
|
|
3117
|
|
|
|
|
|
|
# This rule would be satisfied if the parameter 'bar' is given either an empty |
|
3118
|
|
|
|
|
|
|
# value or a value that is a positive integer. The ruleset will be fulfilled in |
|
3119
|
|
|
|
|
|
|
# either case, but will not be fulfilled if 'bar' is not mentioned at all. For |
|
3120
|
|
|
|
|
|
|
# best results EMPTY_VALUE should not be the last validator in the list, because |
|
3121
|
|
|
|
|
|
|
# if a value fails all of the validators then the last error message is reported |
|
3122
|
|
|
|
|
|
|
# and its error message is by necessity not very helpful. |
|
3123
|
|
|
|
|
|
|
|
|
3124
|
|
|
|
|
|
|
# =cut |
|
3125
|
|
|
|
|
|
|
|
|
3126
|
|
|
|
|
|
|
# sub empty_value { |
|
3127
|
|
|
|
|
|
|
|
|
3128
|
|
|
|
|
|
|
# my ($value, $context) = @_; |
|
3129
|
|
|
|
|
|
|
|
|
3130
|
|
|
|
|
|
|
# return if !defined $value || $value eq ''; |
|
3131
|
|
|
|
|
|
|
# return { error => "parameter {param} must be empty unless it is given a valid value" }; |
|
3132
|
|
|
|
|
|
|
# } |
|
3133
|
|
|
|
|
|
|
|
|
3134
|
|
|
|
|
|
|
# sub EMPTY_VALUE { |
|
3135
|
|
|
|
|
|
|
|
|
3136
|
|
|
|
|
|
|
# return 'EMPTY_VALUE'; |
|
3137
|
|
|
|
|
|
|
# }; |
|
3138
|
|
|
|
|
|
|
|
|
3139
|
|
|
|
|
|
|
|
|
3140
|
|
|
|
|
|
|
=head3 ANY_VALUE |
|
3141
|
|
|
|
|
|
|
|
|
3142
|
|
|
|
|
|
|
This validator accepts any non-empty value. Using this validator |
|
3143
|
|
|
|
|
|
|
is equivalent to not specifying any validator at all. |
|
3144
|
|
|
|
|
|
|
|
|
3145
|
|
|
|
|
|
|
=cut |
|
3146
|
|
|
|
|
|
|
|
|
3147
|
|
|
|
|
|
|
sub ANY_VALUE { |
|
3148
|
|
|
|
|
|
|
|
|
3149
|
4
|
|
|
4
|
1
|
13
|
return 'ANY_VALUE'; |
|
3150
|
|
|
|
|
|
|
}; |
|
3151
|
|
|
|
|
|
|
|
|
3152
|
|
|
|
|
|
|
|
|
3153
|
|
|
|
|
|
|
=head2 Reusing validators |
|
3154
|
|
|
|
|
|
|
|
|
3155
|
|
|
|
|
|
|
Every time you use a parametrized validator such as C, a new |
|
3156
|
|
|
|
|
|
|
closure is generated. If you are repeating a particular set of parameters |
|
3157
|
|
|
|
|
|
|
many times, to save space you may want to instantiate the validator just once: |
|
3158
|
|
|
|
|
|
|
|
|
3159
|
|
|
|
|
|
|
my $zero_to_ten = INT_VALUE(0,10); |
|
3160
|
|
|
|
|
|
|
|
|
3161
|
|
|
|
|
|
|
define_ruleset( 'foo' => |
|
3162
|
|
|
|
|
|
|
{ param => 'bar', valid => $zero_to_ten }, |
|
3163
|
|
|
|
|
|
|
{ param => 'baz', valid => $zero_to_ten }); |
|
3164
|
|
|
|
|
|
|
|
|
3165
|
|
|
|
|
|
|
=head2 Writing your own validator functions |
|
3166
|
|
|
|
|
|
|
|
|
3167
|
|
|
|
|
|
|
If you wish to validate parameters which do not match any of the validators |
|
3168
|
|
|
|
|
|
|
described above, you can write your own validator function. Validator |
|
3169
|
|
|
|
|
|
|
functions are called with two arguments: |
|
3170
|
|
|
|
|
|
|
|
|
3171
|
|
|
|
|
|
|
($value, $context) |
|
3172
|
|
|
|
|
|
|
|
|
3173
|
|
|
|
|
|
|
Where $value is the raw parameter value and $context is a hash ref provided |
|
3174
|
|
|
|
|
|
|
when the validation process is initiated (or an empty hashref if none is |
|
3175
|
|
|
|
|
|
|
provided). This allows the passing of information such as database handles to |
|
3176
|
|
|
|
|
|
|
the validator functions. |
|
3177
|
|
|
|
|
|
|
|
|
3178
|
|
|
|
|
|
|
If your function decides that the parameter value is valid and does not need |
|
3179
|
|
|
|
|
|
|
to be cleaned, it can indicate this by returning an empty result. |
|
3180
|
|
|
|
|
|
|
|
|
3181
|
|
|
|
|
|
|
Otherwise, it must return a hash reference with one or more of the following |
|
3182
|
|
|
|
|
|
|
keys: |
|
3183
|
|
|
|
|
|
|
|
|
3184
|
|
|
|
|
|
|
=over 4 |
|
3185
|
|
|
|
|
|
|
|
|
3186
|
|
|
|
|
|
|
=item error |
|
3187
|
|
|
|
|
|
|
|
|
3188
|
|
|
|
|
|
|
If the parameter value is not valid, the value of this key should be an error |
|
3189
|
|
|
|
|
|
|
message that states I. This message should |
|
3190
|
|
|
|
|
|
|
contain the placeholder {param}, which will be substituted with the parameter |
|
3191
|
|
|
|
|
|
|
name. Use this placeholder, and do not hard-code the parameter name. |
|
3192
|
|
|
|
|
|
|
|
|
3193
|
|
|
|
|
|
|
Here is an example of a good message: |
|
3194
|
|
|
|
|
|
|
|
|
3195
|
|
|
|
|
|
|
"the value of {param} must be a positive integer (was {value})". |
|
3196
|
|
|
|
|
|
|
|
|
3197
|
|
|
|
|
|
|
Here is an example of a bad message: |
|
3198
|
|
|
|
|
|
|
|
|
3199
|
|
|
|
|
|
|
"bad value for 'foo'". |
|
3200
|
|
|
|
|
|
|
|
|
3201
|
|
|
|
|
|
|
=item warn |
|
3202
|
|
|
|
|
|
|
|
|
3203
|
|
|
|
|
|
|
If the parameter value is acceptable but questionable in some way, the value |
|
3204
|
|
|
|
|
|
|
of this key should be a message that states what a good value should look |
|
3205
|
|
|
|
|
|
|
like. All such messages will be made available through the result object that |
|
3206
|
|
|
|
|
|
|
is returned by the validation routine. The code that handles the request may |
|
3207
|
|
|
|
|
|
|
then choose to display these messages as part of the response. Your code may |
|
3208
|
|
|
|
|
|
|
also make use of this information during the process of responding to the |
|
3209
|
|
|
|
|
|
|
request. |
|
3210
|
|
|
|
|
|
|
|
|
3211
|
|
|
|
|
|
|
=item value |
|
3212
|
|
|
|
|
|
|
|
|
3213
|
|
|
|
|
|
|
If the parameter value represents anything other than a simple string (i.e. a |
|
3214
|
|
|
|
|
|
|
number, list, or more complicated data structure), then the value of this key |
|
3215
|
|
|
|
|
|
|
should be the converted or "cleaned" form of the parameter value. For |
|
3216
|
|
|
|
|
|
|
example, a numeric parameter might be converted into an actual number by |
|
3217
|
|
|
|
|
|
|
adding zero to it, or a pair of values might be split apart and converted into |
|
3218
|
|
|
|
|
|
|
an array ref. The value of this key will be returned as the "cleaned" value |
|
3219
|
|
|
|
|
|
|
of the parameter, in place of the raw parameter value provided in the request. |
|
3220
|
|
|
|
|
|
|
|
|
3221
|
|
|
|
|
|
|
=back |
|
3222
|
|
|
|
|
|
|
|
|
3223
|
|
|
|
|
|
|
=head3 Parametrized validators |
|
3224
|
|
|
|
|
|
|
|
|
3225
|
|
|
|
|
|
|
If you want to write your own parametrized validator, write a function that |
|
3226
|
|
|
|
|
|
|
generates and returns a closure. For example: |
|
3227
|
|
|
|
|
|
|
|
|
3228
|
|
|
|
|
|
|
sub integer_multiple { |
|
3229
|
|
|
|
|
|
|
|
|
3230
|
|
|
|
|
|
|
my ($value, $context, $base) = @_; |
|
3231
|
|
|
|
|
|
|
|
|
3232
|
|
|
|
|
|
|
return { value => $value + 0 } if $value % $base == 0; |
|
3233
|
|
|
|
|
|
|
return { error => "the value of {param} must be a multiple of $base (was {value})" }; |
|
3234
|
|
|
|
|
|
|
} |
|
3235
|
|
|
|
|
|
|
|
|
3236
|
|
|
|
|
|
|
sub INTEGER_MULTIPLE { |
|
3237
|
|
|
|
|
|
|
|
|
3238
|
|
|
|
|
|
|
my ($base) = $_[0] + 0; |
|
3239
|
|
|
|
|
|
|
|
|
3240
|
|
|
|
|
|
|
croak "INTEGER_MULTIPLE requires a numeric parameter greater than zero" |
|
3241
|
|
|
|
|
|
|
unless defined $base and $base > 0; |
|
3242
|
|
|
|
|
|
|
|
|
3243
|
|
|
|
|
|
|
return sub { return integer_multiple(shift, shift, $base) }; |
|
3244
|
|
|
|
|
|
|
} |
|
3245
|
|
|
|
|
|
|
|
|
3246
|
|
|
|
|
|
|
define_ruleset( 'foo' => |
|
3247
|
|
|
|
|
|
|
{ param => foo, valid => INTEGER_MULTIPLE(3) }); |
|
3248
|
|
|
|
|
|
|
|
|
3249
|
|
|
|
|
|
|
=cut |
|
3250
|
|
|
|
|
|
|
|
|
3251
|
|
|
|
|
|
|
|
|
3252
|
|
|
|
|
|
|
|
|
3253
|
|
|
|
|
|
|
=head1 AUTHOR |
|
3254
|
|
|
|
|
|
|
|
|
3255
|
|
|
|
|
|
|
Michael McClennen, C<< >> |
|
3256
|
|
|
|
|
|
|
|
|
3257
|
|
|
|
|
|
|
=head1 SUPPORT |
|
3258
|
|
|
|
|
|
|
|
|
3259
|
|
|
|
|
|
|
Please report any bugs or feature requests to C, or through |
|
3260
|
|
|
|
|
|
|
the web interface at L. I will be notified, and then you'll |
|
3261
|
|
|
|
|
|
|
automatically be notified of progress on your bug as I make changes. |
|
3262
|
|
|
|
|
|
|
|
|
3263
|
|
|
|
|
|
|
=head1 LICENSE AND COPYRIGHT |
|
3264
|
|
|
|
|
|
|
|
|
3265
|
|
|
|
|
|
|
Copyright 2014 Michael McClennen. |
|
3266
|
|
|
|
|
|
|
|
|
3267
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it |
|
3268
|
|
|
|
|
|
|
under the terms of either: the GNU General Public License as published |
|
3269
|
|
|
|
|
|
|
by the Free Software Foundation; or the Artistic License. |
|
3270
|
|
|
|
|
|
|
|
|
3271
|
|
|
|
|
|
|
See http://dev.perl.org/licenses/ for more information. |
|
3272
|
|
|
|
|
|
|
|
|
3273
|
|
|
|
|
|
|
|
|
3274
|
|
|
|
|
|
|
=cut |
|
3275
|
|
|
|
|
|
|
|
|
3276
|
|
|
|
|
|
|
1; # End of HTTP::Validate |