Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

allow the app to be hosted at a prefix in script_name but still validate against allowed servers #263

Merged
merged 1 commit into from
Dec 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 104 additions & 0 deletions pyramid_openapi3/tests/test_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,110 @@ def test_request_validation_disabled_response_validation_enabled(self) -> None:
self.assertEqual(start_response.status, "500 Internal Server Error")


class TestServerRequestValidation(RequestValidationBase): # noqa: D101

openapi_spec = (
b"openapi: '3.1.0'\n"
b"info:\n"
b" version: '1.0.0'\n"
b" title: Foo API\n"
b"servers:\n"
b" - url: /prefix/v1\n"
b" - url: http://example.com/prefix\n"
b"paths:\n"
b" /foo:\n"
b" get:\n"
b" responses:\n"
b" 200:\n"
b" description: A foo\n"
b" content:\n"
b" application/json:\n"
b" schema:\n"
b" type: object\n"
b" properties:\n"
b" test:\n"
b" type: string\n"
b" 400:\n"
b" description: Bad Request\n"
)

def test_server_validation_works_with_script_name(self) -> None:
"""Expect to find a match for http://localhost:8080/prefix/v1/foo."""
self._add_view(lambda *arg: {"test": "correct"})
# run request through router
router = Router(self.config.registry)
environ = {
"wsgi.url_scheme": "http",
"SERVER_NAME": "localhost",
"SERVER_PORT": "8080",
"REQUEST_METHOD": "GET",
"SCRIPT_NAME": "/prefix/v1",
"PATH_INFO": "/foo",
"HTTP_ACCEPT": "application/json",
}
start_response = DummyStartResponse()
response = router(environ, start_response)

self.assertEqual(start_response.status, "200 OK")
self.assertEqual(json.loads(response[0]), {"test": "correct"})

def test_server_validation_works_with_script_name_and_hostname(self) -> None:
"""Expect to find a match for http://example.com/prefix/foo."""
self._add_view(lambda *arg: {"test": "correct"})
# run request through router
router = Router(self.config.registry)
environ = {
"wsgi.url_scheme": "http",
"SERVER_NAME": "localhost",
"SERVER_PORT": "8080",
"REQUEST_METHOD": "GET",
"SCRIPT_NAME": "/prefix",
"PATH_INFO": "/foo",
"HTTP_HOST": "example.com",
"HTTP_ACCEPT": "application/json",
}
start_response = DummyStartResponse()
response = router(environ, start_response)

self.assertEqual(start_response.status, "200 OK")
self.assertEqual(json.loads(response[0]), {"test": "correct"})

def test_server_validation_fails_with_bad_hostname(self) -> None:
"""Expect to fail for /prefix/v2/foo."""
self._add_view()
# run request through router
router = Router(self.config.registry)
environ = {
"wsgi.url_scheme": "http",
"SERVER_NAME": "localhost",
"SERVER_PORT": "8080",
"REQUEST_METHOD": "GET",
"SCRIPT_NAME": "/prefix/v2",
"PATH_INFO": "/foo",
"HTTP_HOST": "example.com",
"HTTP_ACCEPT": "application/json",
}
start_response = DummyStartResponse()
with self.assertLogs(level="ERROR") as cm:
response = router(environ, start_response)
self.assertEqual(start_response.status, "500 Internal Server Error")
self.assertEqual(
json.loads(response[0]),
[
{
"exception": "ServerNotFound",
"message": "Server not found for http://example.com/prefix/v2/foo",
}
],
)
self.assertEqual(
cm.output,
[
"ERROR:pyramid_openapi3:Server not found for http://example.com/prefix/v2/foo"
],
)


class TestImproperAPISpecValidation(RequestValidationBase): # noqa: D101

openapi_spec = (
Expand Down
2 changes: 1 addition & 1 deletion pyramid_openapi3/tests/test_wrappers.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ def test_relative_app_request() -> None:
)
assert openapi_request.host_url == "http://example.com"
assert openapi_request.path == "/subpath/foo"
assert openapi_request.path_pattern == "/foo"
assert openapi_request.path_pattern == "/subpath/foo"
assert openapi_request.method == "get"
assert openapi_request.body == b""
assert openapi_request.mimetype == "text/html"
Expand Down
2 changes: 1 addition & 1 deletion pyramid_openapi3/wrappers.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def path_pattern(self) -> str:
if self.request.matched_route
else self.request.path_info
)
return path_pattern
return self.request.script_name + path_pattern

@property
def method(self) -> str:
Expand Down