[6a3a178] | 1 | 'use strict';
|
---|
| 2 | /* global self */
|
---|
| 3 |
|
---|
| 4 | var url = require('url');
|
---|
| 5 |
|
---|
| 6 | var getCurrentScriptSource = require('./getCurrentScriptSource');
|
---|
| 7 |
|
---|
| 8 | function createSocketUrl(resourceQuery, currentLocation) {
|
---|
| 9 | var urlParts;
|
---|
| 10 |
|
---|
| 11 | if (typeof resourceQuery === 'string' && resourceQuery !== '') {
|
---|
| 12 | // If this bundle is inlined, use the resource query to get the correct url.
|
---|
| 13 | // format is like `?http://0.0.0.0:8096&sockPort=8097&sockHost=localhost`
|
---|
| 14 | urlParts = url.parse(resourceQuery // strip leading `?` from query string to get a valid URL
|
---|
| 15 | .substr(1) // replace first `&` with `?` to have a valid query string
|
---|
| 16 | .replace('&', '?'), true);
|
---|
| 17 | } else {
|
---|
| 18 | // Else, get the url from the <script> this file was called with.
|
---|
| 19 | var scriptHost = getCurrentScriptSource();
|
---|
| 20 | urlParts = url.parse(scriptHost || '/', true, true);
|
---|
| 21 | } // Use parameter to allow passing location in unit tests
|
---|
| 22 |
|
---|
| 23 |
|
---|
| 24 | if (typeof currentLocation === 'string' && currentLocation !== '') {
|
---|
| 25 | currentLocation = url.parse(currentLocation);
|
---|
| 26 | } else {
|
---|
| 27 | currentLocation = self.location;
|
---|
| 28 | }
|
---|
| 29 |
|
---|
| 30 | return getSocketUrl(urlParts, currentLocation);
|
---|
| 31 | }
|
---|
| 32 | /*
|
---|
| 33 | * Gets socket URL based on Script Source/Location
|
---|
| 34 | * (scriptSrc: URL, location: URL) -> URL
|
---|
| 35 | */
|
---|
| 36 |
|
---|
| 37 |
|
---|
| 38 | function getSocketUrl(urlParts, loc) {
|
---|
| 39 | var auth = urlParts.auth,
|
---|
| 40 | query = urlParts.query;
|
---|
| 41 | var hostname = urlParts.hostname,
|
---|
| 42 | protocol = urlParts.protocol,
|
---|
| 43 | port = urlParts.port;
|
---|
| 44 |
|
---|
| 45 | if (!port || port === '0') {
|
---|
| 46 | port = loc.port;
|
---|
| 47 | } // check ipv4 and ipv6 `all hostname`
|
---|
| 48 | // why do we need this check?
|
---|
| 49 | // hostname n/a for file protocol (example, when using electron, ionic)
|
---|
| 50 | // see: https://github.com/webpack/webpack-dev-server/pull/384
|
---|
| 51 |
|
---|
| 52 |
|
---|
| 53 | if ((hostname === '0.0.0.0' || hostname === '::') && loc.hostname && loc.protocol.indexOf('http') === 0) {
|
---|
| 54 | hostname = loc.hostname;
|
---|
| 55 | } // `hostname` can be empty when the script path is relative. In that case, specifying
|
---|
| 56 | // a protocol would result in an invalid URL.
|
---|
| 57 | // When https is used in the app, secure websockets are always necessary
|
---|
| 58 | // because the browser doesn't accept non-secure websockets.
|
---|
| 59 |
|
---|
| 60 |
|
---|
| 61 | if (hostname && hostname !== '127.0.0.1' && (loc.protocol === 'https:' || urlParts.hostname === '0.0.0.0')) {
|
---|
| 62 | protocol = loc.protocol;
|
---|
| 63 | } // all of these sock url params are optionally passed in through
|
---|
| 64 | // resourceQuery, so we need to fall back to the default if
|
---|
| 65 | // they are not provided
|
---|
| 66 |
|
---|
| 67 |
|
---|
| 68 | var sockHost = query.sockHost || hostname;
|
---|
| 69 | var sockPath = query.sockPath || '/sockjs-node';
|
---|
| 70 | var sockPort = query.sockPort || port;
|
---|
| 71 |
|
---|
| 72 | if (sockPort === 'location') {
|
---|
| 73 | sockPort = loc.port;
|
---|
| 74 | }
|
---|
| 75 |
|
---|
| 76 | return url.format({
|
---|
| 77 | protocol: protocol,
|
---|
| 78 | auth: auth,
|
---|
| 79 | hostname: sockHost,
|
---|
| 80 | port: sockPort,
|
---|
| 81 | // If sockPath is provided it'll be passed in via the resourceQuery as a
|
---|
| 82 | // query param so it has to be parsed out of the querystring in order for the
|
---|
| 83 | // client to open the socket to the correct location.
|
---|
| 84 | pathname: sockPath
|
---|
| 85 | });
|
---|
| 86 | }
|
---|
| 87 |
|
---|
| 88 | module.exports = createSocketUrl; |
---|