Skip to content

fix(engine): avoid duplicate WriteHeader on failed websocket upgrade#172

Merged
zishang520 merged 1 commit into
zishang520:devfrom
MaxwellKuo47:fix/engine-duplicate-writeheader-upgrade
Jul 2, 2026
Merged

fix(engine): avoid duplicate WriteHeader on failed websocket upgrade#172
zishang520 merged 1 commit into
zishang520:devfrom
MaxwellKuo47:fix/engine-duplicate-writeheader-upgrade

Conversation

@MaxwellKuo47

Copy link
Copy Markdown

Fixes #171.

On a failed WebSocket upgrade the response header is written twice on the same ResponseWriter, so net/http logs http: superfluous response.WriteHeader call ... performWrite (http-context.go:214) once per failed upgrade. See #171 for the full trace.

The gorilla Upgrader.Error callback in HandleUpgrade calls http.Error(w, …) (write #1, straight to the underlying writer, bypassing HttpContext's write-once guard); the following emitAbortRequestabortRequestctx.WriteperformWrite is write #2.

Change

Removed the http.Error from the Error callback. emitAbortRequest (called right after ws.Upgrade fails) is the canonical responder — it writes the engine.io JSON error and emits connection_error — so a failed upgrade now writes the header exactly once, and clients get the proper engine.io error payload instead of gorilla's plain-text body. The WebTransport path (OnWebTransportSession) has no such callback and is unaffected.

Test

Added TestFailedUpgradeWritesHeaderOnce: it drives a failed upgrade through ServeHTTP with a ResponseWriter that counts WriteHeader calls and asserts it is called exactly once. Fails before the change (2 calls), passes after. go test -race ./... in servers/engine is green.

@MaxwellKuo47 MaxwellKuo47 force-pushed the fix/engine-duplicate-writeheader-upgrade branch from 759389c to a740a5f Compare July 1, 2026 15:56
On a failed upgrade the Upgrader.Error callback wrote the response via http.Error, then emitAbortRequest wrote it again, logging "superfluous response.WriteHeader call" on every failed upgrade. Let emitAbortRequest be the sole responder so the header is written once and the client still gets the engine.io error payload.
@MaxwellKuo47 MaxwellKuo47 force-pushed the fix/engine-duplicate-writeheader-upgrade branch from a740a5f to 3229d78 Compare July 2, 2026 01:56
@zishang520 zishang520 changed the base branch from main to dev July 2, 2026 06:02

@zishang520 zishang520 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me.

@zishang520 zishang520 merged commit a52b787 into zishang520:dev Jul 2, 2026
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Duplicate WriteHeader on failed websocket upgrade ("superfluous response.WriteHeader call")

3 participants