Commit Graph

1186 Commits

Author SHA1 Message Date
Damien Arrachequesne
6b9e3e458e refactor: improve types 2024-06-18 17:37:12 +02:00
Damien Arrachequesne
f521cbab6d refactor: simplify the heartbeat code 2024-06-18 17:32:06 +02:00
Damien Arrachequesne
5359bae683 perf: do not reset the hearbeat timer on each packet
This behavior was added in [1]. However, there are two problems:

- a new timer is allocated every time a packet is received, which is
wasteful

- the next heartbeat is not actually delayed, since it's the timeout
timer which gets reset, and not the interval timer

Note: delaying the next heartbeat would be a breaking change.

[1]: be7b4e7478
2024-06-18 17:17:17 +02:00
Damien Arrachequesne
d3f45dca38 docs(changelog): add release notes for versions 3.6.2 and 6.5.5 2024-06-18 10:47:10 +02:00
dependabot[bot]
3c4d314998 chore(deps): bump ws from 8.11.0 to 8.17.1 (#702)
Bumps [ws](https://github.com/websockets/ws) from 8.11.0 to 8.17.1.
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/8.11.0...8.17.1)

---
updated-dependencies:
- dependency-name: ws
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-18 09:57:32 +02:00
Damien Arrachequesne
b0721e6407 ci: upgrade to actions/checkout@4 and actions/setup-node@4
Reference: https://github.blog/changelog/2023-09-22-github-actions-transitioning-from-node-16-to-node-20/
2024-06-17 17:50:39 +02:00
Damien Arrachequesne
9a68c8ce93 perf(websocket): use bound callbacks
Instead of allocating one temporary function for each WebSocket
`send()` call.

Regarding the test removal, the permessage-deflate threshold was
implemented in the "ws" package in [1], so it's not needed anymore.

[1]: 6b3904b42d
2024-06-17 17:47:46 +02:00
Damien Arrachequesne
62f59b6cf3 refactor: remove unnecessary array allocation
If the `packetsFn` array is empty, there is no need to allocate one new
array.
2024-06-14 01:07:48 +02:00
Damien Arrachequesne
407c3ad236 refactor: simplify the handling of the "drain" event
The two event handlers are merged into one.
2024-06-14 00:30:14 +02:00
Damien Arrachequesne
ef1c4c8bb7 refactor: remove the wsPreEncoded option
The wsPreEncoded option was added in the `socket.io-adapter` package
when broadcasting a message to multiple clients.

It was removed in [1] and is now superseded by the `wsPreEncodedFrame`
option, which directly computes the WebSocket frame once for all
clients (see [2]).

[1]: 88eee5948a
[2]: 5f7b47d40f
2024-06-13 23:55:16 +02:00
Damien Arrachequesne
8955eb7b75 docs(examples): add some examples to track the memory usage
Related: fc21c4a05f
2024-06-13 23:21:26 +02:00
Jonathan Perret
fc21c4a05f fix: fix websocket and webtransport send callbacks (#699)
With the `websocket` transport, the callbacks which indicate that the
packets are actually written were not properly called.

Example:

```js
socket.send("hello", () => {
  // the message has been written to the underlying transport
});
```

The bug was caused by the `websocket` transport (and `webtransport` as
well) having its `supportsFraming` property set to `true`, despite
having been changed in [1] to emit a single `drain` event for each
batch of messages written to the transport like the `polling` transport
always did. Note that although [1] is partially reverted in [2], the
new `drain` event behavior is preserved as called out in that commit's
message.

The `supportsFraming` attribute was introduced in [3] (amended by [4])
as a way to distinguish transports that emit one `drain` per message
from those that emit one `drain` per batch. Since the delivery of
`send` callbacks depends on matching `drain` events with
`transport.send` calls, that distinction is vital to correct behavior.

However, now that all transports have converged to "one `drain` per
batch" behavior, this `supportsFraming` property can be retired (and
the code for calling callbacks simplified).

[1]: https://github.com/socketio/engine.io/pull/618
[2]: a65a047526
[3]: https://github.com/socketio/engine.io/pull/130
[4]: https://github.com/socketio/engine.io/pull/132

Related: https://github.com/socketio/engine.io/issues/698
2024-06-13 23:02:22 +02:00
dependabot[bot]
79ea52dc09 chore(deps): bump express from 4.18.2 to 4.19.2 in /examples/latency (#700)
Bumps [express](https://github.com/expressjs/express) from 4.18.2 to 4.19.2.
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/master/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.18.2...4.19.2)

---
updated-dependencies:
- dependency-name: express
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-29 10:29:47 +01:00
Jonathan Perret
0efa04b584 fix(types): make socket.request writable (#697)
Related: https://github.com/socketio/engine.io/issues/696
2024-02-23 10:21:43 +01:00
Damien Arrachequesne
ff0fbfb61f chore(release): 6.5.4
Diff: https://github.com/socketio/engine.io/compare/6.5.3...6.5.4
2023-11-09 18:07:45 +01:00
Damien Arrachequesne
09acb177a6 ci: add Node.js 20 in the test matrix
Reference: https://github.com/nodejs/Release
2023-11-09 18:04:07 +01:00
Damien Arrachequesne
39937f8f4d refactor: minor cleanups 2023-11-09 12:18:55 +01:00
Damien Arrachequesne
43c1c1c1e2 refactor: simplify code 2023-11-09 12:13:15 +01:00
Damien Arrachequesne
3b5e79ef79 refactor: remove useless references
Those timers are only used during the upgrade, so there is no need to
keep those references in memory.
2023-11-09 12:05:38 +01:00
Damien Arrachequesne
f27a6c3501 refactor: remove useless reference
A reference to the initial IncomingMessage object (the first HTTP
request of the session) is kept in memory by default (`socket.request`),
so its attached ServerResponse object (`req.res`) would not be
garbage-collected. This will now be the case.

Note: the IncomingMessage object is needed in two cases:

- when working with the `express-session` middleware (`request.session`)
- when fetching the certificate of the client with `request.socket.getPeerCertificate()`

That's why removing it would be a breaking change.
2023-11-09 11:45:43 +01:00
Damien Arrachequesne
2da559a8fa chore(release): 6.5.3
Diff: https://github.com/socketio/engine.io/compare/6.5.2...6.5.3
2023-10-06 10:20:34 +02:00
Damien Arrachequesne
9545b44b3c refactor: add cache-control header in the polling response
This header should not be needed since the client already includes a
cache busting query parameter ("t"), but a misconfigured CDN could
ignore the query parameters and cache the server response.

Related: https://github.com/socketio/socket.io/issues/4842
2023-10-05 17:19:08 +02:00
Damien Arrachequesne
ff1c861548 fix(webtransport): properly handle abruptly closed connections
Refreshing the page with a client connected with WebTransport would
trigger the following exception:

> node:internal/process/promises:288
>            triggerUncaughtException(err, true /* fromPromise */);
>            ^
>
> [UnhandledPromiseRejection: This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason "0".] {
>   code: 'ERR_UNHANDLED_REJECTION'
> }

Related: https://github.com/socketio/engine.io/issues/688
2023-10-05 16:57:33 +02:00
Avi Vahl
c6bf8c0f57 fix: improve compatibility with node16 module resolution (#689)
Related: https://github.com/microsoft/TypeScript/issues/46770#issuecomment-966612103
2023-08-17 07:59:32 +02:00
Damien Arrachequesne
12ca32b534 chore(release): 6.5.2
Diff: https://github.com/socketio/engine.io/compare/6.5.1...6.5.2
2023-08-02 02:00:02 +02:00
Damien Arrachequesne
a306db09e8 fix(webtransport): add proper framing
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.

We will use a format inspired by the WebSocket frame:

- first bit indicates whether the payload is binary
- the next 7 bits are either:
  - 125 or less: that's the length of the payload
  - 126: the next 2 bytes represent the length of the payload
  - 127: the next 8 bytes represent the length of the payload

Reference: https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_servers#decoding_payload_length

Related:

- https://github.com/socketio/engine.io/issues/687
- https://github.com/socketio/engine.io/issues/688
2023-08-02 01:00:42 +02:00
Damien Arrachequesne
7dd1350bf9 docs: update the list of supported Node.js versions
The server uses `timeout.refresh()` (see [1]), which was added in Node.js 10.2.0.

Reference: https://nodejs.org/api/timers.html#timeoutrefresh

Related: https://github.com/socketio/engine.io/issues/686

[1]: 37474c7e67
2023-07-09 10:08:50 +02:00
Damien Arrachequesne
98915d0b61 chore(release): 6.5.1
Diff: https://github.com/socketio/engine.io/compare/6.5.0...6.5.1
2023-06-27 09:13:22 +02:00
Ben Weintraub
6dd2bc4f68 fix: prevent crash when accessing TextDecoder (#684)
The TextDecoder object was added on the global object in Node.js
v11.0.0, so older versions would throw:

> ReferenceError: TextDecoder is not defined

Reference: https://nodejs.org/api/util.html#new-textdecoderencoding-options
2023-06-27 09:01:26 +02:00
dependabot[bot]
9608781efe chore(deps): bump engine.io from 6.2.1 to 6.4.2 in /examples/latency (#678)
Bumps [engine.io](https://github.com/socketio/engine.io) from 6.2.1 to 6.4.2.
- [Release notes](https://github.com/socketio/engine.io/releases)
- [Changelog](https://github.com/socketio/engine.io/blob/main/CHANGELOG.md)
- [Commits](https://github.com/socketio/engine.io/compare/6.2.1...6.4.2)

---
updated-dependencies:
- dependency-name: engine.io
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-16 11:42:09 +02:00
Damien Arrachequesne
1f640a2a0f chore(release): 6.5.0
Diff: https://github.com/socketio/engine.io/compare/6.4.2...6.5.0
2023-06-16 11:36:09 +02:00
Damien Arrachequesne
1bfa9cd088 refactor: adapt to latest uWebSockets.js changes
Reference: https://github.com/uNetworking/uWebSockets.js/releases
2023-06-16 10:19:58 +02:00
Damien Arrachequesne
123b68c04f feat: add support for WebTransport
Reference: https://developer.mozilla.org/en-US/docs/Web/API/WebTransport
2023-06-11 09:42:45 +02:00
Sean Oxley
3144d27458 fix(uws): discard any write to an aborted uWS response (#682)
This bug only exists for polling transport connections running on top
of uWS.

If the remote client abruptly disconnects (thus aborting the request)
while the server is waiting on an asynchronous operation such as
compression, the server may attempt to write a response via the aborted
response object. This causes an uncaught exception to be thrown.
2023-05-31 14:27:40 +02:00
Damien Arrachequesne
7bd77759bd docs: update the list of CVE 2023-05-23 08:40:03 +02:00
Damien Arrachequesne
95e215387c chore(release): 6.4.2
Diff: https://github.com/socketio/engine.io/compare/6.4.1...6.4.2
2023-05-02 01:27:20 +02:00
Damien Arrachequesne
fc480b4f30 fix: prevent crash when provided with an invalid query param
A specially crafted request could lead to the following exception:

> TypeError: Cannot read properties of undefined (reading 'handlesUpgrades')
>    at Server.onWebSocket (build/server.js:515:67)

This bug was introduced in [1], released in version 5.1.0 and included
in version 4.1.0 of the `socket.io` parent package. Older versions are
not impacted.

[1]: 7096e98a02
2023-05-02 01:07:40 +02:00
Damien Arrachequesne
0141951185 refactor(types): ensure compatibility with Express middlewares
In order to prevent issues like:

> error TS2345: Argument of type 'RequestHandler<ParamsDictionary, any, any, ParsedQs, Record<string, any>>' is not assignable to parameter of type 'Middleware'.
>  Types of parameters 'req' and 'req' are incompatible.
>  Type 'IncomingMessage' is missing the following properties from type 'Request<ParamsDictionary, any, any, ParsedQs, Record<string, any>>': get, header, accepts, acceptsCharsets, and 29 more.
>
>  io.engine.use(sessionMiddleware);
                 ~~~~~~~~~~~~~~~~~

Related: https://github.com/socketio/socket.io/issues/4644

We could also have use the RequestHandler type from the
@types/express-serve-static-core package, but that would add 5 new
dependencies.

See also: https://github.com/socketio/engine.io/issues/673
2023-05-02 00:51:33 +02:00
Damien Arrachequesne
8b22162903 fix(uws): prevent crash when using with middlewares
The class used to accumulate the response headers did not expose the
exact same API as its wrapped type, which could lead to the following
error in some rare cases:

> TypeError: Cannot read properties of undefined (reading 'end')
>    at Polling.onDataRequest (build/transports-uws/polling.js:109:53)
>    at Polling.onRequest (build/transports-uws/polling.js:47:18)
>    at callback (build/userver.js:94:56)
>    at uServer.verify (build/server.js:152:9)

Related: https://github.com/socketio/socket.io/issues/4643
2023-05-02 00:50:34 +02:00
Ciel
93957828be fix: include error handling for Express middlewares (#674)
Following 24786e77c5.

Reference: https://expressjs.com/en/guide/error-handling.html
2023-05-02 00:00:47 +02:00
Damien Arrachequesne
911d0e3575 refactor: return HTTP 400 upon invalid request overlap
In both cases, the error comes from the client as it should not send
multiple concurrent requests, so a HTTP 4xx code is mandated.

Related: https://github.com/socketio/engine.io/issues/650
2023-05-01 07:42:43 +02:00
Asger Hautop Drewsen
bd6d4713b0 fix(typings): make clientsCount public (#675)
Related: https://github.com/socketio/engine.io/issues/672
2023-04-19 23:25:16 +03:00
Damien Arrachequesne
7033c0ed27 chore(release): 6.4.1
Diff: https://github.com/socketio/engine.io/compare/6.4.0...6.4.1
2023-02-20 00:54:54 +01:00
Igor Lins e Silva
6e78489486 refactor: export BaseServer class (#669)
Related: https://github.com/socketio/socket.io/issues/4621
2023-02-17 23:24:50 +01:00
Damien Arrachequesne
535b068670 docs: add upgrade event in the documentation
Reference: 898bd1c9df/lib/socket.ts (L285)

Related: https://github.com/socketio/socket.io-website/issues/369
2023-02-14 15:25:57 +01:00
Damien Arrachequesne
898bd1c9df chore(release): 6.4.0
Diff: https://github.com/socketio/engine.io/compare/6.3.1...6.4.0
2023-02-06 17:16:32 +01:00
dependabot[bot]
6220d140cc chore(deps): bump cookiejar from 2.1.2 to 2.1.4 (#667)
Bumps [cookiejar](https://github.com/bmeck/node-cookiejar) from 2.1.2 to 2.1.4.
- [Release notes](https://github.com/bmeck/node-cookiejar/releases)
- [Commits](https://github.com/bmeck/node-cookiejar/commits)

---
updated-dependencies:
- dependency-name: cookiejar
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-06 17:06:11 +01:00
Damien Arrachequesne
24786e77c5 feat: add support for Express middlewares
This commit implements middlewares at the Engine.IO level, because
Socket.IO middlewares are meant for namespace authorization and are not
executed during a classic HTTP request/response cycle.

A workaround was possible by using the allowRequest option and the
"headers" event, but this feels way cleaner and works with upgrade
requests too.

Syntax:

```js
engine.use((req, res, next) => {
  // do something

  next();
});

// with express-session
import session from "express-session";

engine.use(session({
  secret: "keyboard cat",
  resave: false,
  saveUninitialized: true,
  cookie: { secure: true }
});

// with helmet
import helmet from "helmet";

engine.use(helmet());
```

Related:

- https://github.com/socketio/engine.io/issues/668
- https://github.com/socketio/engine.io/issues/651
- https://github.com/socketio/socket.io/issues/4609
- https://github.com/socketio/socket.io/issues/3933
- a lot of other issues asking for compatibility with express-session
2023-02-06 17:01:27 +01:00
Damien Arrachequesne
4d6f4541c3 chore(release): 6.3.1
Diff: https://github.com/socketio/engine.io/compare/6.3.0...6.3.1
2023-01-12 08:23:07 +01:00
Damien Arrachequesne
69603b955a refactor: make the compress option optional
The compress option was inadvertently made mandatory in [1].

[1]: 6d87a4065a
2023-01-12 08:15:21 +01:00