Skip to content

Commit

Permalink
include websocket protocol in response
Browse files Browse the repository at this point in the history
Chrome doesn't accept websocket connections if protocol is requested but not provided
  • Loading branch information
minrk committed Mar 14, 2024
1 parent 9627c7c commit 7f309b3
Show file tree
Hide file tree
Showing 4 changed files with 21 additions and 2 deletions.
10 changes: 10 additions & 0 deletions jupyter_server/base/websocket.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
"""Base websocket classes."""

from __future__ import annotations

import re
import warnings
from typing import Optional, no_type_check
Expand Down Expand Up @@ -164,3 +167,10 @@ def send_ping(self):
def on_pong(self, data):
"""Handle a pong message."""
self.last_pong = ioloop.IOLoop.current().time()

def select_subprotocol(self, subprotocols: list[str]) -> str | None:
# default subprotocol
# some clients (Chrome)
# require selected subprotocol to match one of the requested subprotocols
# otherwise connection is rejected
return "v1.token.websocket.jupyter.org"
2 changes: 2 additions & 0 deletions jupyter_server/services/events/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@

from jupyter_server.auth.decorator import authorized, ws_authenticated
from jupyter_server.base.handlers import JupyterHandler
from jupyter_server.base.websocket import WebSocketMixin

from ...base.handlers import APIHandler

AUTH_RESOURCE = "events"


class SubscribeWebsocket(
WebSocketMixin,
JupyterHandler,
websocket.WebSocketHandler,
):
Expand Down
8 changes: 7 additions & 1 deletion jupyter_server/services/kernels/websocket.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,12 @@ def select_subprotocol(self, subprotocols):
preferred_protocol = "v1.kernel.websocket.jupyter.org"
elif preferred_protocol == "":
preferred_protocol = None
selected_subprotocol = preferred_protocol if preferred_protocol in subprotocols else None

# super() subprotocol enables token authentication via subprotocol
selected_subprotocol = (
preferred_protocol
if preferred_protocol in subprotocols
else super().select_subprotocol(subprotocols)
)
# None is the default, "legacy" protocol
return selected_subprotocol
3 changes: 2 additions & 1 deletion tests/base/test_websocket.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,10 +149,11 @@ async def test_websocket_token_subprotocol_auth(jp_serverapp, jp_ws_fetch):
"ws",
headers={
"Authorization": "",
"Sec-WebSocket-Protocol": "v1.kernel.websocket.jupyter.org, v1.token.websocket.jupyter.org."
"Sec-WebSocket-Protocol": "v1.kernel.websocket.jupyter.org, v1.token.websocket.jupyter.org, v1.token.websocket.jupyter.org."
+ token,
},
)
assert ws.protocol.selected_subprotocol == "v1.token.websocket.jupyter.org"
ws.close()


Expand Down

0 comments on commit 7f309b3

Please sign in to comment.