| "use strict"; |
| |
| const sockjs = require("sockjs"); |
| const BaseServer = require("./BaseServer"); |
| |
| /** @typedef {import("../Server").WebSocketServerConfiguration} WebSocketServerConfiguration */ |
| /** @typedef {import("../Server").ClientConnection} ClientConnection */ |
| |
| // Workaround for sockjs@~0.3.19 |
| // sockjs will remove Origin header, however Origin header is required for checking host. |
| // See https://github.com/webpack/webpack-dev-server/issues/1604 for more information |
| { |
| // @ts-ignore |
| const SockjsSession = require("sockjs/lib/transport").Session; |
| const decorateConnection = SockjsSession.prototype.decorateConnection; |
| |
| /** |
| * @param {import("http").IncomingMessage} req |
| */ |
| // eslint-disable-next-line func-names |
| SockjsSession.prototype.decorateConnection = function (req) { |
| decorateConnection.call(this, req); |
| |
| const connection = this.connection; |
| |
| if ( |
| connection.headers && |
| !("origin" in connection.headers) && |
| "origin" in req.headers |
| ) { |
| connection.headers.origin = req.headers.origin; |
| } |
| }; |
| } |
| |
| module.exports = class SockJSServer extends BaseServer { |
| // options has: error (function), debug (function), server (http/s server), path (string) |
| /** |
| * @param {import("../Server")} server |
| */ |
| constructor(server) { |
| super(server); |
| |
| this.implementation = sockjs.createServer({ |
| // Use provided up-to-date sockjs-client |
| sockjs_url: "/__webpack_dev_server__/sockjs.bundle.js", |
| // Default logger is very annoy. Limit useless logs. |
| /** |
| * @param {string} severity |
| * @param {string} line |
| */ |
| log: (severity, line) => { |
| if (severity === "error") { |
| this.server.logger.error(line); |
| } else if (severity === "info") { |
| this.server.logger.log(line); |
| } else { |
| this.server.logger.debug(line); |
| } |
| }, |
| }); |
| |
| /** |
| * @param {import("sockjs").ServerOptions & { path?: string }} options |
| * @returns {string | undefined} |
| */ |
| const getPrefix = (options) => { |
| if (typeof options.prefix !== "undefined") { |
| return options.prefix; |
| } |
| |
| return options.path; |
| }; |
| |
| const options = { |
| .../** @type {WebSocketServerConfiguration} */ |
| (this.server.options.webSocketServer).options, |
| prefix: getPrefix( |
| /** @type {NonNullable<WebSocketServerConfiguration["options"]>} */ |
| ( |
| /** @type {WebSocketServerConfiguration} */ |
| (this.server.options.webSocketServer).options |
| ) |
| ), |
| }; |
| |
| this.implementation.installHandlers( |
| /** @type {import("http").Server} */ (this.server.server), |
| options |
| ); |
| |
| this.implementation.on("connection", (client) => { |
| // @ts-ignore |
| // Implement the the same API as for `ws` |
| client.send = client.write; |
| // @ts-ignore |
| client.terminate = client.close; |
| |
| this.clients.push(/** @type {ClientConnection} */ (client)); |
| |
| client.on("close", () => { |
| this.clients.splice( |
| this.clients.indexOf(/** @type {ClientConnection} */ (client)), |
| 1 |
| ); |
| }); |
| }); |
| |
| // @ts-ignore |
| this.implementation.close = (callback) => { |
| callback(); |
| }; |
| } |
| }; |