fix(lan-share): carry app WebSockets, only divert Vite's HMR socket#657
Merged
Merged
Conversation
The LAN share proxy diverted every WebSocket upgrade to the active Vite
dev server whenever one was known. During a normal Laravel dev session
(npm run dev running for HMR), that hijacked application sockets too:
Reverb's /app/<key> and noVNC's /websockify went to Vite, which does not
speak their protocol, so the handshake hung (curl http_code=000) while
plain HTTP pages kept loading.
Only Vite's HMR client connects to the bare origin ("/?token=..."), so
gate the diversion on that path. Application sockets carry a real path
and now fall through to the main proxy, where httputil.ReverseProxy
upgrades them natively, exactly like the site's own nginx vhost.
Fixes lerd-env#656.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
lerd lan:shareforwarded plain HTTP fine but dropped WebSocket upgrades for LAN clients: a WS handshake hung (curl http_code=000, full timeout) while the identical request straight to the site's nginx vhost returned101 Switching Protocols. Reverb's/app/<key>and a noVNC/websockifyendpoint both reproduced it (#656).Root cause
The share handler diverted every WebSocket upgrade to the active Vite dev server whenever one was known:
During a normal Laravel dev session (
npm run devrunning for HMR),activeVitePortis set, so application sockets were hijacked to Vite. Vite does not speak Reverb's or noVNC's protocol, so the handshake hangs. The main proxy path (httputil.ReverseProxyto nginx) carries WebSockets natively and was never the problem, it just never got the chance to run.Fix
Only Vite's HMR client connects to the bare origin (
/?token=...). Gate the diversion on that, so application sockets (which carry a real path) fall through to the main proxy and get upgraded by nginx exactly like its own vhost.Verification
Added an end-to-end test (
lanshare_ws_e2e_test.go) that runs the reallanShareHandler+httputil.ReverseProxyand performs a raw WS handshake:101), confirming that path was always WS-capable./app/<key>and/websockifystill reach the main proxy and upgrade, while Vite's HMR socket (/) still routes to Vite.The Vite-active test fails on
main(the app socket is answered by the Vite stand-in) and passes with this change. Fullinternal/clilan-share suite green;go vetclean.Note / out of scope
The secured share builds its upstream transport from
http.DefaultTransport.Clone()(ForceAttemptHTTP2=true). This is safe today because lerd's nginx never enables HTTP/2, so ALPN always settles on HTTP/1.1 and the h1 WS upgrade passes through. If HTTP/2 is ever enabled on a vhost (e.g. via acustom.dinclude), the secured share could negotiate h2 and break the upgrade. Pinning the secured transport tohttp/1.1would harden against that, but it is not needed for #656 and is left out here.Fixes #656.