15
15
""" This module contains base REST classes for constructing REST servlets. """
16
16
17
17
import logging
18
+ from typing import Iterable , List , Optional , Union
18
19
19
20
from synapse .api .errors import Codes , SynapseError
20
21
from synapse .util import json_decoder
@@ -107,12 +108,11 @@ def parse_boolean_from_args(args, name, default=None, required=False):
107
108
108
109
def parse_string (
109
110
request ,
110
- name ,
111
- default = None ,
112
- required = False ,
113
- allowed_values = None ,
114
- param_type = "string" ,
115
- encoding = "ascii" ,
111
+ name : Union [bytes , str ],
112
+ default : Optional [str ] = None ,
113
+ required : bool = False ,
114
+ allowed_values : Optional [Iterable [str ]] = None ,
115
+ encoding : Optional [str ] = "ascii" ,
116
116
):
117
117
"""
118
118
Parse a string parameter from the request query string.
@@ -131,7 +131,6 @@ def parse_string(
131
131
string, or None if any value is allowed, defaults to None. Must be
132
132
the same type as name, if given.
133
133
encoding (str|None): The encoding to decode the string content with.
134
-
135
134
Returns:
136
135
bytes/unicode|None: A string value or the default. Unicode if encoding
137
136
was given, bytes otherwise.
@@ -142,45 +141,81 @@ def parse_string(
142
141
is not one of those allowed values.
143
142
"""
144
143
return parse_string_from_args (
145
- request .args , name , default , required , allowed_values , param_type , encoding
144
+ request .args , name , default , required , allowed_values , encoding
146
145
)
147
146
148
147
149
- def parse_string_from_args (
150
- args ,
151
- name ,
152
- default = None ,
153
- required = False ,
154
- allowed_values = None ,
155
- param_type = "string" ,
156
- encoding = "ascii" ,
157
- ):
148
+ def _parse_string_value (
149
+ value : Union [str , bytes ],
150
+ allowed_values : Optional [Iterable [str ]],
151
+ name : str ,
152
+ encoding : Optional [str ],
153
+ ) -> str :
154
+ if encoding :
155
+ try :
156
+ value = value .decode (encoding )
157
+ except ValueError :
158
+ raise SynapseError (400 , "Query parameter %r must be %s" % (name , encoding ))
159
+
160
+ if allowed_values is not None and value not in allowed_values :
161
+ message = "Query parameter %r must be one of [%s]" % (
162
+ name ,
163
+ ", " .join (repr (v ) for v in allowed_values ),
164
+ )
165
+ raise SynapseError (400 , message )
166
+ else :
167
+ return value
168
+
169
+
170
+ def parse_strings_from_args (
171
+ args : List [str ],
172
+ name : Union [bytes , str ],
173
+ default : Optional [str ] = None ,
174
+ required : bool = False ,
175
+ allowed_values : Optional [Iterable [str ]] = None ,
176
+ encoding : Optional [str ] = "ascii" ,
177
+ ) -> Optional [List [Union [bytes , str ]]]:
178
+ """
179
+ Parse a string parameter from the request query string list.
180
+
181
+ If encoding is not None, the content of the query param will be
182
+ decoded to Unicode using the encoding, otherwise it will be encoded
183
+
184
+ Args:
185
+ args: the twisted HTTP request.args list.
186
+ name: the name of the query parameter.
187
+ default: value to use if the parameter is absent,
188
+ defaults to None. Must be bytes if encoding is None.
189
+ required : whether to raise a 400 SynapseError if the
190
+ parameter is absent, defaults to False.
191
+ allowed_values (list[bytes|unicode]): List of allowed values for the
192
+ string, or None if any value is allowed, defaults to None. Must be
193
+ the same type as name, if given.
194
+ encoding: The encoding to decode the string content with.
195
+
196
+ Returns:
197
+ A string value or the default. Unicode if encoding
198
+ was given, bytes otherwise.
199
+
200
+ Raises:
201
+ SynapseError if the parameter is absent and required, or if the
202
+ parameter is present, must be one of a list of allowed values and
203
+ is not one of those allowed values.
204
+ """
158
205
159
206
if not isinstance (name , bytes ):
160
207
name = name .encode ("ascii" )
161
208
162
209
if name in args :
163
- value = args [name ][0 ]
164
-
165
- if encoding :
166
- try :
167
- value = value .decode (encoding )
168
- except ValueError :
169
- raise SynapseError (
170
- 400 , "Query parameter %r must be %s" % (name , encoding )
171
- )
172
-
173
- if allowed_values is not None and value not in allowed_values :
174
- message = "Query parameter %r must be one of [%s]" % (
175
- name ,
176
- ", " .join (repr (v ) for v in allowed_values ),
177
- )
178
- raise SynapseError (400 , message )
179
- else :
180
- return value
210
+ values = args [name ]
211
+
212
+ return [
213
+ _parse_string_value (value , allowed_values , name = name , encoding = encoding )
214
+ for value in values
215
+ ]
181
216
else :
182
217
if required :
183
- message = "Missing %s query parameter %r" % (param_type , name )
218
+ message = "Missing string query parameter %r" % (name )
184
219
raise SynapseError (400 , message , errcode = Codes .MISSING_PARAM )
185
220
else :
186
221
@@ -190,6 +225,59 @@ def parse_string_from_args(
190
225
return default
191
226
192
227
228
+ def parse_string_from_args (
229
+ args : List [str ],
230
+ name : Union [bytes , str ],
231
+ default : Optional [str ] = None ,
232
+ required : bool = False ,
233
+ allowed_values : Optional [Iterable [str ]] = None ,
234
+ encoding : Optional [str ] = "ascii" ,
235
+ ) -> Optional [Union [bytes , str ]]:
236
+ """
237
+ Parse the string parameter from the request query string list
238
+ and return the first result.
239
+
240
+ If encoding is not None, the content of the query param will be
241
+ decoded to Unicode using the encoding, otherwise it will be encoded
242
+
243
+ Args:
244
+ args: the twisted HTTP request.args list.
245
+ name: the name of the query parameter.
246
+ default: value to use if the parameter is absent,
247
+ defaults to None. Must be bytes if encoding is None.
248
+ required: whether to raise a 400 SynapseError if the
249
+ parameter is absent, defaults to False.
250
+ allowed_values: List of allowed values for the
251
+ string, or None if any value is allowed, defaults to None. Must be
252
+ the same type as name, if given.
253
+ encoding: The encoding to decode the string content with.
254
+
255
+ Returns:
256
+ A string value or the default. Unicode if encoding
257
+ was given, bytes otherwise.
258
+
259
+ Raises:
260
+ SynapseError if the parameter is absent and required, or if the
261
+ parameter is present, must be one of a list of allowed values and
262
+ is not one of those allowed values.
263
+ """
264
+
265
+ strings = parse_strings_from_args (
266
+ args ,
267
+ name ,
268
+ default = default ,
269
+ required = required ,
270
+ allowed_values = allowed_values ,
271
+ encoding = encoding ,
272
+ )
273
+
274
+ if isinstance (strings , list ):
275
+ return strings [0 ]
276
+
277
+ # Return the default
278
+ return strings
279
+
280
+
193
281
def parse_json_value_from_request (request , allow_empty_body = False ):
194
282
"""Parse a JSON value from the body of a twisted HTTP request.
195
283
@@ -215,7 +303,7 @@ def parse_json_value_from_request(request, allow_empty_body=False):
215
303
try :
216
304
content = json_decoder .decode (content_bytes .decode ("utf-8" ))
217
305
except Exception as e :
218
- logger .warning ("Unable to parse JSON: %s" , e )
306
+ logger .warning ("Unable to parse JSON: %s (%s) " , e , content_bytes )
219
307
raise SynapseError (400 , "Content not JSON." , errcode = Codes .NOT_JSON )
220
308
221
309
return content
0 commit comments