'use strict'; /* global self */ var url = require('url'); var getCurrentScriptSource = require('./getCurrentScriptSource'); function createSocketUrl(resourceQuery, currentLocation) { var urlParts; if (typeof resourceQuery === 'string' && resourceQuery !== '') { // If this bundle is inlined, use the resource query to get the correct url. // format is like `?http://0.0.0.0:8096&sockPort=8097&sockHost=localhost` urlParts = url.parse(resourceQuery // strip leading `?` from query string to get a valid URL .substr(1) // replace first `&` with `?` to have a valid query string .replace('&', '?'), true); } else { // Else, get the url from the <script> this file was called with. var scriptHost = getCurrentScriptSource(); urlParts = url.parse(scriptHost || '/', true, true); } // Use parameter to allow passing location in unit tests if (typeof currentLocation === 'string' && currentLocation !== '') { currentLocation = url.parse(currentLocation); } else { currentLocation = self.location; } return getSocketUrl(urlParts, currentLocation); } /* * Gets socket URL based on Script Source/Location * (scriptSrc: URL, location: URL) -> URL */ function getSocketUrl(urlParts, loc) { var auth = urlParts.auth, query = urlParts.query; var hostname = urlParts.hostname, protocol = urlParts.protocol, port = urlParts.port; if (!port || port === '0') { port = loc.port; } // check ipv4 and ipv6 `all 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 ((hostname === '0.0.0.0' || hostname === '::') && loc.hostname && loc.protocol.indexOf('http') === 0) { hostname = loc.hostname; } // `hostname` can be empty when the script path is relative. In that case, specifying // a protocol would result in an invalid URL. // When https is used in the app, secure websockets are always necessary // because the browser doesn't accept non-secure websockets. if (hostname && hostname !== '127.0.0.1' && (loc.protocol === 'https:' || urlParts.hostname === '0.0.0.0')) { protocol = loc.protocol; } // all of these sock url params are optionally passed in through // resourceQuery, so we need to fall back to the default if // they are not provided var sockHost = query.sockHost || hostname; var sockPath = query.sockPath || '/sockjs-node'; var sockPort = query.sockPort || port; if (sockPort === 'location') { sockPort = loc.port; } return url.format({ protocol: protocol, auth: auth, hostname: sockHost, port: sockPort, // If sockPath 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. pathname: sockPath }); } module.exports = createSocketUrl;