-
Notifications
You must be signed in to change notification settings - Fork 9
SG-43089 Handle Chrome LNA WebSocket preflight in ServerProtocol #347
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
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -124,6 +124,94 @@ def onConnect(self, response): | |||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.info("Connection accepted.") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| self._wss_key = response.headers["sec-websocket-key"] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def dataReceived(self, data): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Override dataReceived to intercept Chrome's Local Network Access preflight | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| requests before Autobahn's WebSocket handshake processing. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Chrome 147+ sends an HTTP OPTIONS preflight with | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Access-Control-Request-Private-Network: true before attempting a WebSocket | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| connection to a local network address (e.g. localhost). | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if data.startswith(b"OPTIONS "): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| self._handle_lna_preflight(data) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| super().dataReceived(data) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+136
to
+140
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if data.startswith(b"OPTIONS "): | |
| self._handle_lna_preflight(data) | |
| return | |
| super().dataReceived(data) | |
| if getattr(self, "_initial_http_request_routed", False): | |
| super().dataReceived(data) | |
| return | |
| buffered_data = getattr(self, "_initial_http_header_buffer", b"") + data | |
| self._initial_http_header_buffer = buffered_data | |
| header_end = buffered_data.find(b"\r\n\r\n") | |
| if header_end == -1: | |
| return | |
| header_end += 4 | |
| headers = buffered_data[:header_end] | |
| remainder = buffered_data[header_end:] | |
| self._initial_http_request_routed = True | |
| self._initial_http_header_buffer = b"" | |
| if headers.startswith(b"OPTIONS "): | |
| self._handle_lna_preflight(headers) | |
| return | |
| super().dataReceived(headers + remainder) |
Copilot
AI
Apr 28, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The preflight response does not take Access-Control-Request-Method / Access-Control-Request-Headers into account. Many user agents require Access-Control-Allow-Methods to include the requested method and Access-Control-Allow-Headers to include (or correctly wildcard) the requested headers; Access-Control-Allow-Headers: * is not consistently accepted for preflight across implementations/versions. To avoid Chrome still rejecting the preflight, parse Access-Control-Request-Method and Access-Control-Request-Headers and echo/permit those values in the corresponding Access-Control-Allow-* headers.
Copilot
AI
Apr 28, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The preflight response does not take Access-Control-Request-Method / Access-Control-Request-Headers into account. Many user agents require Access-Control-Allow-Methods to include the requested method and Access-Control-Allow-Headers to include (or correctly wildcard) the requested headers; Access-Control-Allow-Headers: * is not consistently accepted for preflight across implementations/versions. To avoid Chrome still rejecting the preflight, parse Access-Control-Request-Method and Access-Control-Request-Headers and echo/permit those values in the corresponding Access-Control-Allow-* headers.
Copilot
AI
Apr 28, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For a 405 response, RFC-compliant behavior is to include an Allow: header indicating permitted methods (e.g., Allow: GET). Adding it makes the response more standards-aligned and easier to diagnose with intermediaries/tools.
| b"HTTP/1.1 405 Method Not Allowed\r\nContent-Length: 0\r\n\r\n" | |
| b"HTTP/1.1 405 Method Not Allowed\r\n" | |
| b"Allow: GET\r\n" | |
| b"Content-Length: 0\r\n" | |
| b"\r\n" |
Copilot
AI
Apr 28, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The preflight response does not take Access-Control-Request-Method / Access-Control-Request-Headers into account. Many user agents require Access-Control-Allow-Methods to include the requested method and Access-Control-Allow-Headers to include (or correctly wildcard) the requested headers; Access-Control-Allow-Headers: * is not consistently accepted for preflight across implementations/versions. To avoid Chrome still rejecting the preflight, parse Access-Control-Request-Method and Access-Control-Request-Headers and echo/permit those values in the corresponding Access-Control-Allow-* headers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dataReceived()is not message-framed; Twisted may deliver only part of the HTTP request line/headers in the first call. If the first chunk doesn’t start withb\"OPTIONS \"(e.g., it starts withb\"OP\"), the code will fall through to Autobahn and likely break the handshake. Consider buffering until you have at least a full request line (ending in\\r\\n) and ideally until the end-of-headers marker (\\r\\n\\r\\n) before deciding whether to route to_handle_lna_preflight()vssuper().dataReceived().