Skip to content

fix(socketio): latch connectionRejected and switch handshake scheme - #406

Open
RobertoReale wants to merge 1 commit into
overleaf-workshop:masterfrom
RobertoReale:fix/handshake-rejection-latch
Open

fix(socketio): latch connectionRejected and switch handshake scheme#406
RobertoReale wants to merge 1 commit into
overleaf-workshop:masterfrom
RobertoReale:fix/handshake-rejection-latch

Conversation

@RobertoReale

Copy link
Copy Markdown

Fixes #234
Refs #380, refs #351 — both report the same log line, SocketIOAPI: connectionRejected. missing/bad ?projectId=... query flag on handshake, whose cause is fixed here; whether it accounts for the whole of #380 (the "Open Project Locally" dialog not appearing) I cannot say.

Problem

On overleaf.com the socket.io handshake is only accepted with the ?projectId=... query flag (scheme v2). With the plain handshake (v1) the socket connects and is then rejected with connectionRejected.

The socket is created by the SocketIOAPI constructor, so that rejection normally arrives before joinProject is ever called. The fallback logic lives in a listener registered inside joinProject, which therefore never sees the event: the scheme is never switched, the socket stays in the rejected state, and every later operation only fails through its 5 s timeout — the user sees a spinning compile, or Unable to write file ... (timeout) on save.

Trace from a run against overleaf.com, before this change:

SocketIOAPI: connected
SocketIOAPI: connectionRejected. missing/bad ?projectId=... query flag on handshake
SocketIOAPI: connected
SocketIOAPI: connectionRejected. missing/bad ?projectId=... query flag on handshake
… (loop)

A second detail: the existing code disables auto-reconnect through this.socket.io.reconnect(false), which is the socket.io-client >= 1.x API. The extension bundles 0.9.17-overleaf-5, where this.socket is a SocketNamespace and the flag lives in this.socket.socket.options.reconnect, so the call is a no-op and the rejected socket keeps reconnecting.

Change

In the connectionRejected handler, i.e. where the event is actually received:

  • latch the rejection in _connectionRejected, and let needsReinit report that the socket must be recreated;
  • track the schemes already rejected (_rejectedSchemes), so v1 falls back to v2 and v2 back to v1 without ping-ponging between them; the set is cleared once a join succeeds;
  • fail any in-flight joinProject immediately through _rejectionWaiters, and reject a later joinProject right away if the rejection is already latched, instead of waiting 5 s for the timeout;
  • disable auto-reconnect through stopAutoReconnect(), which handles both the 0.9.x namespace and the >= 1.x manager.

joinProject no longer registers its own connectionRejected listener (one per call, never removed).

Verification

Against overleaf.com with a real project, 0.15.10 + this patch: v1 is rejected once, the client switches to v2, joinProjectResponse arrives, and opening files, editing and saving work. I could not test a self-hosted instance that only accepts v1; that direction of the fallback is symmetric in the code but untested by me.

Possibly related, but not verified by me: #399.

On overleaf.com the socket.io handshake is only accepted with the
`?projectId=...` query flag (scheme v2). The plain handshake (v1) connects and
is then rejected with `connectionRejected`.

The socket is created by the `SocketIOAPI` constructor, so that rejection
normally arrives *before* `joinProject` is called: the listener registered
inside `joinProject` never sees it, the scheme is never switched, and every
later operation fails with a 5s timeout (`Unable to write file ... (timeout)`).

Handle the event where it is actually received:
- latch the rejection in `_connectionRejected` and let `needsReinit` report
  that the socket must be recreated;
- track which schemes were rejected, so v1 falls back to v2 and v2 back to v1
  without ping-ponging;
- fail any in-flight and any subsequent `joinProject` immediately instead of
  waiting for the timeout;
- disable auto-reconnect through `stopAutoReconnect()`, which also works on
  socket.io-client 0.9.x (the bundled version), where the reconnect flag lives
  in `socket.socket.options` and not in `socket.io`;
- clear the rejected-scheme set once a join succeeds.
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.

Compilation hangs indefinitely with both simple and complex documents

1 participant