Open Bug 2051402 Opened 2 months ago Updated 1 month ago

half-upgraded websocket connections starve connection pool

Categories

(Core :: Networking: HTTP, defect, P2)

Firefox 152
defect

Tracking

()

People

(Reporter: kappaloris, Unassigned)

References

(Blocks 1 open bug)

Details

(Whiteboard: [necko-triaged])

User Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:152.0) Gecko/20100101 Firefox/152.0

Steps to reproduce:

  1. Write a simple HTTP/1.1 web server that serves two endpoints: one that serves a hello world page, and one that offers a websocket upgrade.
  2. have the hello world page contain a script element that tries to setup the websocket connection on page load
  3. The websocket endpoint in the web server should read but NOT REPLY to the client with an upgrade confirmation, effectively leaving the upgrade pending.
  4. Reload the page multiple times and observe the tab eventually get stuck trying to load the page forever, and how closing and reopening the tab doesn't solve the situation.

Alternatively, download the appropriate artifact from here: https://github.com/kristoff-it/zine/releases/tag/v0.11.3

Then in an empty directory run in order:

$ zine init
$ zine

This will start a webserver on localhost that exposes the same problematic behavior explained above. Click a few links on the website (or reload the page a few times) and observe Firefox get stuck loading forever after a few clicks.

Actual results:

My understanding is that half-upgraded (i.e. after having sent the upgrade request but before having received confirmation) connections are still considered active HTTP/1.1 connections and thus are not killed on page reload. This causes the connection pool to fill with essentially broken connections, ultimately making it impossible for any request to be fulfilled correctly.

This situation is without a doubt caused primarily by a misbehaving server, but the fact that users experience a severely degraded client-side experience is in my opinion reason enough to adjust client behavior.

To provide some context on how this can happen in the real world, I maintain a static site generator that has its own development webserver for hot-reloading pages on rebuild. I forgot a call to flush on upgrade confirmation, resulting in the situation explained above only when the websocket connection did not have any other data to send (e.g. when the user would open the page and then navigate their site preview without modifying any source file). Firefox users were reporting the browser behaving weirdly, while Chrome users were not affected by this issue.

Expected results:

When reloading a tab firefox should close half-upgraded websocket connections, just like it already does with fully upgraded ones.

Summary: Websocket handshake hang starves connection pool on reload → half-upgraded websocket connections starve connection pool

The Bugbug bot thinks this bug should belong to the 'Core::Networking: HTTP' component, and is moving the bug to that component. Please correct in case you think the bot is wrong.

Component: Untriaged → Networking: HTTP
Product: Firefox → Core

Thank you for the excellent report - the clear STR plus a ready-to-run repro (the zine dev server) makes this easy to act on, and the root-cause framing is really helpful.

Half-upgraded WebSocket connections (upgrade sent, no server confirmation) staying in the pool as active HTTP/1.1 connections and not being torn down on reload, eventually starving the connection pool, looks like a legitimate client robustness gap - even though a misbehaving server triggers it. Tracking it for investigation on that basis.

Thanks for digging into the cause and for the cross-browser note.

Severity: -- → S3
Status: UNCONFIRMED → NEW
Ever confirmed: true
Priority: -- → P2
Whiteboard: [necko-triaged]
You need to log in before you can comment on or make changes to this bug.