Socket
Socket
Sign inDemoInstall

engine.io

Package Overview
Dependencies
20
Maintainers
2
Versions
147
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 6.3.1 to 6.4.0

46

build/server.d.ts
/// <reference types="node" />
import { EventEmitter } from "events";
import { IncomingMessage, Server as HttpServer } from "http";
import { CookieSerializeOptions } from "cookie";
import { CorsOptions, CorsOptionsDelegate } from "cors";
import type { IncomingMessage, Server as HttpServer, ServerResponse } from "http";
import type { CookieSerializeOptions } from "cookie";
import type { CorsOptions, CorsOptionsDelegate } from "cors";
import type { Duplex } from "stream";
declare type Transport = "polling" | "websocket";

@@ -107,2 +108,11 @@ export interface AttachOptions {

}
/**
* An Express-compatible middleware.
*
* Middleware functions are functions that have access to the request object (req), the response object (res), and the
* next middleware function in the application’s request-response cycle.
*
* @see https://expressjs.com/en/guide/using-middleware.html
*/
declare type Middleware = (req: IncomingMessage, res: ServerResponse, next: () => void) => void;
export declare abstract class BaseServer extends EventEmitter {

@@ -112,3 +122,3 @@ opts: ServerOptions;

private clientsCount;
protected corsMiddleware: Function;
protected middlewares: Middleware[];
/**

@@ -144,2 +154,22 @@ * Server constructor.

/**
* Adds a new middleware.
*
* @example
* import helmet from "helmet";
*
* engine.use(helmet());
*
* @param fn
*/
use(fn: Middleware): void;
/**
* Apply the middlewares to the request.
*
* @param req
* @param res
* @param callback
* @protected
*/
protected _applyMiddlewares(req: IncomingMessage, res: ServerResponse, callback: () => void): void;
/**
* Closes all clients.

@@ -210,7 +240,7 @@ *

*
* @param {http.IncomingMessage} request
* @param {http.ServerResponse|http.OutgoingMessage} response
* @param {IncomingMessage} req
* @param {ServerResponse} res
* @api public
*/
handleRequest(req: any, res: any): void;
handleRequest(req: IncomingMessage, res: ServerResponse): void;
/**

@@ -221,3 +251,3 @@ * Handles an Engine.IO HTTP Upgrade.

*/
handleUpgrade(req: any, socket: any, upgradeHead: any): void;
handleUpgrade(req: IncomingMessage, socket: Duplex, upgradeHead: Buffer): void;
/**

@@ -224,0 +254,0 @@ * Called upon a ws.io connection.

129

build/server.js

@@ -14,2 +14,3 @@ "use strict";

const debug = (0, debug_1.default)("engine");
const kResponseHeaders = Symbol("responseHeaders");
class BaseServer extends events_1.EventEmitter {

@@ -24,2 +25,3 @@ /**

super();
this.middlewares = [];
this.clients = {};

@@ -51,3 +53,3 @@ this.clientsCount = 0;

if (this.opts.cors) {
this.corsMiddleware = require("cors")(this.opts.cors);
this.use(require("cors")(this.opts.cors));
}

@@ -156,2 +158,41 @@ if (opts.perMessageDeflate) {

/**
* Adds a new middleware.
*
* @example
* import helmet from "helmet";
*
* engine.use(helmet());
*
* @param fn
*/
use(fn) {
this.middlewares.push(fn);
}
/**
* Apply the middlewares to the request.
*
* @param req
* @param res
* @param callback
* @protected
*/
_applyMiddlewares(req, res, callback) {
if (this.middlewares.length === 0) {
debug("no middleware to apply, skipping");
return callback();
}
const apply = (i) => {
debug("applying middleware n°%d", i + 1);
this.middlewares[i](req, res, () => {
if (i + 1 < this.middlewares.length) {
apply(i + 1);
}
else {
callback();
}
});
};
apply(0);
}
/**
* Closes all clients.

@@ -299,2 +340,31 @@ *

};
/**
* Exposes a subset of the http.ServerResponse interface, in order to be able to apply the middlewares to an upgrade
* request.
*
* @see https://nodejs.org/api/http.html#class-httpserverresponse
*/
class WebSocketResponse {
constructor(req, socket) {
this.req = req;
this.socket = socket;
// temporarily store the response headers on the req object (see the "headers" event)
req[kResponseHeaders] = {};
}
setHeader(name, value) {
this.req[kResponseHeaders][name] = value;
}
getHeader(name) {
return this.req[kResponseHeaders][name];
}
removeHeader(name) {
delete this.req[kResponseHeaders][name];
}
write() { }
writeHead() { }
end() {
// we could return a proper error code, but the WebSocket client will emit an "error" event anyway.
this.socket.destroy();
}
}
class Server extends BaseServer {

@@ -321,3 +391,4 @@ /**

// we could also try to parse the array and then sync the values, but that will be error-prone
const additionalHeaders = {};
const additionalHeaders = req[kResponseHeaders] || {};
delete req[kResponseHeaders];
const isInitialRequest = !req._query.sid;

@@ -328,2 +399,3 @@ if (isInitialRequest) {

this.emit("headers", additionalHeaders, req);
debug("writing headers: %j", additionalHeaders);
Object.keys(additionalHeaders).forEach((key) => {

@@ -359,4 +431,4 @@ headersArray.push(`${key}: ${additionalHeaders[key]}`);

*
* @param {http.IncomingMessage} request
* @param {http.ServerResponse|http.OutgoingMessage} response
* @param {IncomingMessage} req
* @param {ServerResponse} res
* @api public

@@ -367,2 +439,3 @@ */

this.prepare(req);
// @ts-ignore
req.res = res;

@@ -380,4 +453,6 @@ const callback = (errorCode, errorContext) => {

}
// @ts-ignore
if (req._query.sid) {
debug("setting new request for existing client");
// @ts-ignore
this.clients[req._query.sid].transport.onRequest(req);

@@ -387,13 +462,9 @@ }

const closeConnection = (errorCode, errorContext) => abortRequest(res, errorCode, errorContext);
// @ts-ignore
this.handshake(req._query.transport, req, closeConnection);
}
};
if (this.corsMiddleware) {
this.corsMiddleware.call(null, req, res, () => {
this.verify(req, false, callback);
});
}
else {
this._applyMiddlewares(req, res, () => {
this.verify(req, false, callback);
}
});
}

