mirror of
https://github.com/socketio/socket.io.git
synced 2026-01-08 22:48:20 -05:00
refactor: improve types
This commit is contained in:
@@ -17,7 +17,6 @@ export const protocol = parser.protocol;
|
||||
* @param {Function} callback
|
||||
* @param {Object} options
|
||||
* @return {Server} websocket.io server
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function listen(port, options: AttachOptions & ServerOptions, fn) {
|
||||
@@ -46,7 +45,6 @@ function listen(port, options: AttachOptions & ServerOptions, fn) {
|
||||
* @param {http.Server} server
|
||||
* @param {Object} options
|
||||
* @return {Server} engine server
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function attach(server, options: AttachOptions & ServerOptions) {
|
||||
|
||||
@@ -17,12 +17,13 @@ import type { CorsOptions, CorsOptionsDelegate } from "cors";
|
||||
import type { Duplex } from "stream";
|
||||
import { WebTransport } from "./transports/webtransport";
|
||||
import { createPacketDecoderStream } from "engine.io-parser";
|
||||
import type { EngineRequest } from "./transport";
|
||||
|
||||
const debug = debugModule("engine");
|
||||
|
||||
const kResponseHeaders = Symbol("responseHeaders");
|
||||
|
||||
type Transport = "polling" | "websocket";
|
||||
type Transport = "polling" | "websocket" | "webtransport";
|
||||
|
||||
export interface AttachOptions {
|
||||
/**
|
||||
@@ -169,7 +170,6 @@ export abstract class BaseServer extends EventEmitter {
|
||||
* Server constructor.
|
||||
*
|
||||
* @param {Object} opts - options
|
||||
* @api public
|
||||
*/
|
||||
constructor(opts: ServerOptions = {}) {
|
||||
super();
|
||||
@@ -246,9 +246,8 @@ export abstract class BaseServer extends EventEmitter {
|
||||
* Returns a list of available transports for upgrade given a certain transport.
|
||||
*
|
||||
* @return {Array}
|
||||
* @api public
|
||||
*/
|
||||
public upgrades(transport) {
|
||||
public upgrades(transport: string) {
|
||||
if (!this.opts.allowUpgrades) return [];
|
||||
return transports[transport].upgradesTo || [];
|
||||
}
|
||||
@@ -256,11 +255,16 @@ export abstract class BaseServer extends EventEmitter {
|
||||
/**
|
||||
* Verifies a request.
|
||||
*
|
||||
* @param {http.IncomingMessage}
|
||||
* @return {Boolean} whether the request is valid
|
||||
* @api private
|
||||
* @param {EngineRequest} req
|
||||
* @param upgrade - whether it's an upgrade request
|
||||
* @param fn
|
||||
* @protected
|
||||
*/
|
||||
protected verify(req, upgrade, fn) {
|
||||
protected verify(
|
||||
req: any,
|
||||
upgrade: boolean,
|
||||
fn: (errorCode?: number, errorContext?: any) => void
|
||||
) {
|
||||
// transport check
|
||||
const transport = req._query.transport;
|
||||
// WebTransport does not go through the verify() method, see the onWebTransportSession() method
|
||||
@@ -384,8 +388,6 @@ export abstract class BaseServer extends EventEmitter {
|
||||
|
||||
/**
|
||||
* Closes all clients.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
public close() {
|
||||
debug("closing all open clients");
|
||||
@@ -404,23 +406,26 @@ export abstract class BaseServer extends EventEmitter {
|
||||
* generate a socket id.
|
||||
* Overwrite this method to generate your custom socket id
|
||||
*
|
||||
* @param {Object} request object
|
||||
* @api public
|
||||
* @param {IncomingMessage} req - the request object
|
||||
*/
|
||||
public generateId(req) {
|
||||
public generateId(req: IncomingMessage) {
|
||||
return base64id.generateId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handshakes a new client.
|
||||
*
|
||||
* @param {String} transport name
|
||||
* @param {Object} request object
|
||||
* @param {String} transportName
|
||||
* @param {Object} req - the request object
|
||||
* @param {Function} closeConnection
|
||||
*
|
||||
* @api protected
|
||||
* @protected
|
||||
*/
|
||||
protected async handshake(transportName, req, closeConnection) {
|
||||
protected async handshake(
|
||||
transportName: string,
|
||||
req: any,
|
||||
closeConnection: (errorCode?: number, errorContext?: any) => void
|
||||
) {
|
||||
const protocol = req._query.EIO === "4" ? 4 : 3; // 3rd revision by default
|
||||
if (protocol === 3 && !this.opts.allowEIO3) {
|
||||
debug("unsupported protocol version");
|
||||
@@ -661,7 +666,7 @@ export class Server extends BaseServer {
|
||||
/**
|
||||
* Initialize websocket server
|
||||
*
|
||||
* @api protected
|
||||
* @protected
|
||||
*/
|
||||
protected init() {
|
||||
if (!~this.opts.transports.indexOf("websocket")) return;
|
||||
@@ -708,30 +713,30 @@ export class Server extends BaseServer {
|
||||
/**
|
||||
* Prepares a request by processing the query string.
|
||||
*
|
||||
* @api private
|
||||
* @private
|
||||
*/
|
||||
private prepare(req) {
|
||||
private prepare(req: EngineRequest) {
|
||||
// try to leverage pre-existing `req._query` (e.g: from connect)
|
||||
if (!req._query) {
|
||||
req._query = ~req.url.indexOf("?") ? qs.parse(parse(req.url).query) : {};
|
||||
req._query = (
|
||||
~req.url.indexOf("?") ? qs.parse(parse(req.url).query) : {}
|
||||
) as Record<string, string>;
|
||||
}
|
||||
}
|
||||
|
||||
protected createTransport(transportName, req) {
|
||||
protected createTransport(transportName: string, req: IncomingMessage) {
|
||||
return new transports[transportName](req);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles an Engine.IO HTTP request.
|
||||
*
|
||||
* @param {IncomingMessage} req
|
||||
* @param {EngineRequest} req
|
||||
* @param {ServerResponse} res
|
||||
* @api public
|
||||
*/
|
||||
public handleRequest(req: IncomingMessage, res: ServerResponse) {
|
||||
public handleRequest(req: EngineRequest, res: ServerResponse) {
|
||||
debug('handling "%s" http request "%s"', req.method, req.url);
|
||||
this.prepare(req);
|
||||
// @ts-ignore
|
||||
req.res = res;
|
||||
|
||||
const callback = (errorCode, errorContext) => {
|
||||
@@ -746,15 +751,12 @@ export class Server extends BaseServer {
|
||||
return;
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
if (req._query.sid) {
|
||||
debug("setting new request for existing client");
|
||||
// @ts-ignore
|
||||
this.clients[req._query.sid].transport.onRequest(req);
|
||||
} else {
|
||||
const closeConnection = (errorCode, errorContext) =>
|
||||
abortRequest(res, errorCode, errorContext);
|
||||
// @ts-ignore
|
||||
this.handshake(req._query.transport, req, closeConnection);
|
||||
}
|
||||
};
|
||||
@@ -770,11 +772,9 @@ export class Server extends BaseServer {
|
||||
|
||||
/**
|
||||
* Handles an Engine.IO HTTP Upgrade.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
public handleUpgrade(
|
||||
req: IncomingMessage,
|
||||
req: EngineRequest,
|
||||
socket: Duplex,
|
||||
upgradeHead: Buffer
|
||||
) {
|
||||
@@ -819,7 +819,7 @@ export class Server extends BaseServer {
|
||||
* Called upon a ws.io connection.
|
||||
*
|
||||
* @param {ws.Socket} websocket
|
||||
* @api private
|
||||
* @private
|
||||
*/
|
||||
private onWebSocket(req, socket, websocket) {
|
||||
websocket.on("error", onUpgradeError);
|
||||
@@ -877,7 +877,6 @@ export class Server extends BaseServer {
|
||||
*
|
||||
* @param {http.Server} server
|
||||
* @param {Object} options
|
||||
* @api public
|
||||
*/
|
||||
public attach(server: HttpServer, options: AttachOptions = {}) {
|
||||
const path = this._computePath(options);
|
||||
@@ -898,7 +897,7 @@ export class Server extends BaseServer {
|
||||
server.on("request", (req, res) => {
|
||||
if (check(req)) {
|
||||
debug('intercepting request for path "%s"', path);
|
||||
this.handleRequest(req, res);
|
||||
this.handleRequest(req as EngineRequest, res);
|
||||
} else {
|
||||
let i = 0;
|
||||
const l = listeners.length;
|
||||
@@ -911,7 +910,7 @@ export class Server extends BaseServer {
|
||||
if (~this.opts.transports.indexOf("websocket")) {
|
||||
server.on("upgrade", (req, socket, head) => {
|
||||
if (check(req)) {
|
||||
this.handleUpgrade(req, socket, head);
|
||||
this.handleUpgrade(req as EngineRequest, socket, head);
|
||||
} else if (false !== options.destroyUpgrade) {
|
||||
// default node behavior is to disconnect when no handlers
|
||||
// but by adding a handler, we prevent that
|
||||
@@ -939,7 +938,7 @@ export class Server extends BaseServer {
|
||||
* @param errorCode - the error code
|
||||
* @param errorContext - additional error context
|
||||
*
|
||||
* @api private
|
||||
* @private
|
||||
*/
|
||||
|
||||
function abortRequest(res, errorCode, errorContext) {
|
||||
@@ -964,8 +963,6 @@ function abortRequest(res, errorCode, errorContext) {
|
||||
* @param {net.Socket} socket
|
||||
* @param {string} errorCode - the error code
|
||||
* @param {object} errorContext - additional error context
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function abortUpgrade(
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { EventEmitter } from "events";
|
||||
import debugModule from "debug";
|
||||
import { IncomingMessage } from "http";
|
||||
import { Transport } from "./transport";
|
||||
import { Server } from "./server";
|
||||
import type { IncomingMessage } from "http";
|
||||
import type { EngineRequest, Transport } from "./transport";
|
||||
import type { BaseServer } from "./server";
|
||||
import { setTimeout, clearTimeout } from "timers";
|
||||
import { Packet, PacketType, RawData } from "engine.io-parser";
|
||||
import type { Packet, PacketType, RawData } from "engine.io-parser";
|
||||
|
||||
const debug = debugModule("engine:socket");
|
||||
|
||||
@@ -17,15 +17,38 @@ type ReadyState = "opening" | "open" | "closing" | "closed";
|
||||
type SendCallback = (transport: Transport) => void;
|
||||
|
||||
export class Socket extends EventEmitter {
|
||||
/**
|
||||
* The revision of the protocol:
|
||||
*
|
||||
* - 3rd is used in Engine.IO v3 / Socket.IO v2
|
||||
* - 4th is used in Engine.IO v4 and above / Socket.IO v3 and above
|
||||
*
|
||||
* It is found in the `EIO` query parameters of the HTTP requests.
|
||||
*
|
||||
* @see https://github.com/socketio/engine.io-protocol
|
||||
*/
|
||||
public readonly protocol: number;
|
||||
// TODO for the next major release: do not keep the reference to the first HTTP request, as it stays in memory
|
||||
/**
|
||||
* A reference to the first HTTP request of the session
|
||||
*
|
||||
* TODO for the next major release: remove it
|
||||
*/
|
||||
public request: IncomingMessage;
|
||||
/**
|
||||
* The IP address of the client.
|
||||
*/
|
||||
public readonly remoteAddress: string;
|
||||
|
||||
/**
|
||||
* The current state of the socket.
|
||||
*/
|
||||
public _readyState: ReadyState = "opening";
|
||||
/**
|
||||
* The current low-level transport.
|
||||
*/
|
||||
public transport: Transport;
|
||||
|
||||
private server: Server;
|
||||
private server: BaseServer;
|
||||
/* private */ upgrading = false;
|
||||
/* private */ upgraded = false;
|
||||
private writeBuffer: Packet[] = [];
|
||||
@@ -52,12 +75,13 @@ export class Socket extends EventEmitter {
|
||||
this._readyState = state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Client class (abstract).
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
constructor(id, server, transport, req, protocol) {
|
||||
constructor(
|
||||
id: string,
|
||||
server: BaseServer,
|
||||
transport: Transport,
|
||||
req: EngineRequest,
|
||||
protocol: number
|
||||
) {
|
||||
super();
|
||||
this.id = id;
|
||||
this.server = server;
|
||||
@@ -86,7 +110,7 @@ export class Socket extends EventEmitter {
|
||||
/**
|
||||
* Called upon transport considered open.
|
||||
*
|
||||
* @api private
|
||||
* @private
|
||||
*/
|
||||
private onOpen() {
|
||||
this.readyState = "open";
|
||||
@@ -123,7 +147,7 @@ export class Socket extends EventEmitter {
|
||||
* Called upon transport packet.
|
||||
*
|
||||
* @param {Object} packet
|
||||
* @api private
|
||||
* @private
|
||||
*/
|
||||
private onPacket(packet: Packet) {
|
||||
if ("open" !== this.readyState) {
|
||||
@@ -136,7 +160,7 @@ export class Socket extends EventEmitter {
|
||||
switch (packet.type) {
|
||||
case "ping":
|
||||
if (this.transport.protocol !== 3) {
|
||||
this.onError("invalid heartbeat direction");
|
||||
this.onError(new Error("invalid heartbeat direction"));
|
||||
return;
|
||||
}
|
||||
debug("got ping");
|
||||
@@ -147,7 +171,7 @@ export class Socket extends EventEmitter {
|
||||
|
||||
case "pong":
|
||||
if (this.transport.protocol === 3) {
|
||||
this.onError("invalid heartbeat direction");
|
||||
this.onError(new Error("invalid heartbeat direction"));
|
||||
return;
|
||||
}
|
||||
debug("got pong");
|
||||
@@ -171,9 +195,9 @@ export class Socket extends EventEmitter {
|
||||
* Called upon transport error.
|
||||
*
|
||||
* @param {Error} err - error object
|
||||
* @api private
|
||||
* @private
|
||||
*/
|
||||
private onError(err) {
|
||||
private onError(err: Error) {
|
||||
debug("transport error");
|
||||
this.onClose("transport error", err);
|
||||
}
|
||||
@@ -182,7 +206,7 @@ export class Socket extends EventEmitter {
|
||||
* Pings client every `this.pingInterval` and expects response
|
||||
* within `this.pingTimeout` or closes connection.
|
||||
*
|
||||
* @api private
|
||||
* @private
|
||||
*/
|
||||
private schedulePing() {
|
||||
this.pingIntervalTimer = setTimeout(() => {
|
||||
@@ -198,7 +222,7 @@ export class Socket extends EventEmitter {
|
||||
/**
|
||||
* Resets ping timeout.
|
||||
*
|
||||
* @api private
|
||||
* @private
|
||||
*/
|
||||
private resetPingTimeout() {
|
||||
clearTimeout(this.pingTimeoutTimer);
|
||||
@@ -217,9 +241,9 @@ export class Socket extends EventEmitter {
|
||||
* Attaches handlers for the given transport.
|
||||
*
|
||||
* @param {Transport} transport
|
||||
* @api private
|
||||
* @private
|
||||
*/
|
||||
private setTransport(transport) {
|
||||
private setTransport(transport: Transport) {
|
||||
const onError = this.onError.bind(this);
|
||||
const onReady = () => this.flush();
|
||||
const onPacket = this.onPacket.bind(this);
|
||||
@@ -263,7 +287,7 @@ export class Socket extends EventEmitter {
|
||||
* Upgrades socket to the given transport
|
||||
*
|
||||
* @param {Transport} transport
|
||||
* @api private
|
||||
* @private
|
||||
*/
|
||||
/* private */ _maybeUpgrade(transport: Transport) {
|
||||
debug(
|
||||
@@ -357,7 +381,7 @@ export class Socket extends EventEmitter {
|
||||
/**
|
||||
* Clears listeners and timers associated with current transport.
|
||||
*
|
||||
* @api private
|
||||
* @private
|
||||
*/
|
||||
private clearTransport() {
|
||||
let cleanup;
|
||||
@@ -412,7 +436,6 @@ export class Socket extends EventEmitter {
|
||||
* @param {Object} options
|
||||
* @param {Function} callback
|
||||
* @return {Socket} for chaining
|
||||
* @api public
|
||||
*/
|
||||
public send(data: RawData, options?: SendOptions, callback?: SendCallback) {
|
||||
this.sendPacket("message", data, options, callback);
|
||||
@@ -439,7 +462,7 @@ export class Socket extends EventEmitter {
|
||||
* @param {Object} options
|
||||
* @param {Function} callback
|
||||
*
|
||||
* @api private
|
||||
* @private
|
||||
*/
|
||||
private sendPacket(
|
||||
type: PacketType,
|
||||
@@ -480,7 +503,7 @@ export class Socket extends EventEmitter {
|
||||
/**
|
||||
* Attempts to flush the packets buffer.
|
||||
*
|
||||
* @api private
|
||||
* @private
|
||||
*/
|
||||
private flush() {
|
||||
if (
|
||||
@@ -510,14 +533,12 @@ export class Socket extends EventEmitter {
|
||||
/**
|
||||
* Get available upgrades for this socket.
|
||||
*
|
||||
* @api private
|
||||
* @private
|
||||
*/
|
||||
private getAvailableUpgrades() {
|
||||
const availableUpgrades = [];
|
||||
const allUpgrades = this.server.upgrades(this.transport.name);
|
||||
let i = 0;
|
||||
const l = allUpgrades.length;
|
||||
for (; i < l; ++i) {
|
||||
for (let i = 0; i < allUpgrades.length; ++i) {
|
||||
const upg = allUpgrades[i];
|
||||
if (this.server.opts.transports.indexOf(upg) !== -1) {
|
||||
availableUpgrades.push(upg);
|
||||
@@ -531,7 +552,6 @@ export class Socket extends EventEmitter {
|
||||
*
|
||||
* @param {Boolean} discard - optional, discard the transport
|
||||
* @return {Socket} for chaining
|
||||
* @api public
|
||||
*/
|
||||
public close(discard?: boolean) {
|
||||
if ("open" !== this.readyState) return;
|
||||
@@ -558,9 +578,9 @@ export class Socket extends EventEmitter {
|
||||
* Closes the underlying transport.
|
||||
*
|
||||
* @param {Boolean} discard
|
||||
* @api private
|
||||
* @private
|
||||
*/
|
||||
private closeTransport(discard) {
|
||||
private closeTransport(discard: boolean) {
|
||||
debug("closing the transport (discard? %s)", discard);
|
||||
if (discard) this.transport.discard();
|
||||
this.transport.close(this.onClose.bind(this, "forced close"));
|
||||
|
||||
@@ -2,30 +2,63 @@ import { EventEmitter } from "events";
|
||||
import * as parser_v4 from "engine.io-parser";
|
||||
import * as parser_v3 from "./parser-v3/index";
|
||||
import debugModule from "debug";
|
||||
import { IncomingMessage } from "http";
|
||||
import { Packet } from "engine.io-parser";
|
||||
import type { IncomingMessage, ServerResponse } from "http";
|
||||
import { Packet, RawData } from "engine.io-parser";
|
||||
|
||||
const debug = debugModule("engine:transport");
|
||||
|
||||
/**
|
||||
* Noop function.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function noop() {}
|
||||
|
||||
type ReadyState = "open" | "closing" | "closed";
|
||||
|
||||
export type EngineRequest = IncomingMessage & {
|
||||
_query: Record<string, string>;
|
||||
res?: ServerResponse;
|
||||
cleanup?: Function;
|
||||
websocket?: any;
|
||||
};
|
||||
|
||||
export abstract class Transport extends EventEmitter {
|
||||
/**
|
||||
* The session ID.
|
||||
*/
|
||||
public sid: string;
|
||||
/**
|
||||
* Whether the transport is currently ready to send packets.
|
||||
*/
|
||||
public writable = false;
|
||||
/**
|
||||
* The revision of the protocol:
|
||||
*
|
||||
* - 3 is used in Engine.IO v3 / Socket.IO v2
|
||||
* - 4 is used in Engine.IO v4 and above / Socket.IO v3 and above
|
||||
*
|
||||
* It is found in the `EIO` query parameters of the HTTP requests.
|
||||
*
|
||||
* @see https://github.com/socketio/engine.io-protocol
|
||||
*/
|
||||
public protocol: number;
|
||||
|
||||
/**
|
||||
* The current state of the transport.
|
||||
* @protected
|
||||
*/
|
||||
protected _readyState: ReadyState = "open";
|
||||
/**
|
||||
* Whether the transport is discarded and can be safely closed (used during upgrade).
|
||||
* @protected
|
||||
*/
|
||||
protected discarded = false;
|
||||
/**
|
||||
* The parser to use (depends on the revision of the {@link Transport#protocol}.
|
||||
* @protected
|
||||
*/
|
||||
protected parser: any;
|
||||
protected req: IncomingMessage & { cleanup: Function };
|
||||
protected req: EngineRequest;
|
||||
/**
|
||||
* Whether the transport supports binary payloads (else it will be base64-encoded)
|
||||
* @protected
|
||||
*/
|
||||
protected supportsBinary: boolean;
|
||||
|
||||
get readyState() {
|
||||
@@ -45,10 +78,9 @@ export abstract class Transport extends EventEmitter {
|
||||
/**
|
||||
* Transport constructor.
|
||||
*
|
||||
* @param {http.IncomingMessage} req
|
||||
* @api public
|
||||
* @param {EngineRequest} req
|
||||
*/
|
||||
constructor(req) {
|
||||
constructor(req: { _query: Record<string, string> }) {
|
||||
super();
|
||||
this.protocol = req._query.EIO === "4" ? 4 : 3; // 3rd revision by default
|
||||
this.parser = this.protocol === 4 ? parser_v4 : parser_v3;
|
||||
@@ -58,7 +90,7 @@ export abstract class Transport extends EventEmitter {
|
||||
/**
|
||||
* Flags the transport as discarded.
|
||||
*
|
||||
* @api private
|
||||
* @package
|
||||
*/
|
||||
discard() {
|
||||
this.discarded = true;
|
||||
@@ -68,9 +100,9 @@ export abstract class Transport extends EventEmitter {
|
||||
* Called with an incoming HTTP request.
|
||||
*
|
||||
* @param {http.IncomingMessage} req
|
||||
* @api protected
|
||||
* @package
|
||||
*/
|
||||
protected onRequest(req) {
|
||||
onRequest(req) {
|
||||
debug("setting request");
|
||||
this.req = req;
|
||||
}
|
||||
@@ -78,9 +110,9 @@ export abstract class Transport extends EventEmitter {
|
||||
/**
|
||||
* Closes the transport.
|
||||
*
|
||||
* @api private
|
||||
* @package
|
||||
*/
|
||||
close(fn?) {
|
||||
close(fn?: () => void) {
|
||||
if ("closed" === this.readyState || "closing" === this.readyState) return;
|
||||
|
||||
this.readyState = "closing";
|
||||
@@ -92,7 +124,7 @@ export abstract class Transport extends EventEmitter {
|
||||
*
|
||||
* @param {String} msg - message error
|
||||
* @param {Object} desc - error description
|
||||
* @api protected
|
||||
* @protected
|
||||
*/
|
||||
protected onError(msg: string, desc?) {
|
||||
if (this.listeners("error").length) {
|
||||
@@ -111,7 +143,7 @@ export abstract class Transport extends EventEmitter {
|
||||
* Called with parsed out a packets from the data stream.
|
||||
*
|
||||
* @param {Object} packet
|
||||
* @api protected
|
||||
* @protected
|
||||
*/
|
||||
protected onPacket(packet: Packet) {
|
||||
this.emit("packet", packet);
|
||||
@@ -121,16 +153,16 @@ export abstract class Transport extends EventEmitter {
|
||||
* Called with the encoded packet data.
|
||||
*
|
||||
* @param {String} data
|
||||
* @api protected
|
||||
* @protected
|
||||
*/
|
||||
protected onData(data) {
|
||||
protected onData(data: RawData) {
|
||||
this.onPacket(this.parser.decodePacket(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Called upon transport close.
|
||||
*
|
||||
* @api protected
|
||||
* @protected
|
||||
*/
|
||||
protected onClose() {
|
||||
this.readyState = "closed";
|
||||
@@ -140,7 +172,7 @@ export abstract class Transport extends EventEmitter {
|
||||
/**
|
||||
* The name of the transport.
|
||||
*/
|
||||
abstract get name();
|
||||
abstract get name(): string;
|
||||
|
||||
/**
|
||||
* Sends an array of packets.
|
||||
@@ -148,10 +180,10 @@ export abstract class Transport extends EventEmitter {
|
||||
* @param {Array} packets
|
||||
* @package
|
||||
*/
|
||||
abstract send(packets);
|
||||
abstract send(packets: Packet[]): void;
|
||||
|
||||
/**
|
||||
* Closes the transport.
|
||||
*/
|
||||
abstract doClose(fn?);
|
||||
abstract doClose(fn?: () => void): void;
|
||||
}
|
||||
|
||||
@@ -24,8 +24,6 @@ export class Polling extends Transport {
|
||||
|
||||
/**
|
||||
* HTTP polling constructor.
|
||||
*
|
||||
* @api public.
|
||||
*/
|
||||
constructor(req) {
|
||||
super(req);
|
||||
@@ -35,8 +33,6 @@ export class Polling extends Transport {
|
||||
|
||||
/**
|
||||
* Transport name
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
get name() {
|
||||
return "polling";
|
||||
@@ -47,7 +43,7 @@ export class Polling extends Transport {
|
||||
*
|
||||
* @param req
|
||||
*
|
||||
* @api private
|
||||
* @private
|
||||
*/
|
||||
onRequest(req) {
|
||||
const res = req.res;
|
||||
@@ -67,7 +63,7 @@ export class Polling extends Transport {
|
||||
/**
|
||||
* The client sends a request awaiting for us to send data.
|
||||
*
|
||||
* @api private
|
||||
* @private
|
||||
*/
|
||||
onPollRequest(req, res) {
|
||||
if (this.req) {
|
||||
@@ -109,7 +105,7 @@ export class Polling extends Transport {
|
||||
/**
|
||||
* The client sends a request with data.
|
||||
*
|
||||
* @api private
|
||||
* @private
|
||||
*/
|
||||
onDataRequest(req, res) {
|
||||
if (this.dataReq) {
|
||||
@@ -206,7 +202,7 @@ export class Polling extends Transport {
|
||||
/**
|
||||
* Cleanup request.
|
||||
*
|
||||
* @api private
|
||||
* @private
|
||||
*/
|
||||
private onDataRequestCleanup() {
|
||||
this.dataReq = this.dataRes = null;
|
||||
@@ -216,7 +212,7 @@ export class Polling extends Transport {
|
||||
* Processes the incoming data payload.
|
||||
*
|
||||
* @param {String} encoded payload
|
||||
* @api private
|
||||
* @private
|
||||
*/
|
||||
onData(data) {
|
||||
debug('received "%s"', data);
|
||||
@@ -240,7 +236,7 @@ export class Polling extends Transport {
|
||||
/**
|
||||
* Overrides onClose.
|
||||
*
|
||||
* @api private
|
||||
* @private
|
||||
*/
|
||||
onClose() {
|
||||
if (this.writable) {
|
||||
@@ -254,7 +250,7 @@ export class Polling extends Transport {
|
||||
* Writes a packet payload.
|
||||
*
|
||||
* @param {Object} packet
|
||||
* @api private
|
||||
* @private
|
||||
*/
|
||||
send(packets) {
|
||||
this.writable = false;
|
||||
@@ -285,7 +281,7 @@ export class Polling extends Transport {
|
||||
*
|
||||
* @param {String} data
|
||||
* @param {Object} options
|
||||
* @api private
|
||||
* @private
|
||||
*/
|
||||
write(data, options) {
|
||||
debug('writing "%s"', data);
|
||||
@@ -298,7 +294,7 @@ export class Polling extends Transport {
|
||||
/**
|
||||
* Performs the write.
|
||||
*
|
||||
* @api private
|
||||
* @private
|
||||
*/
|
||||
doWrite(data, options, callback) {
|
||||
// explicit UTF-8 is required for pages not served under utf
|
||||
@@ -355,7 +351,7 @@ export class Polling extends Transport {
|
||||
/**
|
||||
* Compresses data.
|
||||
*
|
||||
* @api private
|
||||
* @private
|
||||
*/
|
||||
compress(data, encoding, callback) {
|
||||
debug("compressing");
|
||||
@@ -378,7 +374,7 @@ export class Polling extends Transport {
|
||||
/**
|
||||
* Closes the transport.
|
||||
*
|
||||
* @api private
|
||||
* @private
|
||||
*/
|
||||
doClose(fn) {
|
||||
debug("closing");
|
||||
@@ -410,7 +406,7 @@ export class Polling extends Transport {
|
||||
*
|
||||
* @param req - request
|
||||
* @param {Object} extra headers
|
||||
* @api private
|
||||
* @private
|
||||
*/
|
||||
headers(req, headers) {
|
||||
headers = headers || {};
|
||||
|
||||
@@ -11,7 +11,6 @@ export class WebSocket extends Transport {
|
||||
* WebSocket transport
|
||||
*
|
||||
* @param req
|
||||
* @api public
|
||||
*/
|
||||
constructor(req) {
|
||||
super(req);
|
||||
@@ -21,8 +20,6 @@ export class WebSocket extends Transport {
|
||||
|
||||
/**
|
||||
* Transport name
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
get name() {
|
||||
return "websocket";
|
||||
@@ -30,8 +27,6 @@ export class WebSocket extends Transport {
|
||||
|
||||
/**
|
||||
* Advertise upgrade support.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
get handlesUpgrades() {
|
||||
return true;
|
||||
@@ -41,7 +36,7 @@ export class WebSocket extends Transport {
|
||||
* Writes a packet payload.
|
||||
*
|
||||
* @param {Array} packets
|
||||
* @api private
|
||||
* @private
|
||||
*/
|
||||
send(packets) {
|
||||
this.writable = false;
|
||||
@@ -77,7 +72,7 @@ export class WebSocket extends Transport {
|
||||
/**
|
||||
* Closes the transport.
|
||||
*
|
||||
* @api private
|
||||
* @private
|
||||
*/
|
||||
doClose(fn) {
|
||||
debug("closing");
|
||||
|
||||
@@ -11,8 +11,6 @@ export default {
|
||||
|
||||
/**
|
||||
* Polling polymorphic constructor.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function polling(req) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Polling } from "./polling";
|
||||
import * as qs from "querystring";
|
||||
import type { RawData } from "engine.io-parser";
|
||||
|
||||
const rDoubleSlashes = /\\\\n/g;
|
||||
const rSlashes = /(\\)?\\n/g;
|
||||
@@ -10,8 +11,6 @@ export class JSONP extends Polling {
|
||||
|
||||
/**
|
||||
* JSON-P polling transport.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
constructor(req) {
|
||||
super(req);
|
||||
@@ -20,16 +19,10 @@ export class JSONP extends Polling {
|
||||
this.foot = ");";
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles incoming data.
|
||||
* Due to a bug in \n handling by browsers, we expect a escaped string.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
onData(data) {
|
||||
override onData(data: RawData) {
|
||||
// we leverage the qs module so that we get built-in DoS protection
|
||||
// and the fast alternative to decodeURIComponent
|
||||
data = qs.parse(data).d;
|
||||
data = qs.parse(data).d as string;
|
||||
if ("string" === typeof data) {
|
||||
// client will send already escaped newlines as \\\\n and newlines as \\n
|
||||
// \\n must be replaced with \n and \\\\n with \\n
|
||||
@@ -40,12 +33,7 @@ export class JSONP extends Polling {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the write.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
doWrite(data, options, callback) {
|
||||
override doWrite(data, options, callback) {
|
||||
// we must output valid javascript, not valid json
|
||||
// see: http://timelessrepo.com/json-isnt-a-javascript-subset
|
||||
const js = JSON.stringify(data)
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { Transport } from "../transport";
|
||||
import { EngineRequest, Transport } from "../transport";
|
||||
import { createGzip, createDeflate } from "zlib";
|
||||
import * as accepts from "accepts";
|
||||
import debugModule from "debug";
|
||||
import { IncomingMessage, ServerResponse } from "http";
|
||||
import type { IncomingMessage, ServerResponse } from "http";
|
||||
import type { Packet, RawData } from "engine.io-parser";
|
||||
|
||||
const debug = debugModule("engine:polling");
|
||||
|
||||
@@ -18,14 +19,12 @@ export class Polling extends Transport {
|
||||
private res: ServerResponse;
|
||||
private dataReq: IncomingMessage;
|
||||
private dataRes: ServerResponse;
|
||||
private shouldClose: Function;
|
||||
private shouldClose: () => void;
|
||||
|
||||
private readonly closeTimeout: number;
|
||||
|
||||
/**
|
||||
* HTTP polling constructor.
|
||||
*
|
||||
* @api public.
|
||||
*/
|
||||
constructor(req) {
|
||||
super(req);
|
||||
@@ -35,8 +34,6 @@ export class Polling extends Transport {
|
||||
|
||||
/**
|
||||
* Transport name
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
get name() {
|
||||
return "polling";
|
||||
@@ -45,10 +42,10 @@ export class Polling extends Transport {
|
||||
/**
|
||||
* Overrides onRequest.
|
||||
*
|
||||
* @param {http.IncomingMessage}
|
||||
* @api private
|
||||
* @param {EngineRequest} req
|
||||
* @package
|
||||
*/
|
||||
onRequest(req: IncomingMessage & { res: ServerResponse }) {
|
||||
onRequest(req: EngineRequest) {
|
||||
const res = req.res;
|
||||
// remove the reference to the ServerResponse object (as the first request of the session is kept in memory by default)
|
||||
req.res = null;
|
||||
@@ -66,9 +63,9 @@ export class Polling extends Transport {
|
||||
/**
|
||||
* The client sends a request awaiting for us to send data.
|
||||
*
|
||||
* @api private
|
||||
* @private
|
||||
*/
|
||||
onPollRequest(req, res) {
|
||||
private onPollRequest(req: EngineRequest, res: ServerResponse) {
|
||||
if (this.req) {
|
||||
debug("request overlap");
|
||||
// assert: this.res, '.req and .res should be (un)set together'
|
||||
@@ -108,9 +105,9 @@ export class Polling extends Transport {
|
||||
/**
|
||||
* The client sends a request with data.
|
||||
*
|
||||
* @api private
|
||||
* @private
|
||||
*/
|
||||
onDataRequest(req: IncomingMessage, res: ServerResponse) {
|
||||
private onDataRequest(req: IncomingMessage, res: ServerResponse) {
|
||||
if (this.dataReq) {
|
||||
// assert: this.dataRes, '.dataReq and .dataRes should be (un)set together'
|
||||
this.onError("data request overlap from client");
|
||||
@@ -165,7 +162,7 @@ export class Polling extends Transport {
|
||||
// text/html is required instead of text/plain to avoid an
|
||||
// unwanted download dialog on certain user-agents (GH-43)
|
||||
"Content-Type": "text/html",
|
||||
"Content-Length": 2,
|
||||
"Content-Length": "2",
|
||||
};
|
||||
|
||||
res.writeHead(200, this.headers(req, headers));
|
||||
@@ -182,10 +179,10 @@ export class Polling extends Transport {
|
||||
/**
|
||||
* Processes the incoming data payload.
|
||||
*
|
||||
* @param {String} encoded payload
|
||||
* @api private
|
||||
* @param data - encoded payload
|
||||
* @protected
|
||||
*/
|
||||
onData(data) {
|
||||
override onData(data: RawData) {
|
||||
debug('received "%s"', data);
|
||||
const callback = (packet) => {
|
||||
if ("close" === packet.type) {
|
||||
@@ -207,7 +204,7 @@ export class Polling extends Transport {
|
||||
/**
|
||||
* Overrides onClose.
|
||||
*
|
||||
* @api private
|
||||
* @private
|
||||
*/
|
||||
onClose() {
|
||||
if (this.writable) {
|
||||
@@ -217,13 +214,7 @@ export class Polling extends Transport {
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a packet payload.
|
||||
*
|
||||
* @param {Object} packet
|
||||
* @api private
|
||||
*/
|
||||
send(packets) {
|
||||
send(packets: Packet[]) {
|
||||
this.writable = false;
|
||||
|
||||
if (this.shouldClose) {
|
||||
@@ -252,9 +243,9 @@ export class Polling extends Transport {
|
||||
*
|
||||
* @param {String} data
|
||||
* @param {Object} options
|
||||
* @api private
|
||||
* @private
|
||||
*/
|
||||
write(data, options) {
|
||||
private write(data, options) {
|
||||
debug('writing "%s"', data);
|
||||
this.doWrite(data, options, () => {
|
||||
this.req.cleanup();
|
||||
@@ -265,9 +256,9 @@ export class Polling extends Transport {
|
||||
/**
|
||||
* Performs the write.
|
||||
*
|
||||
* @api private
|
||||
* @protected
|
||||
*/
|
||||
doWrite(data, options, callback) {
|
||||
protected doWrite(data, options, callback) {
|
||||
// explicit UTF-8 is required for pages not served under utf
|
||||
const isString = typeof data === "string";
|
||||
const contentType = isString
|
||||
@@ -319,9 +310,9 @@ export class Polling extends Transport {
|
||||
/**
|
||||
* Compresses data.
|
||||
*
|
||||
* @api private
|
||||
* @private
|
||||
*/
|
||||
compress(data, encoding, callback) {
|
||||
private compress(data, encoding, callback) {
|
||||
debug("compressing");
|
||||
|
||||
const buffers = [];
|
||||
@@ -342,9 +333,9 @@ export class Polling extends Transport {
|
||||
/**
|
||||
* Closes the transport.
|
||||
*
|
||||
* @api private
|
||||
* @private
|
||||
*/
|
||||
doClose(fn) {
|
||||
override doClose(fn: () => void) {
|
||||
debug("closing");
|
||||
|
||||
let closeTimeoutTimer;
|
||||
@@ -377,13 +368,11 @@ export class Polling extends Transport {
|
||||
/**
|
||||
* Returns headers for a response.
|
||||
*
|
||||
* @param {http.IncomingMessage} request
|
||||
* @param {Object} extra headers
|
||||
* @api private
|
||||
* @param {http.IncomingMessage} req
|
||||
* @param {Object} headers - extra headers
|
||||
* @private
|
||||
*/
|
||||
headers(req, headers) {
|
||||
headers = headers || {};
|
||||
|
||||
private headers(req: IncomingMessage, headers: Record<string, string> = {}) {
|
||||
// prevent XSS warnings on IE
|
||||
// https://github.com/LearnBoost/socket.io/pull/1333
|
||||
const ua = req.headers["user-agent"];
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Transport } from "../transport";
|
||||
import { EngineRequest, Transport } from "../transport";
|
||||
import debugModule from "debug";
|
||||
import type { Packet, RawData } from "engine.io-parser";
|
||||
|
||||
@@ -11,10 +11,9 @@ export class WebSocket extends Transport {
|
||||
/**
|
||||
* WebSocket transport
|
||||
*
|
||||
* @param {http.IncomingMessage}
|
||||
* @api public
|
||||
* @param {EngineRequest} req
|
||||
*/
|
||||
constructor(req) {
|
||||
constructor(req: EngineRequest) {
|
||||
super(req);
|
||||
this.socket = req.websocket;
|
||||
this.socket.on("message", (data, isBinary) => {
|
||||
@@ -30,8 +29,6 @@ export class WebSocket extends Transport {
|
||||
|
||||
/**
|
||||
* Transport name
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
get name() {
|
||||
return "websocket";
|
||||
@@ -39,8 +36,6 @@ export class WebSocket extends Transport {
|
||||
|
||||
/**
|
||||
* Advertise upgrade support.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
get handlesUpgrades() {
|
||||
return true;
|
||||
|
||||
@@ -30,7 +30,7 @@ export class uServer extends BaseServer {
|
||||
/**
|
||||
* Prepares a request by processing the query string.
|
||||
*
|
||||
* @api private
|
||||
* @private
|
||||
*/
|
||||
private prepare(req, res: HttpResponse) {
|
||||
req.method = req.getMethod().toUpperCase();
|
||||
|
||||
Reference in New Issue
Block a user