SockJSServer.js 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  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-ignore
  11. const SockjsSession = require("sockjs/lib/transport").Session;
  12. const decorateConnection = SockjsSession.prototype.decorateConnection;
  13. /**
  14. * @param {import("http").IncomingMessage} req
  15. */
  16. // eslint-disable-next-line func-names
  17. SockjsSession.prototype.decorateConnection = function (req) {
  18. decorateConnection.call(this, req);
  19. const connection = this.connection;
  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
  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
  44. * @returns {string}
  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. sockjs_url: getSockjsUrl(webSocketServerOptions),
  55. // Default logger is very annoy. Limit useless logs.
  56. /**
  57. * @param {string} severity
  58. * @param {string} line
  59. */
  60. log: (severity, line) => {
  61. if (severity === "error") {
  62. this.server.logger.error(line);
  63. } else if (severity === "info") {
  64. this.server.logger.log(line);
  65. } else {
  66. this.server.logger.debug(line);
  67. }
  68. },
  69. });
  70. /**
  71. * @param {import("sockjs").ServerOptions & { path?: string }} options
  72. * @returns {string | undefined}
  73. */
  74. const getPrefix = (options) => {
  75. if (typeof options.prefix !== "undefined") {
  76. return options.prefix;
  77. }
  78. return options.path;
  79. };
  80. const options = {
  81. ...webSocketServerOptions,
  82. prefix: getPrefix(webSocketServerOptions),
  83. };
  84. this.implementation.installHandlers(
  85. /** @type {import("http").Server} */ (this.server.server),
  86. options
  87. );
  88. this.implementation.on("connection", (client) => {
  89. // @ts-ignore
  90. // Implement the the same API as for `ws`
  91. client.send = client.write;
  92. // @ts-ignore
  93. client.terminate = client.close;
  94. this.clients.push(/** @type {ClientConnection} */ (client));
  95. client.on("close", () => {
  96. this.clients.splice(
  97. this.clients.indexOf(/** @type {ClientConnection} */ (client)),
  98. 1
  99. );
  100. });
  101. });
  102. // @ts-ignore
  103. this.implementation.close = (callback) => {
  104. callback();
  105. };
  106. }
  107. };