feat: X-Host-Only

This commit is contained in:
2026-04-21 22:51:35 +02:00
parent 18c718d24a
commit c0c281e25c
11 changed files with 229 additions and 60 deletions
+79 -31
View File
@@ -122,7 +122,6 @@ class TestRequestHandler(BaseHandlerTestCase):
def setUp(self) -> None:
self.get_tmp_dir()
self.registry = self.new_mock()
self.cert_manager = self.new_mock()
self.token_manager = self.new_mock()
self.certbot_www = self.tmp_path / "certbot_www"
self.data_dir = self.new_mock()
@@ -146,7 +145,6 @@ class TestRequestHandler(BaseHandlerTestCase):
data_dir=self.get_tmp_dir(), certbot_www=str(self.certbot_www)
),
registry=self.registry,
cert_manager=self.cert_manager,
token_manager=self.token_manager,
)
handler.address_string = lambda: "127.0.0.1" # ty:ignore[invalid-assignment]
@@ -285,6 +283,44 @@ class TestRequestHandler(BaseHandlerTestCase):
):
handler.do_PUT()
def test_do_put_invalid_host_only(self) -> None:
handler = self._get_handler(
"/path", {"X-Token": "secret", "X-Host-Only": "invalid_host"}
)
with (
self.mock_call(self.token_manager.is_valid, ["secret"], True), # noqa: FBT003
self.mock_call(
self.token_manager.is_valid_for_path,
["secret", "path"],
True, # noqa: FBT003
),
self.expects_error(
handler, http.HTTPStatus.BAD_REQUEST, "Invalid requested host"
),
self.seal_mocks(),
):
handler.do_PUT()
def test_do_put_invalid_host_and_host_only(self) -> None:
handler = self._get_handler(
"/path", {"X-Token": "secret", "X-Host": "host", "X-Host-Only": "host"}
)
with (
self.mock_call(self.token_manager.is_valid, ["secret"], True), # noqa: FBT003
self.mock_call(
self.token_manager.is_valid_for_path,
["secret", "path"],
True, # noqa: FBT003
),
self.expects_error(
handler,
http.HTTPStatus.BAD_REQUEST,
"Cannot use X-Host-Only with X-Host",
),
self.seal_mocks(),
):
handler.do_PUT()
def test_do_put_invalid_host_for_path(self) -> None:
handler = self._get_handler(
"/path", {"X-Token": "secret", "X-Host": "example.com"}
@@ -404,31 +440,6 @@ class TestRequestHandler(BaseHandlerTestCase):
):
handler.do_PUT()
def test_do_put_extract_with_host_fail_init(self) -> None:
handler = self._get_handler(
"/path",
{"X-Token": "secret", "Content-Length": "1", "X-Host": "example.com"},
)
handler.rfile.write(b"\0")
with (
self.mock_call(self.token_manager.is_valid, ["secret"], True), # noqa: FBT003
self.mock_call(
self.token_manager.is_valid_for_path,
["secret", "path"],
True, # noqa: FBT003
),
self.mock_call(self.registry.get_from_host, ["example.com"], Page("path")),
self.mock_call_unchecked(self.data_dir.extract_tar_bytes),
self.mock_call(self.registry.add, ["path"]),
self.mock_call(self.token_manager.set_token, ["path", "secret"]),
self.mock_call(self.cert_manager.create_or_update, ["example.com"], False), # noqa: FBT003
self.expects_status_only(
handler, http.HTTPStatus.CREATED, "Resource /path/ updated"
),
self.seal_mocks(),
):
handler.do_PUT()
def test_do_put_extract_with_host(self) -> None:
handler = self._get_handler(
"/path",
@@ -446,7 +457,6 @@ class TestRequestHandler(BaseHandlerTestCase):
self.mock_call_unchecked(self.data_dir.extract_tar_bytes),
self.mock_call(self.registry.add, ["path"]),
self.mock_call(self.token_manager.set_token, ["path", "secret"]),
self.mock_call(self.cert_manager.create_or_update, ["example.com"], True), # noqa: FBT003
self.mock_call(self.registry.set_host, ["path", "example.com"]),
self.expects_status_only(
handler, http.HTTPStatus.CREATED, "Resource /path/ updated"
@@ -523,7 +533,6 @@ class TestRequestHandler(BaseHandlerTestCase):
self.mock_call(self.registry.get_from_host, ["example.com"], Page("path")),
self.mock_call(self.registry.set_redirect, ["path", "https://example.com"]),
self.mock_call(self.token_manager.set_token, ["path", "secret"]),
self.mock_call(self.cert_manager.create_or_update, ["example.com"], True), # noqa: FBT003
self.mock_call(self.registry.set_host, ["path", "example.com"]),
self.expects_status_only(
handler, http.HTTPStatus.CREATED, "Resource /path/ updated"
@@ -532,6 +541,33 @@ class TestRequestHandler(BaseHandlerTestCase):
):
handler.do_PUT()
def test_do_put_redirect_with_host_only(self) -> None:
handler = self._get_handler(
"/path",
{
"X-Token": "secret",
"X-Redirect": "https://example.com",
"X-Host-Only": "example.com",
},
)
with (
self.mock_call(self.token_manager.is_valid, ["secret"], True), # noqa: FBT003
self.mock_call(
self.token_manager.is_valid_for_path,
["secret", "path"],
True, # noqa: FBT003
),
self.mock_call(self.registry.get_from_host, ["example.com"], Page("path")),
self.mock_call(self.registry.set_redirect, ["path", "https://example.com"]),
self.mock_call(self.token_manager.set_token, ["path", "secret"]),
self.mock_call(self.registry.set_host_only, ["path", "example.com"]),
self.expects_status_only(
handler, http.HTTPStatus.CREATED, "Resource /path/ updated"
),
self.seal_mocks(),
):
handler.do_PUT()
def test_do_put_proxy_with_content(self) -> None:
handler = self._get_handler(
"/path",
@@ -600,7 +636,6 @@ class TestRequestHandler(BaseHandlerTestCase):
self.mock_call(self.registry.get_from_host, ["example.com"], Page("path")),
self.mock_call(self.registry.set_proxy, ["path", "https://example.com"]),
self.mock_call(self.token_manager.set_token, ["path", "secret"]),
self.mock_call(self.cert_manager.create_or_update, ["example.com"], True), # noqa: FBT003
self.mock_call(self.registry.set_host, ["path", "example.com"]),
self.expects_status_only(
handler, http.HTTPStatus.CREATED, "Resource /path/ updated"
@@ -626,7 +661,6 @@ class TestRequestHandler(BaseHandlerTestCase):
["secret", "path"],
True, # noqa: FBT003
),
self.mock_call(self.registry.get_from_host, ["example.com"], Page("path")),
self.expects_status_only(
handler,
http.HTTPStatus.BAD_REQUEST,
@@ -1106,6 +1140,20 @@ class TestRequestHandler(BaseHandlerTestCase):
None,
)
def test_translate_path_default_host_only(self) -> None:
handler = self._get_handler()
with (
self.mock_call(
self.registry.get_from_path, ["path"], Page("path", host_only=True)
),
self.patch("http.server.SimpleHTTPRequestHandler.translate_path", count=0),
self.seal_mocks(),
):
self.assertEqual(
handler.translate_path("/path/index.html"),
"",
)
def test_translate_path_default_host_not_found(self) -> None:
handler = self._get_handler()
with (