Compare commits

...

15 Commits

Author SHA1 Message Date
Stephen Sadowski
92bfeaefd5 tests: fix for typing httptools error import - ignore 2022-02-02 11:37:50 -06:00
Stephen Sadowski
5a650f5758 fix: unused f-string 2022-02-02 11:32:31 -06:00
Stephen Sadowski
850b1f432c
Merge branch 'main' into feat-2394-url_parse 2022-02-02 08:30:09 -06:00
Stephen Sadowski
df8480156d test: update malformed url test 2022-02-01 20:14:57 -06:00
Stephen Sadowski
d0cfb69f43 lint: fixed linting (again) across all files 2022-02-01 19:35:52 -06:00
Stephen Sadowski
19eee8bfb2 fix: replace strtobool inside setup.py; including from sanic.utils is a no-go 2022-02-01 19:35:52 -06:00
Stephen Sadowski
625cffb1b9 fix: linting errors 2022-02-01 19:35:52 -06:00
Stephen Sadowski
c5ac28cbcd test: add strtobool validation test for deprecation replacement 2022-02-01 19:35:52 -06:00
Stephen Sadowski
e57bea28f7 fix: update sanic.utils.str_to_bool to match deprecated strtobool, changed setup.py to use sanic.utils.str_to_bool 2022-02-01 19:35:52 -06:00
Stephen Sadowski
28665e31ce fix: added message when ValueError is raised for strtobool replacement 2022-02-01 19:35:52 -06:00
Stephen Sadowski
9f41936861 fix: removed distutils dependency in setup.py per PEP 632 2022-02-01 19:35:52 -06:00
Stephen Sadowski
7835492b09 fix: E501 line too long. 2022-02-01 19:35:52 -06:00
Stephen Sadowski
ca3bea3425 fix: replace distutils.strtobool() with locally implemented version per PEP 632 2022-02-01 19:35:52 -06:00
Stephen Sadowski
88ca56dda3 test: stubbed malformed url test 2022-02-01 15:45:09 -06:00
Stephen Sadowski
d2ab46d70b feat: better error handling for malformed urls 2022-02-01 15:44:33 -06:00
7 changed files with 89 additions and 31 deletions

View File

@ -6,5 +6,5 @@ data = ""
for i in range(1, 250000): for i in range(1, 250000):
data += str(i) data += str(i)
r = requests.post('http://0.0.0.0:8000/stream', data=data) r = requests.post("http://0.0.0.0:8000/stream", data=data)
print(r.text) print(r.text)

View File

@ -30,6 +30,7 @@ from types import SimpleNamespace
from urllib.parse import parse_qs, parse_qsl, unquote, urlunparse from urllib.parse import parse_qs, parse_qsl, unquote, urlunparse
from httptools import parse_url # type: ignore from httptools import parse_url # type: ignore
from httptools.parser.errors import HttpParserInvalidURLError # type: ignore
from sanic.compat import CancelledErrors, Header from sanic.compat import CancelledErrors, Header
from sanic.constants import DEFAULT_HTTP_CONTENT_TYPE from sanic.constants import DEFAULT_HTTP_CONTENT_TYPE
@ -130,7 +131,12 @@ class Request:
self.raw_url = url_bytes self.raw_url = url_bytes
# TODO: Content-Encoding detection # TODO: Content-Encoding detection
self._parsed_url = parse_url(url_bytes) try:
self._parsed_url = parse_url(url_bytes)
except HttpParserInvalidURLError as InvalidURLError:
raise InvalidUsage(
"URL is invalid or malformed"
) from InvalidURLError
self._id: Optional[Union[uuid.UUID, str, int]] = None self._id: Optional[Union[uuid.UUID, str, int]] = None
self._name: Optional[str] = None self._name: Optional[str] = None
self.app = app self.app = app

View File

@ -1,12 +1,26 @@
import asyncio import asyncio
from distutils.util import strtobool
from os import getenv from os import getenv
from sanic.compat import OS_IS_WINDOWS from sanic.compat import OS_IS_WINDOWS
from sanic.log import error_logger from sanic.log import error_logger
def strtobool(query: str) -> bool:
"""
reimplement strtobool per PEP 632 and python 3.12 deprecation
True values are y, yes, t, true, on and 1; false values are n, no, f,
false, off and 0. Raises ValueError if val is anything else.
"""
if query.lower() in ["y", "yes", "t", "true", "on", "1"]:
return True
elif query.lower() in ["n", "no", "f", "false", "off", "0"]:
return False
else:
raise ValueError(f"String value {query} cannot be converted to bool")
def try_use_uvloop() -> None: def try_use_uvloop() -> None:
""" """
Use uvloop instead of the default asyncio loop. Use uvloop instead of the default asyncio loop.

View File

