SockJSServer.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  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. this.implementation = sockjs.createServer({
  37. // Use provided up-to-date sockjs-client
  38. sockjs_url: "/__webpack_dev_server__/sockjs.bundle.js",
  39. // Default logger is very annoy. Limit useless logs.
  40. /**
  41. * @param {string} severity
  42. * @param {string} line
  43. */
  44. log: (severity, line) => {
  45. if (severity === "error") {
  46. this.server.logger.error(line);
  47. } else if (severity === "info") {
  48. this.server.logger.log(line);
  49. } else {
  50. this.server.logger.debug(line);
  51. }
  52. },
  53. });
  54. /**
  55. * @param {import("sockjs").ServerOptions & { path?: string }} options
  56. * @returns {string | undefined}
  57. */
  58. const getPrefix = (options) => {
  59. if (typeof options.prefix !== "undefined") {
  60. return options.prefix;
  61. }
  62. return options.path;
  63. };
  64. const options = {
  65. .../** @type {WebSocketServerConfiguration} */
  66. (this.server.options.webSocketServer).options,
  67. prefix: getPrefix(
  68. /** @type {NonNullable<WebSocketServerConfiguration["options"]>} */
  69. (
  70. /** @type {WebSocketServerConfiguration} */
  71. (this.server.options.webSocketServer).options
  72. )
  73. ),
  74. };
  75. this.implementation.installHandlers(
  76. /** @type {import("http").Server} */ (this.server.server),
  77. options
  78. );
  79. this.implementation.on("connection", (client) => {
  80. // @ts-ignore
  81. // Implement the the same API as for `ws`
  82. client.send = client.write;
  83. // @ts-ignore
  84. client.terminate = client.close;
  85. this.clients.push(/** @type {ClientConnection} */ (client));
  86. client.on("close", () => {
  87. this.clients.splice(
  88. this.clients.indexOf(/** @type {ClientConnection} */ (client)),
  89. 1
  90. );
  91. });
  92. });
  93. // @ts-ignore
  94. this.implementation.close = (callback) => {
  95. callback();
  96. };
  97. }
  98. };