Merge branch 'main' of github.com:sanic-org/sanic into middleware-revamp
This commit is contained in:
@@ -531,6 +531,8 @@ async def test_signals_triggered(app):
|
||||
"http.lifecycle.handle",
|
||||
"http.routing.before",
|
||||
"http.routing.after",
|
||||
"http.handler.before",
|
||||
"http.handler.after",
|
||||
"http.lifecycle.response",
|
||||
# "http.lifecycle.send",
|
||||
# "http.lifecycle.complete",
|
||||
|
||||
@@ -17,7 +17,7 @@ from sanic.response import json, text
|
||||
# ------------------------------------------------------------ #
|
||||
|
||||
|
||||
def test_bp(app):
|
||||
def test_bp(app: Sanic):
|
||||
bp = Blueprint("test_text")
|
||||
|
||||
@bp.route("/")
|
||||
@@ -30,7 +30,7 @@ def test_bp(app):
|
||||
assert response.text == "Hello"
|
||||
|
||||
|
||||
def test_bp_app_access(app):
|
||||
def test_bp_app_access(app: Sanic):
|
||||
bp = Blueprint("test")
|
||||
|
||||
with pytest.raises(
|
||||
@@ -87,7 +87,7 @@ def test_versioned_routes_get(app, method):
|
||||
assert response.status == 200
|
||||
|
||||
|
||||
def test_bp_strict_slash(app):
|
||||
def test_bp_strict_slash(app: Sanic):
|
||||
bp = Blueprint("test_text")
|
||||
|
||||
@bp.get("/get", strict_slashes=True)
|
||||
@@ -114,7 +114,7 @@ def test_bp_strict_slash(app):
|
||||
assert response.status == 404
|
||||
|
||||
|
||||
def test_bp_strict_slash_default_value(app):
|
||||
def test_bp_strict_slash_default_value(app: Sanic):
|
||||
bp = Blueprint("test_text", strict_slashes=True)
|
||||
|
||||
@bp.get("/get")
|
||||
@@ -134,7 +134,7 @@ def test_bp_strict_slash_default_value(app):
|
||||
assert response.status == 404
|
||||
|
||||
|
||||
def test_bp_strict_slash_without_passing_default_value(app):
|
||||
def test_bp_strict_slash_without_passing_default_value(app: Sanic):
|
||||
bp = Blueprint("test_text")
|
||||
|
||||
@bp.get("/get")
|
||||
@@ -154,7 +154,7 @@ def test_bp_strict_slash_without_passing_default_value(app):
|
||||
assert response.text == "OK"
|
||||
|
||||
|
||||
def test_bp_strict_slash_default_value_can_be_overwritten(app):
|
||||
def test_bp_strict_slash_default_value_can_be_overwritten(app: Sanic):
|
||||
bp = Blueprint("test_text", strict_slashes=True)
|
||||
|
||||
@bp.get("/get", strict_slashes=False)
|
||||
@@ -174,7 +174,7 @@ def test_bp_strict_slash_default_value_can_be_overwritten(app):
|
||||
assert response.text == "OK"
|
||||
|
||||
|
||||
def test_bp_with_url_prefix(app):
|
||||
def test_bp_with_url_prefix(app: Sanic):
|
||||
bp = Blueprint("test_text", url_prefix="/test1")
|
||||
|
||||
@bp.route("/")
|
||||
@@ -187,7 +187,7 @@ def test_bp_with_url_prefix(app):
|
||||
assert response.text == "Hello"
|
||||
|
||||
|
||||
def test_several_bp_with_url_prefix(app):
|
||||
def test_several_bp_with_url_prefix(app: Sanic):
|
||||
bp = Blueprint("test_text", url_prefix="/test1")
|
||||
bp2 = Blueprint("test_text2", url_prefix="/test2")
|
||||
|
||||
@@ -208,7 +208,7 @@ def test_several_bp_with_url_prefix(app):
|
||||
assert response.text == "Hello2"
|
||||
|
||||
|
||||
def test_bp_with_host(app):
|
||||
def test_bp_with_host(app: Sanic):
|
||||
bp = Blueprint("test_bp_host", url_prefix="/test1", host="example.com")
|
||||
|
||||
@bp.route("/")
|
||||
@@ -230,7 +230,7 @@ def test_bp_with_host(app):
|
||||
assert response.body == b"Hello subdomain!"
|
||||
|
||||
|
||||
def test_several_bp_with_host(app):
|
||||
def test_several_bp_with_host(app: Sanic):
|
||||
bp = Blueprint(
|
||||
"test_text",
|
||||
url_prefix="/test",
|
||||
@@ -274,7 +274,7 @@ def test_several_bp_with_host(app):
|
||||
assert response.text == "Hello3"
|
||||
|
||||
|
||||
def test_bp_with_host_list(app):
|
||||
def test_bp_with_host_list(app: Sanic):
|
||||
bp = Blueprint(
|
||||
"test_bp_host",
|
||||
url_prefix="/test1",
|
||||
@@ -304,7 +304,7 @@ def test_bp_with_host_list(app):
|
||||
assert response.text == "Hello subdomain!"
|
||||
|
||||
|
||||
def test_several_bp_with_host_list(app):
|
||||
def test_several_bp_with_host_list(app: Sanic):
|
||||
bp = Blueprint(
|
||||
"test_text",
|
||||
url_prefix="/test",
|
||||
@@ -356,7 +356,7 @@ def test_several_bp_with_host_list(app):
|
||||
assert response.text == "Hello3"
|
||||
|
||||
|
||||
def test_bp_middleware(app):
|
||||
def test_bp_middleware(app: Sanic):
|
||||
blueprint = Blueprint("test_bp_middleware")
|
||||
|
||||
@blueprint.middleware("response")
|
||||
@@ -375,7 +375,7 @@ def test_bp_middleware(app):
|
||||
assert response.text == "FAIL"
|
||||
|
||||
|
||||
def test_bp_middleware_with_route(app):
|
||||
def test_bp_middleware_with_route(app: Sanic):
|
||||
blueprint = Blueprint("test_bp_middleware")
|
||||
|
||||
@blueprint.middleware("response")
|
||||
@@ -398,7 +398,7 @@ def test_bp_middleware_with_route(app):
|
||||
assert response.text == "OK"
|
||||
|
||||
|
||||
def test_bp_middleware_order(app):
|
||||
def test_bp_middleware_order(app: Sanic):
|
||||
blueprint = Blueprint("test_bp_middleware_order")
|
||||
order = []
|
||||
|
||||
@@ -438,7 +438,7 @@ def test_bp_middleware_order(app):
|
||||
assert order == [1, 2, 3, 4, 5, 6]
|
||||
|
||||
|
||||
def test_bp_exception_handler(app):
|
||||
def test_bp_exception_handler(app: Sanic):
|
||||
blueprint = Blueprint("test_middleware")
|
||||
|
||||
@blueprint.route("/1")
|
||||
@@ -470,7 +470,7 @@ def test_bp_exception_handler(app):
|
||||
assert response.status == 200
|
||||
|
||||
|
||||
def test_bp_exception_handler_applied(app):
|
||||
def test_bp_exception_handler_applied(app: Sanic):
|
||||
class Error(Exception):
|
||||
pass
|
||||
|
||||
@@ -500,7 +500,7 @@ def test_bp_exception_handler_applied(app):
|
||||
assert response.status == 500
|
||||
|
||||
|
||||
def test_bp_exception_handler_not_applied(app):
|
||||
def test_bp_exception_handler_not_applied(app: Sanic):
|
||||
class Error(Exception):
|
||||
pass
|
||||
|
||||
@@ -522,7 +522,7 @@ def test_bp_exception_handler_not_applied(app):
|
||||
assert response.status == 500
|
||||
|
||||
|
||||
def test_bp_listeners(app):
|
||||
def test_bp_listeners(app: Sanic):
|
||||
app.route("/")(lambda x: x)
|
||||
blueprint = Blueprint("test_middleware")
|
||||
|
||||
@@ -559,7 +559,7 @@ def test_bp_listeners(app):
|
||||
assert order == [1, 2, 3, 4, 5, 6]
|
||||
|
||||
|
||||
def test_bp_static(app):
|
||||
def test_bp_static(app: Sanic):
|
||||
current_file = inspect.getfile(inspect.currentframe())
|
||||
with open(current_file, "rb") as file:
|
||||
current_file_contents = file.read()
|
||||
@@ -597,7 +597,7 @@ def test_bp_static_content_type(app, file_name):
|
||||
assert response.headers["Content-Type"] == "text/html; charset=utf-8"
|
||||
|
||||
|
||||
def test_bp_shorthand(app):
|
||||
def test_bp_shorthand(app: Sanic):
|
||||
blueprint = Blueprint("test_shorhand_routes")
|
||||
ev = asyncio.Event()
|
||||
|
||||
@@ -682,7 +682,7 @@ def test_bp_shorthand(app):
|
||||
assert ev.is_set()
|
||||
|
||||
|
||||
def test_bp_group(app):
|
||||
def test_bp_group(app: Sanic):
|
||||
deep_0 = Blueprint("deep_0", url_prefix="/deep")
|
||||
deep_1 = Blueprint("deep_1", url_prefix="/deep1")
|
||||
|
||||
@@ -722,7 +722,7 @@ def test_bp_group(app):
|
||||
assert response.text == "D1B_OK"
|
||||
|
||||
|
||||
def test_bp_group_with_default_url_prefix(app):
|
||||
def test_bp_group_with_default_url_prefix(app: Sanic):
|
||||
from sanic.response import json
|
||||
|
||||
bp_resources = Blueprint("bp_resources")
|
||||
@@ -873,7 +873,7 @@ def test_websocket_route(app: Sanic):
|
||||
assert event.is_set()
|
||||
|
||||
|
||||
def test_duplicate_blueprint(app):
|
||||
def test_duplicate_blueprint(app: Sanic):
|
||||
bp_name = "bp"
|
||||
bp = Blueprint(bp_name)
|
||||
bp1 = Blueprint(bp_name)
|
||||
@@ -1056,7 +1056,7 @@ def test_bp_set_attribute_warning():
|
||||
bp.foo = 1
|
||||
|
||||
|
||||
def test_early_registration(app):
|
||||
def test_early_registration(app: Sanic):
|
||||
assert len(app.router.routes) == 0
|
||||
|
||||
bp = Blueprint("bp")
|
||||
@@ -1082,3 +1082,29 @@ def test_early_registration(app):
|
||||
for path in ("one", "two", "three"):
|
||||
_, response = app.test_client.get(f"/{path}")
|
||||
assert response.text == path
|
||||
|
||||
|
||||
def test_remove_double_slashes_defined_on_bp(app: Sanic):
|
||||
bp = Blueprint("bp", url_prefix="/foo/", strict_slashes=True)
|
||||
|
||||
@bp.get("/")
|
||||
async def handler(_):
|
||||
...
|
||||
|
||||
app.blueprint(bp)
|
||||
app.router.finalize()
|
||||
|
||||
assert app.router.routes[0].path == "foo/"
|
||||
|
||||
|
||||
def test_remove_double_slashes_defined_on_register(app: Sanic):
|
||||
bp = Blueprint("bp")
|
||||
|
||||
@bp.get("/")
|
||||
async def index(_):
|
||||
...
|
||||
|
||||
app.blueprint(bp, url_prefix="/foo/", strict_slashes=True)
|
||||
app.router.finalize()
|
||||
|
||||
assert app.router.routes[0].path == "foo/"
|
||||
|
||||
@@ -120,7 +120,7 @@ def test_error_with_path_as_instance_without_simple_arg():
|
||||
),
|
||||
),
|
||||
)
|
||||
def test_tls_options(cmd: Tuple[str]):
|
||||
def test_tls_options(cmd: Tuple[str, ...]):
|
||||
command = ["sanic", "fake.server.app", *cmd, "-p=9999", "--debug"]
|
||||
out, err, exitcode = capture(command)
|
||||
assert exitcode != 1
|
||||
@@ -141,7 +141,7 @@ def test_tls_options(cmd: Tuple[str]):
|
||||
("--tls-strict-host",),
|
||||
),
|
||||
)
|
||||
def test_tls_wrong_options(cmd: Tuple[str]):
|
||||
def test_tls_wrong_options(cmd: Tuple[str, ...]):
|
||||
command = ["sanic", "fake.server.app", *cmd, "-p=9999", "--debug"]
|
||||
out, err, exitcode = capture(command)
|
||||
assert exitcode == 1
|
||||
@@ -158,7 +158,7 @@ def test_tls_wrong_options(cmd: Tuple[str]):
|
||||
("-H", "localhost", "-p", "9999"),
|
||||
),
|
||||
)
|
||||
def test_host_port_localhost(cmd: Tuple[str]):
|
||||
def test_host_port_localhost(cmd: Tuple[str, ...]):
|
||||
command = ["sanic", "fake.server.app", *cmd]
|
||||
out, err, exitcode = capture(command)
|
||||
lines = out.split(b"\n")
|
||||
@@ -175,7 +175,7 @@ def test_host_port_localhost(cmd: Tuple[str]):
|
||||
("-H", "127.0.0.127", "-p", "9999"),
|
||||
),
|
||||
)
|
||||
def test_host_port_ipv4(cmd: Tuple[str]):
|
||||
def test_host_port_ipv4(cmd: Tuple[str, ...]):
|
||||
command = ["sanic", "fake.server.app", *cmd]
|
||||
out, err, exitcode = capture(command)
|
||||
lines = out.split(b"\n")
|
||||
@@ -192,7 +192,7 @@ def test_host_port_ipv4(cmd: Tuple[str]):
|
||||
("-H", "::", "-p", "9999"),
|
||||
),
|
||||
)
|
||||
def test_host_port_ipv6_any(cmd: Tuple[str]):
|
||||
def test_host_port_ipv6_any(cmd: Tuple[str, ...]):
|
||||
command = ["sanic", "fake.server.app", *cmd]
|
||||
out, err, exitcode = capture(command)
|
||||
lines = out.split(b"\n")
|
||||
@@ -209,7 +209,7 @@ def test_host_port_ipv6_any(cmd: Tuple[str]):
|
||||
("-H", "::1", "-p", "9999"),
|
||||
),
|
||||
)
|
||||
def test_host_port_ipv6_loopback(cmd: Tuple[str]):
|
||||
def test_host_port_ipv6_loopback(cmd: Tuple[str, ...]):
|
||||
command = ["sanic", "fake.server.app", *cmd]
|
||||
out, err, exitcode = capture(command)
|
||||
lines = out.split(b"\n")
|
||||
@@ -230,7 +230,7 @@ def test_host_port_ipv6_loopback(cmd: Tuple[str]):
|
||||
(4, ("-w", "4")),
|
||||
),
|
||||
)
|
||||
def test_num_workers(num: int, cmd: Tuple[str]):
|
||||
def test_num_workers(num: int, cmd: Tuple[str, ...]):
|
||||
command = ["sanic", "fake.server.app", *cmd]
|
||||
out, err, exitcode = capture(command)
|
||||
lines = out.split(b"\n")
|
||||
|
||||
@@ -7,7 +7,7 @@ from unittest.mock import Mock
|
||||
import pytest
|
||||
|
||||
from bs4 import BeautifulSoup
|
||||
from pytest import LogCaptureFixture, MonkeyPatch
|
||||
from pytest import LogCaptureFixture, MonkeyPatch, WarningsRecorder
|
||||
|
||||
from sanic import Sanic, handlers
|
||||
from sanic.exceptions import BadRequest, Forbidden, NotFound, ServerError
|
||||
@@ -266,3 +266,22 @@ def test_exception_handler_response_was_sent(
|
||||
|
||||
_, response = app.test_client.get("/2")
|
||||
assert "Error" in response.text
|
||||
|
||||
|
||||
def test_warn_on_duplicate(
|
||||
app: Sanic, caplog: LogCaptureFixture, recwarn: WarningsRecorder
|
||||
):
|
||||
@app.exception(ServerError)
|
||||
async def exception_handler_1(request, exception):
|
||||
...
|
||||
|
||||
@app.exception(ServerError)
|
||||
async def exception_handler_2(request, exception):
|
||||
...
|
||||
|
||||
assert len(caplog.records) == 1
|
||||
assert len(recwarn) == 1
|
||||
assert caplog.records[0].message == (
|
||||
"Duplicate exception handler definition on: route=__ALL_ROUTES__ and "
|
||||
"exception=<class 'sanic.exceptions.ServerError'>"
|
||||
)
|
||||
|
||||
36
tests/test_handler.py
Normal file
36
tests/test_handler.py
Normal file
@@ -0,0 +1,36 @@
|
||||
from sanic.app import Sanic
|
||||
from sanic.response import empty
|
||||
from sanic.signals import Event
|
||||
|
||||
|
||||
def test_handler_operation_order(app: Sanic):
|
||||
operations = []
|
||||
|
||||
@app.on_request
|
||||
async def on_request(_):
|
||||
nonlocal operations
|
||||
operations.append(1)
|
||||
|
||||
@app.on_response
|
||||
async def on_response(*_):
|
||||
nonlocal operations
|
||||
operations.append(5)
|
||||
|
||||
@app.get("/")
|
||||
async def handler(_):
|
||||
nonlocal operations
|
||||
operations.append(3)
|
||||
return empty()
|
||||
|
||||
@app.signal(Event.HTTP_HANDLER_BEFORE)
|
||||
async def handler_before(**_):
|
||||
nonlocal operations
|
||||
operations.append(2)
|
||||
|
||||
@app.signal(Event.HTTP_HANDLER_AFTER)
|
||||
async def handler_after(**_):
|
||||
nonlocal operations
|
||||
operations.append(4)
|
||||
|
||||
app.test_client.get("/")
|
||||
assert operations == [1, 2, 3, 4, 5]
|
||||
@@ -1,6 +1,7 @@
|
||||
import asyncio
|
||||
import inspect
|
||||
import os
|
||||
import time
|
||||
|
||||
from collections import namedtuple
|
||||
from datetime import datetime
|
||||
@@ -730,8 +731,10 @@ def test_file_response_headers(
|
||||
test_expires = test_last_modified.timestamp() + test_max_age
|
||||
|
||||
@app.route("/files/cached/<filename>", methods=["GET"])
|
||||
def file_route_cache(request, filename):
|
||||
file_path = (Path(static_file_directory) / file_name).absolute()
|
||||
def file_route_cache(request: Request, filename: str):
|
||||
file_path = (
|
||||
Path(static_file_directory) / unquote(filename)
|
||||
).absolute()
|
||||
return file(
|
||||
file_path, max_age=test_max_age, last_modified=test_last_modified
|
||||
)
|
||||
@@ -739,18 +742,26 @@ def test_file_response_headers(
|
||||
@app.route(
|
||||
"/files/cached_default_last_modified/<filename>", methods=["GET"]
|
||||
)
|
||||
def file_route_cache_default_last_modified(request, filename):
|
||||
file_path = (Path(static_file_directory) / file_name).absolute()
|
||||
def file_route_cache_default_last_modified(
|
||||
request: Request, filename: str
|
||||
):
|
||||
file_path = (
|
||||
Path(static_file_directory) / unquote(filename)
|
||||
).absolute()
|
||||
return file(file_path, max_age=test_max_age)
|
||||
|
||||
@app.route("/files/no_cache/<filename>", methods=["GET"])
|
||||
def file_route_no_cache(request, filename):
|
||||
file_path = (Path(static_file_directory) / file_name).absolute()
|
||||
def file_route_no_cache(request: Request, filename: str):
|
||||
file_path = (
|
||||
Path(static_file_directory) / unquote(filename)
|
||||
).absolute()
|
||||
return file(file_path)
|
||||
|
||||
@app.route("/files/no_store/<filename>", methods=["GET"])
|
||||
def file_route_no_store(request, filename):
|
||||
file_path = (Path(static_file_directory) / file_name).absolute()
|
||||
def file_route_no_store(request: Request, filename: str):
|
||||
file_path = (
|
||||
Path(static_file_directory) / unquote(filename)
|
||||
).absolute()
|
||||
return file(file_path, no_store=True)
|
||||
|
||||
_, response = app.test_client.get(f"/files/cached/{file_name}")
|
||||
@@ -767,11 +778,11 @@ def test_file_response_headers(
|
||||
== formatdate(test_expires, usegmt=True)[:-6]
|
||||
# [:-6] to allow at most 1 min difference
|
||||
# It's minimal for cases like:
|
||||
# Thu, 26 May 2022 05:36:49 GMT
|
||||
# Thu, 26 May 2022 05:36:59 GMT
|
||||
# AND
|
||||
# Thu, 26 May 2022 05:36:50 GMT
|
||||
# Thu, 26 May 2022 05:37:00 GMT
|
||||
)
|
||||
|
||||
assert response.status == 200
|
||||
assert "last-modified" in headers and headers.get(
|
||||
"last-modified"
|
||||
) == formatdate(test_last_modified.timestamp(), usegmt=True)
|
||||
@@ -786,15 +797,127 @@ def test_file_response_headers(
|
||||
assert "last-modified" in headers and headers.get(
|
||||
"last-modified"
|
||||
) == formatdate(file_last_modified, usegmt=True)
|
||||
assert response.status == 200
|
||||
|
||||
_, response = app.test_client.get(f"/files/no_cache/{file_name}")
|
||||
headers = response.headers
|
||||
assert "cache-control" in headers and f"no-cache" == headers.get(
|
||||
"cache-control"
|
||||
)
|
||||
assert response.status == 200
|
||||
|
||||
_, response = app.test_client.get(f"/files/no_store/{file_name}")
|
||||
headers = response.headers
|
||||
assert "cache-control" in headers and f"no-store" == headers.get(
|
||||
"cache-control"
|
||||
)
|
||||
assert response.status == 200
|
||||
|
||||
|
||||
def test_file_validate(app: Sanic, static_file_directory: str):
|
||||
file_name = "test_validate.txt"
|
||||
static_file_directory = Path(static_file_directory)
|
||||
file_path = static_file_directory / file_name
|
||||
file_path = file_path.absolute()
|
||||
test_max_age = 10
|
||||
|
||||
with open(file_path, "w+") as f:
|
||||
f.write("foo\n")
|
||||
|
||||
@app.route("/validate", methods=["GET"])
|
||||
def file_route_cache(request: Request):
|
||||
return file(
|
||||
file_path,
|
||||
request_headers=request.headers,
|
||||
max_age=test_max_age,
|
||||
validate_when_requested=True,
|
||||
)
|
||||
|
||||
_, response = app.test_client.get("/validate")
|
||||
assert response.status == 200
|
||||
assert response.body == b"foo\n"
|
||||
last_modified = response.headers["Last-Modified"]
|
||||
|
||||
time.sleep(1)
|
||||
with open(file_path, "a") as f:
|
||||
f.write("bar\n")
|
||||
|
||||
_, response = app.test_client.get(
|
||||
"/validate", headers={"If-Modified-Since": last_modified}
|
||||
)
|
||||
assert response.status == 200
|
||||
assert response.body == b"foo\nbar\n"
|
||||
|
||||
last_modified = response.headers["Last-Modified"]
|
||||
_, response = app.test_client.get(
|
||||
"/validate", headers={"if-modified-since": last_modified}
|
||||
)
|
||||
assert response.status == 304
|
||||
assert response.body == b""
|
||||
|
||||
file_path.unlink()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"file_name", ["test.file", "decode me.txt", "python.png"]
|
||||
)
|
||||
def test_file_validating_invalid_header(
|
||||
app: Sanic, file_name: str, static_file_directory: str
|
||||
):
|
||||
@app.route("/files/<filename>", methods=["GET"])
|
||||
def file_route(request: Request, filename: str):
|
||||
handler_file_path = (
|
||||
Path(static_file_directory) / unquote(filename)
|
||||
).absolute()
|
||||
|
||||
return file(
|
||||
handler_file_path,
|
||||
request_headers=request.headers,
|
||||
validate_when_requested=True,
|
||||
)
|
||||
|
||||
_, response = app.test_client.get(f"/files/{file_name}")
|
||||
assert response.status == 200
|
||||
assert response.body == get_file_content(static_file_directory, file_name)
|
||||
|
||||
_, response = app.test_client.get(
|
||||
f"/files/{file_name}", headers={"if-modified-since": "invalid-value"}
|
||||
)
|
||||
assert response.status == 200
|
||||
assert response.body == get_file_content(static_file_directory, file_name)
|
||||
|
||||
_, response = app.test_client.get(
|
||||
f"/files/{file_name}", headers={"if-modified-since": ""}
|
||||
)
|
||||
assert response.status == 200
|
||||
assert response.body == get_file_content(static_file_directory, file_name)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"file_name", ["test.file", "decode me.txt", "python.png"]
|
||||
)
|
||||
def test_file_validating_304_response(
|
||||
app: Sanic, file_name: str, static_file_directory: str
|
||||
):
|
||||
@app.route("/files/<filename>", methods=["GET"])
|
||||
def file_route(request: Request, filename: str):
|
||||
handler_file_path = (
|
||||
Path(static_file_directory) / unquote(filename)
|
||||
).absolute()
|
||||
|
||||
return file(
|
||||
handler_file_path,
|
||||
request_headers=request.headers,
|
||||
validate_when_requested=True,
|
||||
)
|
||||
|
||||
_, response = app.test_client.get(f"/files/{file_name}")
|
||||
assert response.status == 200
|
||||
assert response.body == get_file_content(static_file_directory, file_name)
|
||||
|
||||
_, response = app.test_client.get(
|
||||
f"/files/{file_name}",
|
||||
headers={"if-modified-since": response.headers["Last-Modified"]},
|
||||
)
|
||||
assert response.status == 304
|
||||
assert response.body == b""
|
||||
|
||||
Reference in New Issue
Block a user