Skip to content

Commit

Permalink
Use web.HTTPError to safely return errors to browser
Browse files Browse the repository at this point in the history
  • Loading branch information
manics committed May 29, 2024
1 parent 652849c commit 3909949
Show file tree
Hide file tree
Showing 2 changed files with 12 additions and 16 deletions.
19 changes: 6 additions & 13 deletions jupyter_server_proxy/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import socket
from asyncio import Lock
from copy import copy
from html import escape
from tempfile import mkdtemp
from urllib.parse import quote, urlparse, urlunparse

Expand Down Expand Up @@ -324,14 +323,11 @@ async def proxy(self, host, port, proxied_path):
"""

if not self._check_host_allowlist(host):
self.set_status(403)
self.write(
"Host '{host}' is not allowed. "
"See https://jupyter-server-proxy.readthedocs.io/en/latest/arbitrary-ports-hosts.html for info.".format(
host=escape(host)
)
raise web.HTTPError(
403,
f"Host '{host}' is not allowed. "
"See https://jupyter-server-proxy.readthedocs.io/en/latest/arbitrary-ports-hosts.html for info.",
)
return

# Remove hop-by-hop headers that don't necessarily apply to the request we are making
# to the backend. See https://github.com/jupyterhub/jupyter-server-proxy/pull/328
Expand Down Expand Up @@ -392,9 +388,7 @@ async def proxy(self, host, port, proxied_path):
# Ref: https://www.tornadoweb.org/en/stable/httpclient.html#tornado.httpclient.AsyncHTTPClient.fetch
if err.code == 599:
self._record_activity()
self.set_status(599)
self.write(escape(str(err)))
return
raise web.HTTPError(599, str(err))
else:
raise

Expand All @@ -403,8 +397,7 @@ async def proxy(self, host, port, proxied_path):

# For all non http errors...
if response.error and type(response.error) is not httpclient.HTTPError:
self.set_status(500)
self.write(escape(str(response.error)))
raise web.HTTPError(500, str(response.error))
else:
# Represent the original response as a RewritableResponse object.
original_response = RewritableResponse(orig_response=response)
Expand Down
9 changes: 6 additions & 3 deletions tests/test_proxies.py
Original file line number Diff line number Diff line change
Expand Up @@ -255,12 +255,15 @@ def test_server_proxy_host_absolute(a_server_port_and_token: Tuple[int, str]) ->
assert "X-Proxycontextpath" not in s


def test_server_proxy_host_invalid(a_server_port_and_token: Tuple[int, str]) -> None:
@pytest.mark.parametrize("absolute", ["", "/absolute"])
def test_server_proxy_host_invalid(
a_server_port_and_token: Tuple[int, str], absolute: str
) -> None:
PORT, TOKEN = a_server_port_and_token
r = request_get(PORT, "/proxy/absolute/<invalid>:54321/", TOKEN)
r = request_get(PORT, f"/proxy{absolute}/<invalid>:54321/", TOKEN)
assert r.code == 403
s = r.read().decode("ascii")
assert s.startswith("Host '&lt;invalid&gt;' is not allowed.")
assert "Host &#39;&lt;invalid&gt;&#39; is not allowed." in s


def test_server_proxy_port_non_service_rewrite_response(
Expand Down

0 comments on commit 3909949

Please sign in to comment.