Skip to content

Commit 7f309b3

Browse files
committed
include websocket protocol in response
Chrome doesn't accept websocket connections if protocol is requested but not provided
1 parent 9627c7c commit 7f309b3

File tree

4 files changed

+21
-2
lines changed

4 files changed

+21
-2
lines changed

jupyter_server/base/websocket.py

+10
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
"""Base websocket classes."""
2+
3+
from __future__ import annotations
4+
25
import re
36
import warnings
47
from typing import Optional, no_type_check
@@ -164,3 +167,10 @@ def send_ping(self):
164167
def on_pong(self, data):
165168
"""Handle a pong message."""
166169
self.last_pong = ioloop.IOLoop.current().time()
170+
171+
def select_subprotocol(self, subprotocols: list[str]) -> str | None:
172+
# default subprotocol
173+
# some clients (Chrome)
174+
# require selected subprotocol to match one of the requested subprotocols
175+
# otherwise connection is rejected
176+
return "v1.token.websocket.jupyter.org"

jupyter_server/services/events/handlers.py

+2
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,15 @@
1414

1515
from jupyter_server.auth.decorator import authorized, ws_authenticated
1616
from jupyter_server.base.handlers import JupyterHandler
17+
from jupyter_server.base.websocket import WebSocketMixin
1718

1819
from ...base.handlers import APIHandler
1920

2021
AUTH_RESOURCE = "events"
2122

2223

2324
class SubscribeWebsocket(
25+
WebSocketMixin,
2426
JupyterHandler,
2527
websocket.WebSocketHandler,
2628
):

jupyter_server/services/kernels/websocket.py

+7-1
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,12 @@ def select_subprotocol(self, subprotocols):
9090
preferred_protocol = "v1.kernel.websocket.jupyter.org"
9191
elif preferred_protocol == "":
9292
preferred_protocol = None
93-
selected_subprotocol = preferred_protocol if preferred_protocol in subprotocols else None
93+
94+
# super() subprotocol enables token authentication via subprotocol
95+
selected_subprotocol = (
96+
preferred_protocol
97+
if preferred_protocol in subprotocols
98+
else super().select_subprotocol(subprotocols)
99+
)
94100
# None is the default, "legacy" protocol
95101
return selected_subprotocol

tests/base/test_websocket.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -149,10 +149,11 @@ async def test_websocket_token_subprotocol_auth(jp_serverapp, jp_ws_fetch):
149149
"ws",
150150
headers={
151151
"Authorization": "",
152-
"Sec-WebSocket-Protocol": "v1.kernel.websocket.jupyter.org, v1.token.websocket.jupyter.org."
152+
"Sec-WebSocket-Protocol": "v1.kernel.websocket.jupyter.org, v1.token.websocket.jupyter.org, v1.token.websocket.jupyter.org."
153153
+ token,
154154
},
155155
)
156+
assert ws.protocol.selected_subprotocol == "v1.token.websocket.jupyter.org"
156157
ws.close()
157158

158159

0 commit comments

Comments
 (0)