This commit adds the ability to provide a list of transport
implementations to use when connecting to an Engine.IO server.
This can be used to use HTTP long-polling based on `fetch()`, instead
of the default implementation based on the `XMLHttpRequest` object.
```
import { Socket, Fetch, WebSocket } from "engine.io-client";
const socket = new Socket({
transports: [Fetch, WebSocket]
});
```
This is useful in some environments that do not provide a
`XMLHttpRequest` object, like Chrome extension background scripts.
> XMLHttpRequest() can't be called from a service worker, extension or
otherwise. Replace calls from your background script to
XMLHttpRequest() with calls to global fetch().
Source: https://developer.chrome.com/docs/extensions/develop/migrate/to-service-workers#replace-xmlhttprequest
Related:
- https://github.com/socketio/engine.io-client/issues/716
- https://github.com/socketio/socket.io/issues/4980
This is also useful when running the client with Deno or Bun, as it
allows to use the built-in `fetch()` method and `WebSocket` object,
instead of using the `xmlhttprequest-ssl` and `ws` Node.js packages.
Related: https://github.com/socketio/socket.io-deno/issues/12
This feature also comes with the ability to exclude the code related to
unused transports (a.k.a. "tree-shaking"):
```js
import { SocketWithoutUpgrade, WebSocket } from "engine.io-client";
const socket = new SocketWithoutUpgrade({
transports: [WebSocket]
});
```
In that case, the code related to HTTP long-polling and WebTransport
will be excluded from the final bundle.
Related: https://github.com/socketio/socket.io/discussions/4393
When setting the `tryAllTransports` option to `true`, if the first
transport (usually, HTTP long-polling) fails, then the other transports
will be tested too.
This is useful in two cases:
> when HTTP long-polling is disabled on the server, or if CORS fails
Related:
- https://github.com/socketio/engine.io-client/issues/575
- https://github.com/socketio/socket.io-client/issues/1448
> when WebSocket is tested first (`transports: ["websocket", "polling"])
Related:
- https://github.com/socketio/engine.io-client/issues/714
- https://github.com/socketio/socket.io-client/issues/1599
The only potential downside is that the connection attempt could take
more time in case of failure, as there have been reports of WebSocket
connection errors taking several seconds before being detected (that's
one reason for using HTTP long-polling first). That's why the option
defaults to `false` for now.
The regular expression used to parse the URL provided by the user has a
time complexity of O(n^2), hence the length limitation.
Please note that this does not seem realistically exploitable, as an
attacker would have to be able to provide a malicious URL to the user
and inject it in the Engine.IO client.
We could also have:
- modified the regex, but there are a lot of edge cases and the current test coverage is probably not sufficient
- use the built-in URL object, but we would have to add a polyfill for old platforms like IE
Thanks to Young-jin Hwang from the Soonchunhyang University for the
responsible disclosure.
The Node.js client will now properly receive binary data as Buffers
instead of ArrayBuffers, when connecting with WebTransport. Browser
clients will still receive ArrayBuffers though (or Blobs, if
`socket.binaryType` is set to "blob").
WebTransport being a stream-based protocol, the chunking boundaries are
not necessarily preserved. That's why we need a header indicating the
type of the payload (plain text or binary) and its length.
See also: a306db09e8
This commit ensures that when there are multiple possible upgrades
(like WebSocket and WebTransport), then the WebTransport is favored and
the other upgrades are delayed.
Following 7195c0f305
When setting the `withCredentials` option to `true`, the Node.js client
will now include the cookies in the HTTP requests, making it easier to
use it with cookie-based sticky sessions.
Related: https://github.com/socketio/socket.io/issues/3812
For some reason, "import { type A }" does not work in some cases:
> node_modules/engine.io-client/build/esm/socket.d.ts:2:15 - error TS1005: ',' expected.
> 2 import { type Packet, type BinaryType, RawData } from "engine.io-parser";
References: https://www.typescriptlang.org/docs/handbook/modules.html#importing-types