@ -11,35 +11,18 @@ from sanic.helpers import import_string
def str_to_bool(val: str) -> bool: def str_to_bool(val: str) -> bool:
"""Takes string and tries to turn it into bool as human would do. """
reimplement strtobool per PEP 632 and python 3.12 deprecation
If val is in case insensitive ( True values are y, yes, t, true, on and 1; false values are n, no, f,
"y", "yes", "yep", "yup", "t", false, off and 0. Raises ValueError if val is anything else.
"true", "on", "enable", "enabled", "1" """
) returns True. if val.lower() in ["y", "yes", "t", "true", "on", "1"]:
If val is in case insensitive (
"n", "no", "f", "false", "off", "disable", "disabled", "0"
) returns False.
Else Raise ValueError."""
val = val.lower()
if val in {
"y",
"yes",
"yep",
"yup",
"t",
"true",
"on",
"enable",
"enabled",
"1",
}:
return True return True
elif val in {"n", "no", "f", "false", "off", "disable", "disabled", "0"}: elif val.lower() in ["n", "no", "f", "false", "off", "0"]:
return False return False
else: else:
raise ValueError(f"Invalid truth value {val}") raise ValueError(f"String value {val} cannot be converted to bool")
def load_module_from_file_location( def load_module_from_file_location(

View File

@ -6,8 +6,6 @@ import os
import re import re
import sys import sys
from distutils.util import strtobool
from setuptools import find_packages, setup from setuptools import find_packages, setup
from setuptools.command.test import test as TestCommand from setuptools.command.test import test as TestCommand
@ -61,7 +59,7 @@ setup_kwargs = {
"Build fast. Run fast." "Build fast. Run fast."
), ),
"long_description": long_description, "long_description": long_description,
"packages": find_packages(), "packages": find_packages(include=[]),
"package_data": {"sanic": ["py.typed"]}, "package_data": {"sanic": ["py.typed"]},
"platforms": "any", "platforms": "any",
"python_requires": ">=3.7", "python_requires": ">=3.7",
@ -132,6 +130,23 @@ dev_require = tests_require + [
all_require = list(set(dev_require + docs_require)) all_require = list(set(dev_require + docs_require))
# trying to self-refernce this from within sanic prior to install is
# problematic
def strtobool(val: str) -> bool:
"""
reimplement strtobool per PEP 632 and python 3.12 deprecation
True values are y, yes, t, true, on and 1; false values are n, no, f,
false, off and 0. Raises ValueError if val is anything else.
"""
if val.lower() in ["y", "yes", "t", "true", "on", "1"]:
return True
elif val.lower() in ["n", "no", "f", "false", "off", "0"]:
return False
else:
raise ValueError(f"String value {val} cannot be converted to bool")
if strtobool(os.environ.get("SANIC_NO_UJSON", "no")): if strtobool(os.environ.get("SANIC_NO_UJSON", "no")):
print("Installing without uJSON") print("Installing without uJSON")
requirements.remove(ujson) requirements.remove(ujson)

View File

@ -21,3 +21,25 @@ def test_bad_request_response(app):
app.run(host="127.0.0.1", port=42101, debug=False) app.run(host="127.0.0.1", port=42101, debug=False)
assert lines[0] == b"HTTP/1.1 400 Bad Request\r\n" assert lines[0] == b"HTTP/1.1 400 Bad Request\r\n"
assert b"Bad Request" in lines[-2] assert b"Bad Request" in lines[-2]
def test_malformed_uri_bad_request(app):
lines = []
app.get("/")(lambda x: ...)
@app.listener("after_server_start")
async def _request(sanic, loop):
connect = asyncio.open_connection("127.0.0.1", 42101)
reader, writer = await connect
writer.write(b"GET /\r\nHost: ---.com\r\n\r\n")
while True:
line = await reader.readline()
if not line:
break
lines.append(line)
app.stop()
app.run(host="127.0.0.1", port=42101, debug=False)
assert lines[0] == b"HTTP/1.1 400 Bad Request\r\n"
assert b"Bad Request" in lines[-2]

View File

@ -6,6 +6,7 @@ import pytest
from sanic.exceptions import LoadFileException from sanic.exceptions import LoadFileException
from sanic.utils import load_module_from_file_location from sanic.utils import load_module_from_file_location
from sanic.utils import str_to_bool as strtobool
@pytest.mark.parametrize( @pytest.mark.parametrize(
@ -48,3 +49,20 @@ def test_load_module_from_file_location_using_env():
module = load_module_from_file_location(location) module = load_module_from_file_location(location)
assert isinstance(module, ModuleType) assert isinstance(module, ModuleType)
@pytest.mark.parametrize(
"valid,values",
(
(True, ["y", "yes", "t", "true", "on", "1", "Y", "yEs", "True"]),
(False, ["n", "no", "f", "false", "off", "0", "N", "No", "False"]),
(None, ["yyy", "foo"]),
),
)
def test_strtobool(valid, values):
for value in values:
if valid is None:
with pytest.raises(ValueError):
strtobool(value)
else:
assert strtobool(value) is valid