Skip to content

Commit 3909949

Browse files
committed
Use web.HTTPError to safely return errors to browser
1 parent 652849c commit 3909949

File tree

2 files changed

+12
-16
lines changed

2 files changed

+12
-16
lines changed

jupyter_server_proxy/handlers.py

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import socket
99
from asyncio import Lock
1010
from copy import copy
11-
from html import escape
1211
from tempfile import mkdtemp
1312
from urllib.parse import quote, urlparse, urlunparse
1413

@@ -324,14 +323,11 @@ async def proxy(self, host, port, proxied_path):
324323
"""
325324

326325
if not self._check_host_allowlist(host):
327-
self.set_status(403)
328-
self.write(
329-
"Host '{host}' is not allowed. "
330-
"See https://jupyter-server-proxy.readthedocs.io/en/latest/arbitrary-ports-hosts.html for info.".format(
331-
host=escape(host)
332-
)
326+
raise web.HTTPError(
327+
403,
328+
f"Host '{host}' is not allowed. "
329+
"See https://jupyter-server-proxy.readthedocs.io/en/latest/arbitrary-ports-hosts.html for info.",
333330
)
334-
return
335331

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

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

404398
# For all non http errors...
405399
if response.error and type(response.error) is not httpclient.HTTPError:
406-
self.set_status(500)
407-
self.write(escape(str(response.error)))
400+
raise web.HTTPError(500, str(response.error))
408401
else:
409402
# Represent the original response as a RewritableResponse object.
410403
original_response = RewritableResponse(orig_response=response)

tests/test_proxies.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -255,12 +255,15 @@ def test_server_proxy_host_absolute(a_server_port_and_token: Tuple[int, str]) ->
255255
assert "X-Proxycontextpath" not in s
256256

257257

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

265268

266269
def test_server_proxy_port_non_service_rewrite_response(

0 commit comments

Comments
 (0)