Skip to content

Commit b4b8ad9

Browse files
fix(#256): PR feedback additional middelware testing
1 parent 8de9c51 commit b4b8ad9

File tree

4 files changed

+83
-2
lines changed

4 files changed

+83
-2
lines changed

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ dev = [
6363
"pytest-asyncio",
6464
"httpx",
6565
"pypgstac>=0.9.8,<=0.10",
66+
"pytest-asyncio>=1.3.0,<2",
6667
"pytest-postgresql",
6768
"owslib",
6869
"pre-commit",

tests/test_middleware.py

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
"""Test middlewares."""
2+
3+
from typing import cast
4+
from unittest import mock
5+
from urllib.parse import quote
6+
7+
import pytest
8+
from starlette.types import Receive, Scope, Send
9+
10+
from titiler.pgstac.middleware import StripNulMiddleware
11+
12+
13+
@pytest.mark.asyncio
14+
async def test_strip_nul_middleware_with_nuls(app) -> None:
15+
"""Test nul byte stripping middleware with nul bytes."""
16+
app_mock = mock.AsyncMock()
17+
core_scope = {
18+
"type": "http",
19+
}
20+
path_with_nul = "/path/with-{}/nul".format("\x00")
21+
path_with_escaped_nul = "/path/with-{}/nul".format(quote("\x00"))
22+
await StripNulMiddleware(app_mock)(
23+
cast(
24+
Scope,
25+
{
26+
**core_scope,
27+
"path": path_with_nul,
28+
"query_string": "param=query-with-{}-nul".format(quote("\x00")).encode(
29+
"utf-8"
30+
),
31+
"raw_path": path_with_escaped_nul.encode("utf-8"),
32+
},
33+
),
34+
cast(Receive, None),
35+
cast(Send, None),
36+
)
37+
path_without_null = "/path/with-/nul"
38+
app_mock.assert_called_once_with(
39+
{
40+
**core_scope,
41+
"path": path_without_null,
42+
"query_string": "param=query-with--nul".encode("utf-8"),
43+
"raw_path": path_without_null.encode("utf-8"),
44+
},
45+
None,
46+
None,
47+
)
48+
49+
50+
@pytest.mark.asyncio
51+
async def test_strip_nul_middleware_without_nuls(app) -> None:
52+
"""Test nul byte stripping middleware without any nul butes."""
53+
app_mock = mock.AsyncMock()
54+
path = "/path/without/nul"
55+
core_scope = {
56+
"type": "http",
57+
"path": path,
58+
"query_string": "param=query-without-nul".encode("utf-8"),
59+
"raw_path": path.encode("utf-8"),
60+
}
61+
await StripNulMiddleware(app_mock)(
62+
cast(
63+
Scope,
64+
core_scope,
65+
),
66+
cast(Receive, None),
67+
cast(Send, None),
68+
)
69+
app_mock.assert_called_once_with(
70+
core_scope,
71+
None,
72+
None,
73+
)

titiler/pgstac/middleware.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,16 @@ async def __call__(self, scope: Scope, receive: Receive, send: Send):
3333
await self.app(scope, receive, send)
3434
return
3535

36-
scope["path"] = re.sub(_nul, "", scope["path"])
36+
scope["path"] = re.sub(
37+
_nul, "", scope["path"]
38+
) # nul in path is URL-unescaped at this point
3739
for property in ["query_string", "raw_path"]:
3840
scope[property] = re.sub(
39-
quote(_nul), "", cast(bytes, scope[property]).decode(_encoding)
41+
quote(_nul),
42+
"",
43+
cast(bytes, scope[property]).decode(
44+
_encoding
45+
), # nul in these properties is URL-escaped
4046
).encode(_encoding)
4147

4248
await self.app(scope, receive, send)

uv.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)