Skip to content
This repository was archived by the owner on Apr 26, 2024. It is now read-only.

Commit 8f10f15

Browse files
committed
Add parse_strings_from_args to get prev_events array
Split out from #9247 Strings: - `parse_string` - `parse_string_from_args` - `parse_strings_from_args` For comparison with ints: - `parse_integer` - `parse_integer_from_args` Previous discussions: - #9247 (comment) - #9247 (comment) - #9247 (comment) Signed-off-by: Eric Eastwood <[email protected]>
1 parent 3e831f2 commit 8f10f15

File tree

2 files changed

+126
-37
lines changed

2 files changed

+126
-37
lines changed

changelog.d/10048.misc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add `parse_strings_from_args` for parsing an array from query parameters.

synapse/http/servlet.py

Lines changed: 125 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
""" This module contains base REST classes for constructing REST servlets. """
1616

1717
import logging
18+
from typing import Iterable, List, Optional, Union
1819

1920
from synapse.api.errors import Codes, SynapseError
2021
from synapse.util import json_decoder
@@ -107,12 +108,11 @@ def parse_boolean_from_args(args, name, default=None, required=False):
107108

108109
def parse_string(
109110
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",
116116
):
117117
"""
118118
Parse a string parameter from the request query string.
@@ -131,7 +131,6 @@ def parse_string(
131131
string, or None if any value is allowed, defaults to None. Must be
132132
the same type as name, if given.
133133
encoding (str|None): The encoding to decode the string content with.
134-
135134
Returns:
136135
bytes/unicode|None: A string value or the default. Unicode if encoding
137136
was given, bytes otherwise.
@@ -142,45 +141,81 @@ def parse_string(
142141
is not one of those allowed values.
143142
"""
144143
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
146145
)
147146

148147

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+
"""
158205

159206
if not isinstance(name, bytes):
160207
name = name.encode("ascii")
161208

162209
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+
]
181216
else:
182217
if required:
183-
message = "Missing %s query parameter %r" % (param_type, name)
218+
message = "Missing string query parameter %r" % (name)
184219
raise SynapseError(400, message, errcode=Codes.MISSING_PARAM)
185220
else:
186221

@@ -190,6 +225,59 @@ def parse_string_from_args(
190225
return default
191226

192227

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+
193281
def parse_json_value_from_request(request, allow_empty_body=False):
194282
"""Parse a JSON value from the body of a twisted HTTP request.
195283
@@ -215,7 +303,7 @@ def parse_json_value_from_request(request, allow_empty_body=False):
215303
try:
216304
content = json_decoder.decode(content_bytes.decode("utf-8"))
217305
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)
219307
raise SynapseError(400, "Content not JSON.", errcode=Codes.NOT_JSON)
220308

221309
return content

0 commit comments

Comments
 (0)