1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 r"""Support for validation of request parameters.
21
22 """
23 __docformat__ = "restructuredtext en"
24
25 import re
26 from wsgisupport import HTTPNotFound
27 from application import ValidationError
28
29 -def validate_param(key, vals, minreps, maxreps, pattern,
30 compiled_pattern, default, doc):
31 """Validate a particular parameter.
32
33 """
34 l = len(vals)
35
36
37 if l == 0 and default is not None:
38 vals = default
39
40
41 if l < minreps:
42 raise ValidationError(u"Too few instances of %r supplied "
43 u"(needed %d, got %d)" %
44 (key, minreps, l))
45 if maxreps is not None and l > maxreps:
46 raise ValidationError(u"Too many instances of %r supplied "
47 u"(maximum %d, got %d)" %
48 (key, maxreps, l))
49
50 if compiled_pattern is not None:
51
52 for val in vals:
53 if not compiled_pattern.match(val):
54 raise ValidationError(u"Invalid parameter value for %r" % key)
55
56 return vals
57
59 """Validate parameters, raising ValidationError for problems.
60
61 `constraints` is a dict of tuples, one for each field. Unknown fields
62 raise an error.
63
64 """
65 p = {}
66
67
68
69 missing_params = set()
70 for key, constraint in constraints.iteritems():
71 if constraint[4] is not None:
72 if key not in requestobj:
73 p[key] = constraint[4]
74 else:
75
76 if constraint[0] > 0 and key not in requestobj:
77 missing_params.add(key)
78
79 if len(missing_params) != 0:
80
81 raise ValidationError(u"Missing required parameters %s" %
82 u', '.join(u"'%s'" % p for p in missing_params))
83
84 for key in requestobj:
85 constraint = constraints.get(key, None)
86 if constraint is None:
87 if re.match('\w+$', key):
88
89 raise ValidationError(u"Unknown parameter %r supplied" % key)
90 else:
91 raise ValidationError(u"Unknown parameter supplied")
92 p[key] = validate_param(key, requestobj[key], *constraint)
93
94 return p
95
97 constraints = props.get('valid_params', None)
98 if constraints != None:
99 request.params = validate_params(request.params, constraints)
100 return request
101
103 if len(request.params) != 0:
104 raise ValidationError(u"This resource does not accept parameters")
105 return request
106
107
109 """Check that the pathinfo satisfies the supplied rules.
110
111 """
112 index = 0
113 for name, pattern, compiled_pattern, default, required in param_rules:
114 if len(request.pathinfo.tail) <= index:
115 if required:
116 raise ValidationError("Required pathinfo component missing")
117
118 request.pathinfo[name] = default
119 index += 1
120 continue
121 param = request.pathinfo.tail[index]
122 index += 1
123
124 if compiled_pattern is not None:
125 if not compiled_pattern.match(param):
126 raise ValidationError("Pathinfo component does not match "
127 "allowed pattern")
128 request.pathinfo[name] = param
129 request.pathinfo.tail = request.pathinfo.tail[index:]
130
132 """Check that the pathinfo tail satisfies the supplied rules.
133
134 """
135 if tail_rules is None:
136 if len(request.pathinfo.tail) > 0:
137 raise ValidationError("Unexpected trailing pathinfo")
138 else:
139 return
140 minreps, maxreps, pattern, compiled_pattern, default, doc = tail_rules
141
142
144 """Check the pathinfo for validity, and populate the pathinfo dictionary.
145
146 """
147 param_rules = props['pathinfo_params_rules']
148 tail_rules = props['pathinfo_tail_rules']
149
150 validate_pathinfo_params(request, param_rules)
151 validate_pathinfo_tail(request, tail_rules)
152
153 return request
154
156 """Pad a list of arguments with None to specified length.
157
158 """
159 return (list(args) + [None] * length)[:length]
160
162 """Parse pathinfo rules.
163
164 """
165
166 param_rules = []
167 previous_required = True
168 for pathinfo_item in pathinfo_items:
169 if len(pathinfo_item) < 1 or len(pathinfo_item) > 3:
170 raise TypeError("pathinfo decorator arguments must be "
171 "sequences of length 1 to 3 items - got %d"
172 " items" % len(pathinfo_item))
173 required = False
174 if len(pathinfo_item) < 3:
175
176 required = True
177 if not previous_required:
178 raise TypeError("required parameter in pathinfo decorator"
179 " following non-required parameter")
180 else:
181 previous_required = False
182 name, pattern, default = _pad_none(pathinfo_item, 3)
183 compiled_pattern = None
184 if pattern is not None:
185 compiled_pattern = re.compile(pattern, re.UNICODE)
186 param_rules.append((name, pattern, compiled_pattern, default, required))
187
188
189 if not tail_rules is None:
190 if len(tail_rules) > 5:
191 raise TypeError("pathinfo tail argument must be "
192 "sequence of length 0 to 5 items - got %d "
193 "items" % len(tail_rules))
194 tail_rules = _pad_none(tail_rules, 5)
195 pattern = tail_rules[2]
196 compiled_pattern = None
197 if pattern is not None:
198 compiled_pattern = re.compile(pattern, re.UNICODE)
199 tail_rules = tail_rules[:2] + [compiled_pattern] + tail_rules[2:]
200
201 return param_rules, tail_rules
202
203
204