| /** |
| * @param {{ protocol?: string, auth?: string, hostname?: string, port?: string, pathname?: string, search?: string, hash?: string, slashes?: boolean }} objURL |
| * @returns {string} |
| */ |
| function format(objURL) { |
| var protocol = objURL.protocol || ""; |
| |
| if (protocol && protocol.substr(-1) !== ":") { |
| protocol += ":"; |
| } |
| |
| var auth = objURL.auth || ""; |
| |
| if (auth) { |
| auth = encodeURIComponent(auth); |
| auth = auth.replace(/%3A/i, ":"); |
| auth += "@"; |
| } |
| |
| var host = ""; |
| |
| if (objURL.hostname) { |
| host = auth + (objURL.hostname.indexOf(":") === -1 ? objURL.hostname : "[".concat(objURL.hostname, "]")); |
| |
| if (objURL.port) { |
| host += ":".concat(objURL.port); |
| } |
| } |
| |
| var pathname = objURL.pathname || ""; |
| |
| if (objURL.slashes) { |
| host = "//".concat(host || ""); |
| |
| if (pathname && pathname.charAt(0) !== "/") { |
| pathname = "/".concat(pathname); |
| } |
| } else if (!host) { |
| host = ""; |
| } |
| |
| var search = objURL.search || ""; |
| |
| if (search && search.charAt(0) !== "?") { |
| search = "?".concat(search); |
| } |
| |
| var hash = objURL.hash || ""; |
| |
| if (hash && hash.charAt(0) !== "#") { |
| hash = "#".concat(hash); |
| } |
| |
| pathname = pathname.replace(/[?#]/g, |
| /** |
| * @param {string} match |
| * @returns {string} |
| */ |
| function (match) { |
| return encodeURIComponent(match); |
| }); |
| search = search.replace("#", "%23"); |
| return "".concat(protocol).concat(host).concat(pathname).concat(search).concat(hash); |
| } |
| /** |
| * @param {URL & { fromCurrentScript?: boolean }} parsedURL |
| * @returns {string} |
| */ |
| |
| |
| function createSocketURL(parsedURL) { |
| var hostname = parsedURL.hostname; // Node.js module parses it as `::` |
| // `new URL(urlString, [baseURLString])` parses it as '[::]' |
| |
| var isInAddrAny = hostname === "0.0.0.0" || hostname === "::" || hostname === "[::]"; // why do we need this check? |
| // hostname n/a for file protocol (example, when using electron, ionic) |
| // see: https://github.com/webpack/webpack-dev-server/pull/384 |
| |
| if (isInAddrAny && self.location.hostname && self.location.protocol.indexOf("http") === 0) { |
| hostname = self.location.hostname; |
| } |
| |
| var socketURLProtocol = parsedURL.protocol || self.location.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:") { |
| socketURLProtocol = self.location.protocol; |
| } |
| |
| socketURLProtocol = socketURLProtocol.replace(/^(?:http|.+-extension|file)/i, "ws"); |
| var socketURLAuth = ""; // `new URL(urlString, [baseURLstring])` doesn't have `auth` property |
| // Parse authentication credentials in case we need them |
| |
| if (parsedURL.username) { |
| socketURLAuth = parsedURL.username; // Since HTTP basic authentication does not allow empty username, |
| // we only include password if the username is not empty. |
| |
| if (parsedURL.password) { |
| // Result: <username>:<password> |
| socketURLAuth = socketURLAuth.concat(":", parsedURL.password); |
| } |
| } // In case the host is a raw IPv6 address, it can be enclosed in |
| // the brackets as the brackets are needed in the final URL string. |
| // Need to remove those as url.format blindly adds its own set of brackets |
| // if the host string contains colons. That would lead to non-working |
| // double brackets (e.g. [[::]]) host |
| // |
| // All of these web socket url params are optionally passed in through resourceQuery, |
| // so we need to fall back to the default if they are not provided |
| |
| |
| var socketURLHostname = (hostname || self.location.hostname || "localhost").replace(/^\[(.*)\]$/, "$1"); |
| var socketURLPort = parsedURL.port; |
| |
| if (!socketURLPort || socketURLPort === "0") { |
| socketURLPort = self.location.port; |
| } // If path is provided it'll be passed in via the resourceQuery as a |
| // query param so it has to be parsed out of the querystring in order for the |
| // client to open the socket to the correct location. |
| |
| |
| var socketURLPathname = "/ws"; |
| |
| if (parsedURL.pathname && !parsedURL.fromCurrentScript) { |
| socketURLPathname = parsedURL.pathname; |
| } |
| |
| return format({ |
| protocol: socketURLProtocol, |
| auth: socketURLAuth, |
| hostname: socketURLHostname, |
| port: socketURLPort, |
| pathname: socketURLPathname, |
| slashes: true |
| }); |
| } |
| |
| export default createSocketURL; |