Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fix-blob-worker-socket-url.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"webpack-dev-server": patch
---

Connect the client to the page's host when it runs in a worker started from a `blob:` URL, instead of `0.0.0.0` or an insecure `ws:` socket on HTTPS pages.
23 changes: 15 additions & 8 deletions client-src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -724,6 +724,13 @@ const formatURL = (objURL) => {
* @returns {string} socket URL
*/
const createSocketURL = (parsedURL) => {
// Blob workers have an empty hostname; their origin is the page that created them.
const pageLocation =
self.location.protocol === "blob:" &&
self.location.origin &&
self.location.origin !== "null"
? new URL(self.location.origin)
: self.location;
let { hostname } = parsedURL;

// Node.js module parses it as `::`
Expand All @@ -736,20 +743,20 @@ const createSocketURL = (parsedURL) => {
// see: https://github.com/webpack/webpack-dev-server/pull/384
if (
isInAddrAny &&
self.location.hostname &&
self.location.protocol.indexOf("http") === 0
pageLocation.hostname &&
pageLocation.protocol.indexOf("http") === 0
) {
hostname = self.location.hostname;
hostname = pageLocation.hostname;
}

let socketURLProtocol = parsedURL.protocol || self.location.protocol;
let socketURLProtocol = parsedURL.protocol || pageLocation.protocol;

// When https is used in the app, secure web sockets are always necessary because the browser doesn't accept non-secure web sockets.
if (
socketURLProtocol === "auto:" ||
(hostname && isInAddrAny && self.location.protocol === "https:")
(hostname && isInAddrAny && pageLocation.protocol === "https:")
) {
socketURLProtocol = self.location.protocol;
socketURLProtocol = pageLocation.protocol;
}

socketURLProtocol = socketURLProtocol.replace(
Expand Down Expand Up @@ -796,14 +803,14 @@ const createSocketURL = (parsedURL) => {
// so we need to fall back to the default if they are not provided
const socketURLHostname = (
hostname ||
self.location.hostname ||
pageLocation.hostname ||
"localhost"
).replace(/^\[(.*)\]$/, "$1");

let socketURLPort = parsedURL.port;

if (!socketURLPort || socketURLPort === "0") {
socketURLPort = self.location.port;
socketURLPort = pageLocation.port;
}

// If path is provided it'll be passed in via the resourceQuery as a
Expand Down
20 changes: 20 additions & 0 deletions test/client/utils/createSocketURL.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,26 @@ describe("'createSocketURL' function", () => {
[null, "file:///home/user/project/index.html", "ws://localhost/ws"],
[null, "chrome-extension://localhost/", "ws://localhost/ws"],
[null, "file://localhost/", "ws://localhost/ws"],
[
"?protocol=ws:&hostname=0.0.0.0&port=0",
"blob:https://example.com/worker-id",
"wss://example.com/ws",
],
[
"?protocol=ws:&hostname=0.0.0.0&port=0",
"blob:http://localhost:8080/worker-id",
"ws://localhost:8080/ws",
],
[
"?hostname=0.0.0.0",
"blob:https://example.com:8443/worker-id",
"wss://example.com:8443/ws",
],
[
"?hostname=example.com&port=9000",
"blob:https://localhost/worker-id",
"wss://example.com:9000/ws",
],
];

for (const [__resourceQuery, location, expected] of samples) {
Expand Down