Commit Graph

20 Commits

Author SHA1 Message Date
Damien Arrachequesne
c310b7b6b6 refactor: improve types 2024-06-21 14:03:01 +02:00
Damien Arrachequesne
6b9e3e458e refactor: improve types 2024-06-18 17:37:12 +02:00
Damien Arrachequesne
43c1c1c1e2 refactor: simplify code 2023-11-09 12:13:15 +01: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
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
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
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
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
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
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
bc98bf1232 refactor: bump prettier to version 2.8.1
This major bump creates a lot of noise, but it is necessary for
prettier to be able to parse new syntax such as:

- typed imports: `import { type xxx } from ...`
- private attributes: `class A { #b; #c() {} }`
2023-01-10 15:22:57 +01:00
iifawzi
d0fd4746af feat: add the "addTrailingSlash" option (#655)
The "addTrailingSlash" option allows to control whether a trailing
slash is added to the path of the HTTP requests:

- true (default): "/engine.io/"
- false: "/engine.io"

Related: 21a6e1219a

Signed-off-by: iifawzi <iifawzie@gmail.com>
2023-01-10 14:51:31 +01:00
Jonathan Neve
425e833ab1 fix: catch errors when destroying invalid upgrades (#658)
Before this change, receiving an HTTP2 upgrade would make the server
crash:

> Error: read ECONNRESET
>    at TCP.onStreamRead (node:internal/stream_base_commons:217:20) {
>  errno: -104,
>  code: 'ECONNRESET',
>  syscall: 'read'
> }

This can be reproduced with Node.js v14.15.3, v16.18.1 and v18.12.1.
2022-11-20 01:55:11 +01:00
Lam Wei Li
917d1d29e1 refactor: replace deprecated String.prototype.substr() (#646)
`.substr()` is deprecated so we replace it with `.slice()` which works
similarily but isn't deprecated.

See also: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/substr

Signed-off-by: Lam Wei Li <peteriman@mail.com>
2022-06-06 08:42:45 +02:00
Jeffrey van Norden
a463d268ed fix(typings): allow CorsOptionsDelegate as cors options (#641)
Reference: https://www.npmjs.com/package/cors#configuring-cors-asynchronously

Related: 54a59cd8f0
2022-02-17 06:36:49 +01:00
Damien Arrachequesne
8b4d6a8176 fix(uws): handle invalid websocket upgrades
When binding to an uWebSockets.js App, there was an unhandled case that
could crash the server:

```
curl "http://localhost:3000/engine.io/?EIO=4&transport=websocket"
```

would result in:

```
Error: Returning from a request handler without responding or attaching an abort handler is forbidden!
terminate called without an active exception
```

Note: this does not apply to the default server based on ws, because
the error was caught elsewhere in the source code.

Related: https://github.com/socketio/socket.io/issues/4250
2022-01-14 08:18:03 +01:00
Damien Arrachequesne
c0e194d449 fix: properly handle invalid data sent by a malicious websocket client
**IMPORTANT SECURITY FIX**

A malicious client could send a specially crafted HTTP request,
triggering an uncaught exception and killing the Node.js process:

> RangeError: Invalid WebSocket frame: RSV2 and RSV3 must be clear
>   at Receiver.getInfo (/.../node_modules/ws/lib/receiver.js:176:14)
>   at Receiver.startLoop (/.../node_modules/ws/lib/receiver.js:136:22)
>   at Receiver._write (/.../node_modules/ws/lib/receiver.js:83:10)
>   at writeOrBuffer (internal/streams/writable.js:358:12)

This bug was introduced by [1], included in `engine.io@4.0.0`, so
previous releases are not impacted.

[1]: f3c291fa61

Thanks to Marcus Wejderot from Mevisio for the responsible disclosure.
2022-01-11 15:52:15 +01:00
Damien Arrachequesne
271e2df94d feat: add an implementation based on uWebSockets.js
```js
const { App } = require("uWebSockets.js");
const { uServer } = require("engine.io");

const app = new App();
const server = new uServer();

server.attach(app);

app.listen(3000);
```

Reference: https://github.com/uNetworking/uWebSockets.js

Related: https://github.com/socketio/engine.io/issues/578
2021-11-02 22:46:09 +01:00
Damien Arrachequesne
c0d6eaa1ba chore: migrate to TypeScript
Related: https://github.com/socketio/engine.io/issues/510
2021-10-08 14:55:30 +02:00