'use strict';
var url = require('url'); // We handle legacy API that is Node.js specific, and a newer API that implements the same WHATWG URL Standard used by web browsers
// Please look at https://nodejs.org/api/url.html#url_url_strings_and_url_objects
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 || 'ws:'; // 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 url.format({
protocol: socketURLProtocol,
auth: socketURLAuth,
hostname: socketURLHostname,
port: socketURLPort,
pathname: socketURLPathname,
slashes: true
});
}
module.exports = createSocketURL;