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.
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
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
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
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
This reverts commit [1], which was included in `engine.io@5.1.0` and
`socket.io@4.1.0`.
The WebSocket connection was closed before all packets were written
out, so for example when calling `socket.disconnect(true)` on the
Socket.IO server (which disconnect from all namespaces and close the
connection), the client would receive only the first disconnect packet
and kept trying to reconnect to the other namespaces.
The only difference with the previous implementation (pre 5.1.0) is
that the "drain" event gets only called once at the end, and not after
each packet.
[1]: ad5306aeae
Related: https://github.com/socketio/engine.io/issues/648
The package does not have a default export, so importing it from a
project using ES modules would break in some cases.
> Cannot destructure property 'Server' of '_engineIo.default'
Related: https://github.com/socketio/engine.io/issues/657
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() {} }`
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>
This optimization is only applied if:
- the permessage-deflate extension is disabled (which is the default)
- the "ws" package is used (which is the default)
In that case, the WebSocket frame will only be computed once, when
broadcasting to multiple clients.
Related: 5f7b47d40f
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.
A few notes:
- the certificates were recreated because Node.js 18 includes OpenSSL
v3, which has deprecated support for some legacy ciphers (like RC2)
- eiows currently fails to build on Node.js 18, so the tests are
temporarily skipped
See also: https://github.com/nodejs/Release