@@ -407,18 +478,24 @@ /**

this.prepare(req);
this.verify(req, true, (errorCode, errorContext) => {
if (errorCode) {
this.emit("connection_error", {
req,
code: errorCode,
message: Server.errorMessages[errorCode],
context: errorContext,
const res = new WebSocketResponse(req, socket);
this._applyMiddlewares(req, res, () => {
this.verify(req, true, (errorCode, errorContext) => {
if (errorCode) {
this.emit("connection_error", {
req,
code: errorCode,
message: Server.errorMessages[errorCode],
context: errorContext,
});
abortUpgrade(socket, errorCode, errorContext);
return;
}
const head = Buffer.from(upgradeHead);
upgradeHead = null;
// some middlewares (like express-session) wait for the writeHead() call to flush their headers
// see https://github.com/expressjs/session/blob/1010fadc2f071ddf2add94235d72224cf65159c6/index.js#L220-L244
res.writeHead();
// delegate to ws
this.ws.handleUpgrade(req, socket, head, (websocket) => {
this.onWebSocket(req, socket, websocket);
});
abortUpgrade(socket, errorCode, errorContext);
return;
}
const head = Buffer.from(upgradeHead);
upgradeHead = null;
// delegate to ws
this.ws.handleUpgrade(req, socket, head, (websocket) => {
this.onWebSocket(req, socket, websocket);
});

@@ -425,0 +502,0 @@ });

@@ -35,2 +35,3 @@ import { AttachOptions, BaseServer } from "./server";

attach(app: any, options?: AttachOptions & uOptions): void;
_applyMiddlewares(req: any, res: any, callback: () => void): void;
private handleRequest;

@@ -37,0 +38,0 @@ private handleUpgrade;

@@ -18,2 +18,3 @@ "use strict";

req.method = req.getMethod().toUpperCase();
req.url = req.getUrl();
const params = new URLSearchParams(req.getQuery());

@@ -64,2 +65,15 @@ req._query = Object.fromEntries(params.entries());

}
_applyMiddlewares(req, res, callback) {
if (this.middlewares.length === 0) {
return callback();
}
// needed to buffer headers until the status is computed
req.res = new ResponseWrapper(res);
super._applyMiddlewares(req, req.res, () => {
// some middlewares (like express-session) wait for the writeHead() call to flush their headers
// see https://github.com/expressjs/session/blob/1010fadc2f071ddf2add94235d72224cf65159c6/index.js#L220-L244
req.res.writeHead();
callback();
});
}
handleRequest(res, req) {

@@ -69,32 +83,24 @@ debug('handling "%s" http request "%s"', req.getMethod(), req.getUrl());

req.res = res;
const callback = (errorCode, errorContext) => {
if (errorCode !== undefined) {
this.emit("connection_error", {
req,
code: errorCode,
message: server_1.Server.errorMessages[errorCode],
context: errorContext,
});
this.abortRequest(req.res, errorCode, errorContext);
return;
}
if (req._query.sid) {
debug("setting new request for existing client");
this.clients[req._query.sid].transport.onRequest(req);
}
else {
const closeConnection = (errorCode, errorContext) => this.abortRequest(res, errorCode, errorContext);
this.handshake(req._query.transport, req, closeConnection);
}
};
if (this.corsMiddleware) {
// needed to buffer headers until the status is computed
req.res = new ResponseWrapper(res);
this.corsMiddleware.call(null, req, req.res, () => {
this.verify(req, false, callback);
this._applyMiddlewares(req, res, () => {
this.verify(req, false, (errorCode, errorContext) => {
if (errorCode !== undefined) {
this.emit("connection_error", {
req,
code: errorCode,
message: server_1.Server.errorMessages[errorCode],
context: errorContext,
});
this.abortRequest(req.res, errorCode, errorContext);
return;
}
if (req._query.sid) {
debug("setting new request for existing client");
this.clients[req._query.sid].transport.onRequest(req);
}
else {
const closeConnection = (errorCode, errorContext) => this.abortRequest(res, errorCode, errorContext);
this.handshake(req._query.transport, req, closeConnection);
}
});
}
else {
this.verify(req, false, callback);
}
});
}

@@ -104,46 +110,49 @@ handleUpgrade(res, req, context) {

this.prepare(req, res);
// @ts-ignore
req.res = res;
this.verify(req, true, async (errorCode, errorContext) => {
if (errorCode) {
this.emit("connection_error", {
req,
code: errorCode,
message: server_1.Server.errorMessages[errorCode],
context: errorContext,
});
this.abortRequest(res, errorCode, errorContext);
return;
}
const id = req._query.sid;
let transport;
if (id) {
const client = this.clients[id];
if (!client) {
debug("upgrade attempt for closed client");
res.close();
this._applyMiddlewares(req, res, () => {
this.verify(req, true, async (errorCode, errorContext) => {
if (errorCode) {
this.emit("connection_error", {
req,
code: errorCode,
message: server_1.Server.errorMessages[errorCode],
context: errorContext,
});
this.abortRequest(res, errorCode, errorContext);
return;
}
else if (client.upgrading) {
debug("transport has already been trying to upgrade");
res.close();
const id = req._query.sid;
let transport;
if (id) {
const client = this.clients[id];
if (!client) {
debug("upgrade attempt for closed client");
res.close();
}
else if (client.upgrading) {
debug("transport has already been trying to upgrade");
res.close();
}
else if (client.upgraded) {
debug("transport had already been upgraded");
res.close();
}
else {
debug("upgrading existing transport");
transport = this.createTransport(req._query.transport, req);
client.maybeUpgrade(transport);
}
}
else if (client.upgraded) {
debug("transport had already been upgraded");
res.close();
}
else {
debug("upgrading existing transport");
transport = this.createTransport(req._query.transport, req);
client.maybeUpgrade(transport);
transport = await this.handshake(req._query.transport, req, (errorCode, errorContext) => this.abortRequest(res, errorCode, errorContext));
if (!transport) {
return;
}
}
}
else {
transport = await this.handshake(req._query.transport, req, (errorCode, errorContext) => this.abortRequest(res, errorCode, errorContext));
if (!transport) {
return;
}
}
res.upgrade({
transport,
}, req.getHeader("sec-websocket-key"), req.getHeader("sec-websocket-protocol"), req.getHeader("sec-websocket-extensions"), context);
// calling writeStatus() triggers the flushing of any header added in a middleware
req.res.writeStatus("101 Switching Protocols");
res.upgrade({
transport,
}, req.getHeader("sec-websocket-key"), req.getHeader("sec-websocket-protocol"), req.getHeader("sec-websocket-extensions"), context);
});
});

@@ -174,7 +183,24 @@ }

set statusCode(status) {
if (!status) {
return;
}
// FIXME: handle all status codes?
this.writeStatus(status === 200 ? "200 OK" : "204 No Content");
}
writeHead(status) {
this.statusCode = status;
}
setHeader(key, value) {
this.writeHeader(key, value);
if (Array.isArray(value)) {
value.forEach((val) => {
this.writeHeader(key, val);
});
}
else {
this.writeHeader(key, value);
}
}
removeHeader() {
// FIXME: not implemented
}
// needed by vary: https://github.com/jshttp/vary/blob/5d725d059b3871025cf753e9dfa08924d0bcfa8f/index.js#L134

@@ -181,0 +207,0 @@ getHeader() { }

{
"name": "engine.io",
"version": "6.3.1",
"version": "6.4.0",
"description": "The realtime engine behind Socket.IO. Provides the foundation of a bidirectional connection between client and server",

@@ -48,5 +48,7 @@ "type": "commonjs",

"eiows": "^4.1.2",
"engine.io-client": "6.3.0",
"engine.io-client": "6.4.0",
"engine.io-client-v3": "npm:engine.io-client@3.5.2",
"expect.js": "^0.3.1",
"express-session": "^1.17.3",
"helmet": "^6.0.1",
"mocha": "^9.1.3",

@@ -53,0 +55,0 @@ "prettier": "^2.8.2",

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc