Spaces:
Sleeping
Sleeping
File size: 4,772 Bytes
cc651f6 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
const getCurrentScriptSource = require('./getCurrentScriptSource.js');
/**
* @typedef {Object} SocketUrlParts
* @property {string} [auth]
* @property {string} hostname
* @property {string} [protocol]
* @property {string} pathname
* @property {string} [port]
*/
/**
* Parse current location and Webpack's `__resourceQuery` into parts that can create a valid socket URL.
* @param {string} [resourceQuery] The Webpack `__resourceQuery` string.
* @param {import('./getWDSMetadata').WDSMetaObj} [metadata] The parsed WDS metadata object.
* @returns {SocketUrlParts} The parsed URL parts.
* @see https://webpack.js.org/api/module-variables/#__resourcequery-webpack-specific
*/
function getSocketUrlParts(resourceQuery, metadata) {
if (typeof metadata === 'undefined') {
metadata = {};
}
/** @type {SocketUrlParts} */
let urlParts = {};
// If the resource query is available,
// parse it and ignore everything we received from the script host.
if (resourceQuery) {
const parsedQuery = {};
const searchParams = new URLSearchParams(resourceQuery.slice(1));
searchParams.forEach(function (value, key) {
parsedQuery[key] = value;
});
urlParts.hostname = parsedQuery.sockHost;
urlParts.pathname = parsedQuery.sockPath;
urlParts.port = parsedQuery.sockPort;
// Make sure the protocol from resource query has a trailing colon
if (parsedQuery.sockProtocol) {
urlParts.protocol = parsedQuery.sockProtocol + ':';
}
} else {
const scriptSource = getCurrentScriptSource();
let url = {};
try {
// The placeholder `baseURL` with `window.location.href`,
// is to allow parsing of path-relative or protocol-relative URLs,
// and will have no effect if `scriptSource` is a fully valid URL.
url = new URL(scriptSource, window.location.href);
} catch (e) {
// URL parsing failed, do nothing.
// We will still proceed to see if we can recover using `resourceQuery`
}
// Parse authentication credentials in case we need them
if (url.username) {
// Since HTTP basic authentication does not allow empty username,
// we only include password if the username is not empty.
// Result: <username> or <username>:<password>
urlParts.auth = url.username;
if (url.password) {
urlParts.auth += ':' + url.password;
}
}
// `file://` URLs has `'null'` origin
if (url.origin !== 'null') {
urlParts.hostname = url.hostname;
}
urlParts.protocol = url.protocol;
urlParts.port = url.port;
}
if (!urlParts.pathname) {
if (metadata.version === 4) {
// This is hard-coded in WDS v4
urlParts.pathname = '/ws';
} else {
// This is hard-coded in WDS v3
urlParts.pathname = '/sockjs-node';
}
}
// Check for IPv4 and IPv6 host addresses that correspond to any/empty.
// This is important because `hostname` can be empty for some hosts,
// such as 'about:blank' or 'file://' URLs.
const isEmptyHostname =
urlParts.hostname === '0.0.0.0' || urlParts.hostname === '[::]' || !urlParts.hostname;
// We only re-assign the hostname if it is empty,
// and if we are using HTTP/HTTPS protocols.
if (
isEmptyHostname &&
window.location.hostname &&
window.location.protocol.indexOf('http') === 0
) {
urlParts.hostname = window.location.hostname;
}
// We only re-assign `protocol` when `protocol` is unavailable,
// or if `hostname` is available and is empty,
// since otherwise we risk creating an invalid URL.
// We also do this when no sockProtocol was passed to the config and 'https' is used,
// as it mandates the use of secure sockets.
if (
!urlParts.protocol ||
(urlParts.hostname &&
(isEmptyHostname || (!resourceQuery && window.location.protocol === 'https:')))
) {
urlParts.protocol = window.location.protocol;
}
// We only re-assign port when it is not available
if (!urlParts.port) {
urlParts.port = window.location.port;
}
if (!urlParts.hostname || !urlParts.pathname) {
throw new Error(
[
'[React Refresh] Failed to get an URL for the socket connection.',
"This usually means that the current executed script doesn't have a `src` attribute set.",
'You should either specify the socket path parameters under the `devServer` key in your Webpack config, or use the `overlay` option.',
'https://github.com/pmmmwh/react-refresh-webpack-plugin/blob/main/docs/API.md#overlay',
].join('\n')
);
}
return {
auth: urlParts.auth,
hostname: urlParts.hostname,
pathname: urlParts.pathname,
protocol: urlParts.protocol,
port: urlParts.port || undefined,
};
}
module.exports = getSocketUrlParts;
|