You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
137 lines
4.3 KiB
137 lines
4.3 KiB
/** |
|
* @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; |