mockttp
Version:
Mock HTTP server for testing HTTP clients and stubbing webservices
154 lines • 5.69 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.normalizeUrl = exports.normalizeHost = exports.getDestination = exports.getEffectivePort = exports.getDefaultPort = exports.getPathFromAbsoluteUrl = exports.getHostFromAbsoluteUrl = exports.getUrlWithoutProtocol = exports.isAbsoluteProtocollessUrl = exports.isRelativeUrl = exports.isAbsoluteUrl = void 0;
const url = require("url");
const _ = require("lodash");
const util_1 = require("./util");
// Is this URL fully qualified?
// Note that this supports only HTTP - no websockets or anything else.
const isAbsoluteUrl = (url) => url.toLowerCase().startsWith('http://') ||
url.toLowerCase().startsWith('https://');
exports.isAbsoluteUrl = isAbsoluteUrl;
const isRelativeUrl = (url) => url.startsWith('/');
exports.isRelativeUrl = isRelativeUrl;
const isAbsoluteProtocollessUrl = (url) => !(0, exports.isAbsoluteUrl)(url) && !(0, exports.isRelativeUrl)(url);
exports.isAbsoluteProtocollessUrl = isAbsoluteProtocollessUrl;
const getUrlWithoutProtocol = (url) => {
return url.split('://', 2).slice(-1).join('');
};
exports.getUrlWithoutProtocol = getUrlWithoutProtocol;
const getHostFromAbsoluteUrl = (url) => {
const hostIndex = (0, util_1.nthIndexOf)(url, '/', 2);
const pathIndex = (0, util_1.nthIndexOf)(url, '/', 3);
if (pathIndex !== -1) {
return url.slice(hostIndex + 1, pathIndex);
}
else {
return url.slice(hostIndex + 1);
}
};
exports.getHostFromAbsoluteUrl = getHostFromAbsoluteUrl;
const getPathFromAbsoluteUrl = (url) => {
const pathIndex = (0, util_1.nthIndexOf)(url, '/', 3);
if (pathIndex !== -1) {
return url.slice(pathIndex);
}
else {
return '/';
}
};
exports.getPathFromAbsoluteUrl = getPathFromAbsoluteUrl;
const getDefaultPort = (protocol) => {
if (protocol[protocol.length - 1] === ':') {
protocol = protocol.slice(0, -1);
}
if (protocol === 'https' || protocol === 'wss') {
return 443;
}
else if (protocol === 'http' || protocol === 'ws') {
return 80;
}
else {
throw new Error(`Unknown protocol: ${protocol}`);
}
};
exports.getDefaultPort = getDefaultPort;
const getEffectivePort = (url) => {
if (url.port) {
return parseInt(url.port, 10);
}
else {
return (0, exports.getDefaultPort)(url.protocol || 'http');
}
};
exports.getEffectivePort = getEffectivePort;
const getDestination = (protocol, host) => {
let hostname;
let portString;
const lastColonIndex = host.lastIndexOf(':');
if (lastColonIndex !== -1) {
hostname = host.slice(0, lastColonIndex);
portString = host.slice(lastColonIndex + 1);
}
else {
hostname = host;
portString = undefined;
}
if (hostname[0] === '[' && hostname[hostname.length - 1] === ']') {
// Bracketed IPv6 address, drop the brackets:
hostname = hostname.slice(1, -1);
}
const port = portString
? parseInt(portString, 10)
: (0, exports.getDefaultPort)(protocol);
if (isNaN(port)) {
throw new Error(`Invalid port: ${portString}`);
}
return { hostname, port };
};
exports.getDestination = getDestination;
const normalizeHost = (protocol, host) => {
const { hostname, port } = (0, exports.getDestination)(protocol, host);
if (port === (0, exports.getDefaultPort)(protocol)) {
return hostname;
}
else {
return `${hostname}:${port}`;
}
};
exports.normalizeHost = normalizeHost;
/**
* Normalizes URLs to the form used when matching them.
*
* This accepts URLs in all three formats: relative, absolute, and protocolless-absolute,
* and returns them in the same format but normalized.
*/
exports.normalizeUrl = _.memoize((urlInput) => {
let parsedUrl;
let isProtocolless = false;
try {
// Strip the query and anything following it
const queryIndex = urlInput.indexOf('?');
if (queryIndex !== -1) {
urlInput = urlInput.slice(0, queryIndex);
}
if ((0, exports.isAbsoluteProtocollessUrl)(urlInput)) {
parsedUrl = url.parse('http://' + urlInput);
isProtocolless = true;
}
else {
parsedUrl = url.parse(urlInput);
}
// Trim out lots of the bits we don't like:
delete parsedUrl.host;
delete parsedUrl.query;
delete parsedUrl.search;
delete parsedUrl.hash;
if (parsedUrl.pathname) {
parsedUrl.pathname = parsedUrl.pathname.replace(/\%[A-Fa-z0-9]{2}/g, (encoded) => encoded.toUpperCase()).replace(/[^\u0000-\u007F]+/g, (unicodeChar) => encodeURIComponent(unicodeChar));
}
if (parsedUrl.hostname?.endsWith('.')) {
parsedUrl.hostname = parsedUrl.hostname.slice(0, -1);
}
if ((parsedUrl.protocol === 'https:' && parsedUrl.port === '443') ||
(parsedUrl.protocol === 'http:' && parsedUrl.port === '80')) {
delete parsedUrl.port;
}
}
catch (e) {
console.log(`Failed to normalize URL ${urlInput}`);
console.log(e);
if (!parsedUrl)
return urlInput; // Totally unparseble: use as-is
// If we've successfully parsed it, we format what we managed
// and leave it at that:
}
let normalizedUrl = url.format(parsedUrl);
// If the URL came in with no protocol, it should leave with
// no protocol (protocol added temporarily above to allow parsing)
if (isProtocolless) {
normalizedUrl = normalizedUrl.slice('http://'.length);
}
return normalizedUrl;
});
//# sourceMappingURL=url.js.map