diff --git a/lib/Server.js b/lib/Server.js index 3c2d3e8b78..7a29938b08 100644 --- a/lib/Server.js +++ b/lib/Server.js @@ -127,6 +127,9 @@ function Server(compiler, options) { contentBase = process.cwd(); } + // Keep track of websocket proxies for external websocket upgrade. + const websocketProxies = []; + const features = { compress() { if(options.compress) { @@ -205,6 +208,9 @@ function Server(compiler, options) { } proxyMiddleware = getProxyMiddleware(proxyConfig); + if(proxyConfig.ws) { + websocketProxies.push(proxyMiddleware); + } app.use((req, res, next) => { if(typeof proxyConfigOrCallback === "function") { @@ -361,6 +367,12 @@ function Server(compiler, options) { } else { this.listeningApp = http.createServer(app); } + + // Proxy websockets without the initial http request + // https://github.com/chimurai/http-proxy-middleware#external-websocket-upgrade + websocketProxies.forEach(function(wsProxy) { + this.listeningApp.on("upgrade", wsProxy.upgrade); + }, this); } Server.prototype.use = function() { diff --git a/package.json b/package.json index 83a164a217..565fc7c83e 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,8 @@ "style-loader": "~0.13.0", "supertest": "^2.0.1", "url-loader": "~0.5.6", - "webpack": "^2.2.0" + "webpack": "^2.2.0", + "ws": "^1.1.1" }, "license": "MIT", "repository": { diff --git a/test/Proxy.test.js b/test/Proxy.test.js index ef0c40eec3..ba6c75936f 100644 --- a/test/Proxy.test.js +++ b/test/Proxy.test.js @@ -3,9 +3,12 @@ const request = require("supertest"); const path = require("path"); const express = require("express"); +const WebSocket = require("ws"); const helper = require("./helper"); +const should = require("should"); const config = require("./fixtures/proxy-config/webpack.config"); +const WebSocketServer = WebSocket.Server; const contentBase = path.join(__dirname, "fixtures/proxy-config"); const proxyOption = { @@ -184,4 +187,48 @@ describe("Proxy", function() { req.get("/proxy2").expect(200, "from proxy", done); }); }); + + context("External websocket upgrade", function() { + let ws; + let wsServer; + let responseMessage; + + before(function(done) { + helper.start(config, { + contentBase, + proxy: [{ + context: "/", + target: "http://localhost:9003", + ws: true + }] + }, done); + + wsServer = new WebSocketServer({ port: 9003 }); + wsServer.on("connection", function connection(ws) { + ws.on("message", function incoming(message) { + ws.send(message); + }); + }); + }); + + beforeEach(function(done) { + ws = new WebSocket("ws://localhost:8080/proxy3/socket"); + ws.on("message", function(message) { + responseMessage = message; + done() + }); + ws.on("open", function open() { + ws.send("foo"); + }); + }) + + it("Should receive response", function() { + should(responseMessage).equal("foo"); + }); + + after(function(done) { + wsServer.close(); + helper.close(done); + }); + }); });