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