-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor(client): create createSocketUrl module into utils (#1954)
- Loading branch information
1 parent
9a1ad89
commit 1581adc
Showing
4 changed files
with
151 additions
and
72 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
'use strict'; | ||
|
||
/* global self */ | ||
|
||
const url = require('url'); | ||
const querystring = require('querystring'); | ||
const getCurrentScriptSource = require('./getCurrentScriptSource'); | ||
|
||
function createSocketUrl(resourceQuery) { | ||
let urlParts; | ||
|
||
if (typeof resourceQuery === 'string' && resourceQuery !== '') { | ||
// If this bundle is inlined, use the resource query to get the correct url. | ||
urlParts = url.parse(resourceQuery.substr(1)); | ||
} else { | ||
// Else, get the url from the <script> this file was called with. | ||
let scriptHost = getCurrentScriptSource(); | ||
|
||
// eslint-disable-next-line no-useless-escape | ||
scriptHost = scriptHost.replace(/\/[^\/]+$/, ''); | ||
urlParts = url.parse(scriptHost || '/', false, true); | ||
} | ||
|
||
if (!urlParts.port || urlParts.port === '0') { | ||
urlParts.port = self.location.port; | ||
} | ||
|
||
const { auth, path } = urlParts; | ||
let { hostname, protocol } = urlParts; | ||
|
||
// 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 === '::') && | ||
self.location.hostname && | ||
// eslint-disable-next-line no-bitwise | ||
!!~self.location.protocol.indexOf('http') | ||
) { | ||
hostname = self.location.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 && | ||
(self.location.protocol === 'https:' || urlParts.hostname === '0.0.0.0') | ||
) { | ||
protocol = self.location.protocol; | ||
} | ||
|
||
// default values of the sock url if they are not provided | ||
let sockHost = hostname; | ||
let sockPath = '/sockjs-node'; | ||
let sockPort = urlParts.port; | ||
|
||
// eslint-disable-next-line no-undefined | ||
if (path !== null && path !== undefined && path !== '/') { | ||
const parsedQuery = querystring.parse(path); | ||
// 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 | ||
sockHost = parsedQuery.sockHost || sockHost; | ||
sockPath = parsedQuery.sockPath || sockPath; | ||
sockPort = parsedQuery.sockPort || sockPort; | ||
} | ||
|
||
return url.format({ | ||
protocol, | ||
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; |
33 changes: 33 additions & 0 deletions
33
test/client/default/utils/__snapshots__/createSocketUrl.test.js.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`createSocketUrl should return the url when __resourceQuery is ?test 1`] = `"/sockjs-node"`; | ||
|
||
exports[`createSocketUrl should return the url when __resourceQuery is http://0.0.0.0 1`] = `"http://localhost/sockjs-node"`; | ||
|
||
exports[`createSocketUrl should return the url when __resourceQuery is http://user:pass@[::]:8080 1`] = `"ttp:user:pass@localhost:8080/sockjs-node"`; | ||
|
||
exports[`createSocketUrl should return the url when __resourceQuery is http://user:password@localhost/ 1`] = `"ttp:user:password@localhost/sockjs-node"`; | ||
|
||
exports[`createSocketUrl should return the url when __resourceQuery is https://example.com 1`] = `"ttps:example.com/sockjs-node"`; | ||
|
||
exports[`createSocketUrl should return the url when __resourceQuery is https://example.com/path 1`] = `"ttps:example.com/sockjs-node"`; | ||
|
||
exports[`createSocketUrl should return the url when __resourceQuery is https://example.com/path/foo.js 1`] = `"ttps:example.com/sockjs-node"`; | ||
|
||
exports[`createSocketUrl should return the url when __resourceQuery is https://localhost:123 1`] = `"ttps:localhost:123/sockjs-node"`; | ||
|
||
exports[`createSocketUrl should return the url when the current script source is ?test 1`] = `"/sockjs-node"`; | ||
|
||
exports[`createSocketUrl should return the url when the current script source is http://0.0.0.0 1`] = `"http:/sockjs-node"`; | ||
|
||
exports[`createSocketUrl should return the url when the current script source is http://user:pass@[::]:8080 1`] = `"http:/sockjs-node"`; | ||
|
||
exports[`createSocketUrl should return the url when the current script source is http://user:password@localhost/ 1`] = `"http://user:password@localhost/sockjs-node"`; | ||
|
||
exports[`createSocketUrl should return the url when the current script source is https://example.com 1`] = `"https:/sockjs-node"`; | ||
|
||
exports[`createSocketUrl should return the url when the current script source is https://example.com/path 1`] = `"https://example.com/sockjs-node"`; | ||
|
||
exports[`createSocketUrl should return the url when the current script source is https://example.com/path/foo.js 1`] = `"https://example.com/sockjs-node"`; | ||
|
||
exports[`createSocketUrl should return the url when the current script source is https://localhost:123 1`] = `"https:/sockjs-node"`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
'use strict'; | ||
|
||
describe('createSocketUrl', () => { | ||
const samples = [ | ||
'?test', | ||
'https://example.com', | ||
'https://example.com/path', | ||
'https://example.com/path/foo.js', | ||
'http://user:password@localhost/', | ||
'http://0.0.0.0', | ||
'https://localhost:123', | ||
'http://user:pass@[::]:8080', | ||
// TODO: comment out after the major release | ||
// https://github.com/webpack/webpack-dev-server/pull/1954#issuecomment-498043376 | ||
// 'file://filename', | ||
]; | ||
|
||
samples.forEach((url) => { | ||
jest.doMock('../../../../client-src/default/utils/getCurrentScriptSource.js', () => () => url); | ||
const createSocketUrl = require('../../../../client-src/default/utils/createSocketUrl'); | ||
|
||
test(`should return the url when __resourceQuery is ${url}`, () => { | ||
expect(createSocketUrl(url)).toMatchSnapshot(); | ||
}); | ||
|
||
test(`should return the url when the current script source is ${url}`, () => { | ||
expect(createSocketUrl()).toMatchSnapshot(); | ||
}); | ||
|
||
// put here because resetModules mustn't be reset when L20 is finished | ||
jest.resetModules(); | ||
}); | ||
}); |