SockJSServer.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. "use strict";
  2. const sockjs = require("sockjs");
  3. const BaseServer = require("./BaseServer");
  4. /** @typedef {import("../Server").WebSocketServerConfiguration} WebSocketServerConfiguration */
  5. /** @typedef {import("../Server").ClientConnection} ClientConnection */
  6. // Workaround for sockjs@~0.3.19
  7. // sockjs will remove Origin header, however Origin header is required for checking host.
  8. // See https://github.com/webpack/webpack-dev-server/issues/1604 for more information
  9. {
  10. // @ts-expect-error
  11. const SockjsSession = require("sockjs/lib/transport").Session;
  12. const { decorateConnection } = SockjsSession.prototype;
  13. /**
  14. * @param {import("http").IncomingMessage} req request
  15. */
  16. // eslint-disable-next-line func-names
  17. SockjsSession.prototype.decorateConnection = function (req) {
  18. decorateConnection.call(this, req);
  19. const { connection } = this;
  20. if (
  21. connection.headers &&
  22. !("origin" in connection.headers) &&
  23. "origin" in req.headers
  24. ) {
  25. connection.headers.origin = req.headers.origin;
  26. }
  27. };
  28. }
  29. module.exports = class SockJSServer extends BaseServer {
  30. // options has: error (function), debug (function), server (http/s server), path (string)
  31. /**
  32. * @param {import("../Server")} server server
  33. */
  34. constructor(server) {
  35. super(server);
  36. const webSocketServerOptions =
  37. /** @type {NonNullable<WebSocketServerConfiguration["options"]>} */
  38. (
  39. /** @type {WebSocketServerConfiguration} */
  40. (this.server.options.webSocketServer).options
  41. );
  42. /**
  43. * @param {NonNullable<WebSocketServerConfiguration["options"]>} options options
  44. * @returns {string} sockjs URL
  45. */
  46. const getSockjsUrl = (options) => {
  47. if (typeof options.sockjsUrl !== "undefined") {
  48. return options.sockjsUrl;
  49. }
  50. return "/__webpack_dev_server__/sockjs.bundle.js";
  51. };
  52. this.implementation = sockjs.createServer({
  53. // Use provided up-to-date sockjs-client
  54. // eslint-disable-next-line camelcase
  55. sockjs_url: getSockjsUrl(webSocketServerOptions),
  56. // Default logger is very annoy. Limit useless logs.
  57. /**
  58. * @param {string} severity severity
  59. * @param {string} line line
  60. */
  61. log: (severity, line) => {
  62. if (severity === "error") {
  63. this.server.logger.error(line);
  64. } else if (severity === "info") {
  65. this.server.logger.log(line);
  66. } else {
  67. this.server.logger.debug(line);
  68. }
  69. },
  70. });
  71. /**
  72. * @param {import("sockjs").ServerOptions & { path?: string }} options options
  73. * @returns {string | undefined} prefix
  74. */
  75. const getPrefix = (options) => {
  76. if (typeof options.prefix !== "undefined") {
  77. return options.prefix;
  78. }
  79. return options.path;
  80. };
  81. const options = {
  82. ...webSocketServerOptions,
  83. prefix: getPrefix(webSocketServerOptions),
  84. };
  85. this.implementation.installHandlers(
  86. /** @type {import("http").Server} */ (this.server.server),
  87. options,
  88. );
  89. this.implementation.on("connection", (client) => {
  90. // @ts-expect-error
  91. // Implement the the same API as for `ws`
  92. client.send = client.write;
  93. // @ts-expect-error
  94. client.terminate = client.close;
  95. this.clients.push(/** @type {ClientConnection} */ (client));
  96. client.on("close", () => {
  97. this.clients.splice(
  98. this.clients.indexOf(/** @type {ClientConnection} */ (client)),
  99. 1,
  100. );
  101. });
  102. });
  103. // @ts-expect-error
  104. this.implementation.close = (callback) => {
  105. callback();
  106. };
  107. }
  108. };