3086 lines
156 KiB
JavaScript
3086 lines
156 KiB
JavaScript
(function () {
|
|
|
|
/******************************************************************************
|
|
Copyright (c) Microsoft Corporation.
|
|
|
|
Permission to use, copy, modify, and/or distribute this software for any
|
|
purpose with or without fee is hereby granted.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
PERFORMANCE OF THIS SOFTWARE.
|
|
***************************************************************************** */
|
|
/* global Reflect, Promise */
|
|
|
|
var extendStatics = function(d, b) {
|
|
extendStatics = Object.setPrototypeOf ||
|
|
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
|
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
|
|
return extendStatics(d, b);
|
|
};
|
|
|
|
function __extends(d, b) {
|
|
if (typeof b !== "function" && b !== null)
|
|
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
|
|
extendStatics(d, b);
|
|
function __() { this.constructor = d; }
|
|
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
|
}
|
|
|
|
function __spreadArray(to, from, pack) {
|
|
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
if (ar || !(i in from)) {
|
|
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
ar[i] = from[i];
|
|
}
|
|
}
|
|
return to.concat(ar || Array.prototype.slice.call(from));
|
|
}
|
|
|
|
// -------------------------------------------------------------
|
|
// WARNING: this file is used by both the client and the server.
|
|
// Do not use any browser or node-specific API!
|
|
// -------------------------------------------------------------
|
|
// NOTE: Some websites override the String.prototype.trim method. When we use this function
|
|
// in our scripts, we expect it to have the default behavior. Therefore, in order to protect
|
|
// ourselves from spoofing, we must use our own implementation. Also, we cannot use the
|
|
// String.prototype.trim method because on the client-side it is the same in the top window and
|
|
// an iframe window. The client code may override this method in the top window before the
|
|
// iframe is initialized, so that the iframe will lose access to the native method.
|
|
function trim (str) {
|
|
return typeof str === 'string' ? str.replace(/(^\s+)|(\s+$)/g, '') : str;
|
|
}
|
|
|
|
// -------------------------------------------------------------
|
|
var URL_RE = /^\s*([\w-]+?:)?(?:\/\/(?:([^/]+)@)?(([^/%?;#: ]*)(?::(\d+))?))?(.*?)\s*$/;
|
|
var PROTOCOL_RE = /^([\w-]+?:)(\/\/|[^\\/]|$)/;
|
|
var PATH_AFTER_HOST_RE = /^\/([^/]+?)\/([\S\s]+)$/;
|
|
var FILE_RE = /^file:/i;
|
|
var SHORT_ORIGIN_RE = /^http(s)?:\/\//;
|
|
var IS_SECURE_ORIGIN_RE = /^s\*/;
|
|
var SUPPORTED_PROTOCOL_RE = /^(?:https?|file):/i;
|
|
var HASH_RE = /^#/;
|
|
var REQUEST_DESCRIPTOR_VALUES_SEPARATOR = '!';
|
|
var REQUEST_DESCRIPTOR_SESSION_INFO_VALUES_SEPARATOR = '*';
|
|
var TRAILING_SLASH_RE = /\/$/;
|
|
var SPECIAL_BLANK_PAGE = 'about:blank';
|
|
var SPECIAL_ERROR_PAGE = 'about:error';
|
|
var SPECIAL_PAGES = [SPECIAL_BLANK_PAGE, SPECIAL_ERROR_PAGE];
|
|
var HTTP_DEFAULT_PORT = '80';
|
|
var HTTPS_DEFAULT_PORT = '443';
|
|
var Credentials;
|
|
(function (Credentials) {
|
|
Credentials[Credentials["include"] = 0] = "include";
|
|
Credentials[Credentials["sameOrigin"] = 1] = "sameOrigin";
|
|
Credentials[Credentials["omit"] = 2] = "omit";
|
|
Credentials[Credentials["unknown"] = 3] = "unknown";
|
|
})(Credentials || (Credentials = {})); // eslint-disable-line no-shadow
|
|
var SPECIAL_PAGE_DEST_RESOURCE_INFO = {
|
|
protocol: 'about:',
|
|
host: '',
|
|
hostname: '',
|
|
port: '',
|
|
partAfterHost: '',
|
|
};
|
|
var RESOURCE_TYPES = [
|
|
{ name: 'isIframe', flag: 'i' },
|
|
{ name: 'isForm', flag: 'f' },
|
|
{ name: 'isScript', flag: 's' },
|
|
{ name: 'isEventSource', flag: 'e' },
|
|
{ name: 'isHtmlImport', flag: 'h' },
|
|
{ name: 'isWebSocket', flag: 'w' },
|
|
{ name: 'isServiceWorker', flag: 'c' },
|
|
{ name: 'isAjax', flag: 'a' },
|
|
{ name: 'isObject', flag: 'o' },
|
|
];
|
|
function parseResourceType(resourceType) {
|
|
var parsedResourceType = {};
|
|
if (!resourceType)
|
|
return parsedResourceType;
|
|
for (var _i = 0, RESOURCE_TYPES_1 = RESOURCE_TYPES; _i < RESOURCE_TYPES_1.length; _i++) {
|
|
var _a = RESOURCE_TYPES_1[_i], name_1 = _a.name, flag = _a.flag;
|
|
if (resourceType.indexOf(flag) > -1)
|
|
parsedResourceType[name_1] = true;
|
|
}
|
|
return parsedResourceType;
|
|
}
|
|
function getResourceTypeString(parsedResourceType) {
|
|
if (!parsedResourceType)
|
|
return null;
|
|
var resourceType = '';
|
|
for (var _i = 0, RESOURCE_TYPES_2 = RESOURCE_TYPES; _i < RESOURCE_TYPES_2.length; _i++) {
|
|
var _a = RESOURCE_TYPES_2[_i], name_2 = _a.name, flag = _a.flag;
|
|
if (parsedResourceType[name_2])
|
|
resourceType += flag;
|
|
}
|
|
return resourceType || null;
|
|
}
|
|
function makeShortOrigin(origin) {
|
|
return origin === 'null' ? '' : origin.replace(SHORT_ORIGIN_RE, function (_, secure) { return secure ? 's*' : ''; });
|
|
}
|
|
function restoreShortOrigin(origin) {
|
|
if (!origin)
|
|
return 'null';
|
|
return IS_SECURE_ORIGIN_RE.test(origin) ? origin.replace(IS_SECURE_ORIGIN_RE, 'https://') : 'http://' + origin;
|
|
}
|
|
function sameOriginCheck$1(location, checkedUrl) {
|
|
if (!checkedUrl)
|
|
return true;
|
|
var parsedCheckedUrl = parseUrl$1(checkedUrl);
|
|
var isRelative = !parsedCheckedUrl.host;
|
|
if (isRelative)
|
|
return true;
|
|
var parsedLocation = parseUrl$1(location);
|
|
var parsedProxyLocation = parseProxyUrl$1(location);
|
|
if (parsedCheckedUrl.host === parsedLocation.host && parsedCheckedUrl.protocol === parsedLocation.protocol)
|
|
return true;
|
|
var parsedDestUrl = parsedProxyLocation ? parsedProxyLocation.destResourceInfo : parsedLocation;
|
|
if (!parsedDestUrl)
|
|
return false;
|
|
var isSameProtocol = !parsedCheckedUrl.protocol || parsedCheckedUrl.protocol === parsedDestUrl.protocol;
|
|
var portsEq = !parsedDestUrl.port && !parsedCheckedUrl.port ||
|
|
parsedDestUrl.port && parsedDestUrl.port.toString() === parsedCheckedUrl.port;
|
|
return isSameProtocol && !!portsEq && parsedDestUrl.hostname === parsedCheckedUrl.hostname;
|
|
}
|
|
// NOTE: Convert the destination protocol and hostname to the lower case. (GH-1)
|
|
function convertHostToLowerCase(url) {
|
|
var parsedUrl = parseUrl$1(url);
|
|
parsedUrl.protocol = parsedUrl.protocol && parsedUrl.protocol.toLowerCase();
|
|
parsedUrl.host = parsedUrl.host && parsedUrl.host.toLowerCase();
|
|
return formatUrl(parsedUrl);
|
|
}
|
|
function getURLString(url) {
|
|
// TODO: fix it
|
|
// eslint-disable-next-line no-undef
|
|
if (url === null && /iPad|iPhone/i.test(window.navigator.userAgent))
|
|
return '';
|
|
return String(url).replace(/[\n\t]/g, '');
|
|
}
|
|
function getProxyUrl$1(url, opts) {
|
|
var sessionInfo = [opts.sessionId];
|
|
if (opts.windowId)
|
|
sessionInfo.push(opts.windowId);
|
|
var params = [sessionInfo.join(REQUEST_DESCRIPTOR_SESSION_INFO_VALUES_SEPARATOR)];
|
|
if (opts.resourceType)
|
|
params.push(opts.resourceType);
|
|
if (opts.charset)
|
|
params.push(opts.charset.toLowerCase());
|
|
if (typeof opts.credentials === 'number')
|
|
params.push(opts.credentials.toString());
|
|
if (opts.reqOrigin)
|
|
params.push(encodeURIComponent(makeShortOrigin(opts.reqOrigin)));
|
|
var descriptor = params.join(REQUEST_DESCRIPTOR_VALUES_SEPARATOR);
|
|
var proxyProtocol = opts.proxyProtocol || 'http:';
|
|
return "".concat(proxyProtocol, "//").concat(opts.proxyHostname, ":").concat(opts.proxyPort, "/").concat(descriptor, "/").concat(convertHostToLowerCase(url));
|
|
}
|
|
function getDomain(parsed) {
|
|
if (parsed.protocol === 'file:')
|
|
return 'null';
|
|
return formatUrl({
|
|
protocol: parsed.protocol,
|
|
host: parsed.host,
|
|
hostname: parsed.hostname,
|
|
port: String(parsed.port || ''),
|
|
});
|
|
}
|
|
function parseRequestDescriptor(desc) {
|
|
var _a = desc.split(REQUEST_DESCRIPTOR_VALUES_SEPARATOR), sessionInfo = _a[0], resourceType = _a[1], resourceData = _a.slice(2);
|
|
if (!sessionInfo)
|
|
return null;
|
|
var _b = sessionInfo.split(REQUEST_DESCRIPTOR_SESSION_INFO_VALUES_SEPARATOR), sessionId = _b[0], windowId = _b[1];
|
|
var parsedDesc = { sessionId: sessionId, resourceType: resourceType || null };
|
|
if (windowId)
|
|
parsedDesc.windowId = windowId;
|
|
if (resourceType && resourceData.length) {
|
|
var parsedResourceType = parseResourceType(resourceType);
|
|
if (parsedResourceType.isScript || parsedResourceType.isServiceWorker)
|
|
parsedDesc.charset = resourceData[0];
|
|
else if (parsedResourceType.isWebSocket)
|
|
parsedDesc.reqOrigin = decodeURIComponent(restoreShortOrigin(resourceData[0]));
|
|
else if (parsedResourceType.isIframe && resourceData[0])
|
|
parsedDesc.reqOrigin = decodeURIComponent(restoreShortOrigin(resourceData[0]));
|
|
else if (parsedResourceType.isAjax) {
|
|
parsedDesc.credentials = parseInt(resourceData[0], 10);
|
|
if (resourceData.length === 2)
|
|
parsedDesc.reqOrigin = decodeURIComponent(restoreShortOrigin(resourceData[1]));
|
|
}
|
|
}
|
|
return parsedDesc;
|
|
}
|
|
function parseProxyUrl$1(proxyUrl) {
|
|
// TODO: Remove it.
|
|
var parsedUrl = parseUrl$1(proxyUrl);
|
|
if (!parsedUrl.partAfterHost)
|
|
return null;
|
|
var match = parsedUrl.partAfterHost.match(PATH_AFTER_HOST_RE);
|
|
if (!match)
|
|
return null;
|
|
var parsedDesc = parseRequestDescriptor(match[1]);
|
|
// NOTE: We should have, at least, the job uid and the owner token.
|
|
if (!parsedDesc)
|
|
return null;
|
|
var destUrl = match[2];
|
|
// Browser can redirect to a special page with hash (GH-1671)
|
|
var destUrlWithoutHash = destUrl.replace(/#[\S\s]*$/, '');
|
|
if (!isSpecialPage$1(destUrlWithoutHash) && !SUPPORTED_PROTOCOL_RE.test(destUrl))
|
|
return null;
|
|
var destResourceInfo;
|
|
if (isSpecialPage$1(destUrlWithoutHash))
|
|
destResourceInfo = SPECIAL_PAGE_DEST_RESOURCE_INFO;
|
|
else {
|
|
destUrl = omitDefaultPort(destUrl);
|
|
destResourceInfo = parseUrl$1(destUrl);
|
|
}
|
|
return {
|
|
destUrl: destUrl,
|
|
destResourceInfo: destResourceInfo,
|
|
partAfterHost: parsedUrl.partAfterHost,
|
|
proxy: {
|
|
hostname: parsedUrl.hostname || '',
|
|
port: parsedUrl.port || '',
|
|
},
|
|
sessionId: parsedDesc.sessionId,
|
|
resourceType: parsedDesc.resourceType,
|
|
charset: parsedDesc.charset,
|
|
reqOrigin: parsedDesc.reqOrigin,
|
|
windowId: parsedDesc.windowId,
|
|
credentials: parsedDesc.credentials,
|
|
};
|
|
}
|
|
function parseUrl$1(url) {
|
|
url = processSpecialChars(url);
|
|
if (!url)
|
|
return {};
|
|
var urlMatch = url.match(URL_RE);
|
|
return urlMatch ? {
|
|
protocol: urlMatch[1],
|
|
auth: urlMatch[2],
|
|
host: urlMatch[3],
|
|
hostname: urlMatch[4],
|
|
port: urlMatch[5],
|
|
partAfterHost: urlMatch[6],
|
|
} : {};
|
|
}
|
|
function isSupportedProtocol$1(url) {
|
|
url = trim(url || '');
|
|
var isHash = HASH_RE.test(url);
|
|
if (isHash)
|
|
return false;
|
|
var protocol = url.match(PROTOCOL_RE);
|
|
if (!protocol)
|
|
return true;
|
|
return SUPPORTED_PROTOCOL_RE.test(protocol[0]);
|
|
}
|
|
function resolveUrlAsDest$1(url, getProxyUrlMeth, isUrlsSet) {
|
|
if (isUrlsSet === void 0) { isUrlsSet = false; }
|
|
if (isUrlsSet)
|
|
return handleUrlsSet(resolveUrlAsDest$1, url, getProxyUrlMeth);
|
|
getProxyUrlMeth = getProxyUrlMeth || getProxyUrl$1;
|
|
if (isSupportedProtocol$1(url)) {
|
|
var proxyUrl = getProxyUrlMeth(url);
|
|
var parsedProxyUrl = parseProxyUrl$1(proxyUrl);
|
|
return parsedProxyUrl ? formatUrl(parsedProxyUrl.destResourceInfo) : url;
|
|
}
|
|
return url;
|
|
}
|
|
function formatUrl(parsedUrl) {
|
|
// NOTE: the URL is relative.
|
|
if (parsedUrl.protocol !== 'file:' && parsedUrl.protocol !== 'about:' &&
|
|
!parsedUrl.host && (!parsedUrl.hostname || !parsedUrl.port))
|
|
return parsedUrl.partAfterHost || '';
|
|
var url = parsedUrl.protocol || '';
|
|
if (parsedUrl.protocol !== 'about:')
|
|
url += '//';
|
|
if (parsedUrl.auth)
|
|
url += parsedUrl.auth + '@';
|
|
if (parsedUrl.host)
|
|
url += parsedUrl.host;
|
|
else if (parsedUrl.hostname) {
|
|
url += parsedUrl.hostname;
|
|
if (parsedUrl.port)
|
|
url += ':' + parsedUrl.port;
|
|
}
|
|
if (parsedUrl.partAfterHost)
|
|
url += parsedUrl.partAfterHost;
|
|
return url;
|
|
}
|
|
function handleUrlsSet(handler, url) {
|
|
var args = [];
|
|
for (var _i = 2; _i < arguments.length; _i++) {
|
|
args[_i - 2] = arguments[_i];
|
|
}
|
|
var resourceUrls = url.split(',');
|
|
var replacedUrls = [];
|
|
for (var _a = 0, resourceUrls_1 = resourceUrls; _a < resourceUrls_1.length; _a++) {
|
|
var fullUrlStr = resourceUrls_1[_a];
|
|
var _b = fullUrlStr.replace(/ +/g, ' ').trim().split(' '), urlStr = _b[0], postUrlStr = _b[1];
|
|
if (urlStr) {
|
|
var replacedUrl = handler.apply(void 0, __spreadArray([urlStr], args, false));
|
|
replacedUrls.push(replacedUrl + (postUrlStr ? " ".concat(postUrlStr) : ''));
|
|
}
|
|
}
|
|
return replacedUrls.join(',');
|
|
}
|
|
function correctMultipleSlashes(url, pageProtocol) {
|
|
if (pageProtocol === void 0) { pageProtocol = ''; }
|
|
// NOTE: Remove unnecessary slashes from the beginning of the url and after scheme.
|
|
// For example:
|
|
// "//////example.com" -> "//example.com" (scheme-less HTTP(S) URL)
|
|
// "////home/testcafe/documents" -> "///home/testcafe/documents" (scheme-less unix file URL)
|
|
// "http:///example.com" -> "http://example.com"
|
|
//
|
|
// And add missing slashes after the file scheme.
|
|
// "file://C:/document.txt" -> "file:///C:/document.txt"
|
|
if (url.match(FILE_RE) || pageProtocol.match(FILE_RE)) {
|
|
return url
|
|
.replace(/^(file:)?\/+(\/\/\/.*$)/i, '$1$2')
|
|
.replace(/^(file:)?\/*([A-Za-z]):/i, '$1///$2:');
|
|
}
|
|
return url.replace(/^(https?:)?\/+(\/\/.*$)/i, '$1$2');
|
|
}
|
|
function processSpecialChars(url) {
|
|
return correctMultipleSlashes(getURLString(url));
|
|
}
|
|
function ensureTrailingSlash(srcUrl, processedUrl) {
|
|
if (!isValidUrl(processedUrl))
|
|
return processedUrl;
|
|
var srcUrlEndsWithTrailingSlash = TRAILING_SLASH_RE.test(srcUrl);
|
|
var processedUrlEndsWithTrailingSlash = TRAILING_SLASH_RE.test(processedUrl);
|
|
if (srcUrlEndsWithTrailingSlash && !processedUrlEndsWithTrailingSlash)
|
|
processedUrl += '/';
|
|
else if (srcUrl && !srcUrlEndsWithTrailingSlash && processedUrlEndsWithTrailingSlash)
|
|
processedUrl = processedUrl.replace(TRAILING_SLASH_RE, '');
|
|
return processedUrl;
|
|
}
|
|
function isSpecialPage$1(url) {
|
|
return SPECIAL_PAGES.indexOf(url) !== -1;
|
|
}
|
|
function isValidPort(port) {
|
|
var parsedPort = parseInt(port, 10);
|
|
return parsedPort > 0 && parsedPort <= 65535;
|
|
}
|
|
function isValidUrl(url) {
|
|
var parsedUrl = parseUrl$1(url);
|
|
return parsedUrl.protocol === 'file:' || parsedUrl.protocol === 'about:' ||
|
|
!!parsedUrl.hostname && (!parsedUrl.port || isValidPort(parsedUrl.port));
|
|
}
|
|
function omitDefaultPort(url) {
|
|
// NOTE: If you request an url containing default port
|
|
// then browser remove this one itself.
|
|
var parsedUrl = parseUrl$1(url);
|
|
var hasDefaultPort = parsedUrl.protocol === 'https:' && parsedUrl.port === HTTPS_DEFAULT_PORT ||
|
|
parsedUrl.protocol === 'http:' && parsedUrl.port === HTTP_DEFAULT_PORT;
|
|
if (hasDefaultPort) {
|
|
parsedUrl.host = parsedUrl.hostname;
|
|
parsedUrl.port = '';
|
|
return formatUrl(parsedUrl);
|
|
}
|
|
return url;
|
|
}
|
|
|
|
// -------------------------------------------------------------
|
|
// WARNING: this file is used by both the client and the server.
|
|
// Do not use any browser or node-specific API!
|
|
// -------------------------------------------------------------
|
|
var INTERNAL_PROPS = {
|
|
processDomMethodName: 'hammerhead|process-dom-method',
|
|
processedContext: 'hammerhead|processed-context',
|
|
documentWasCleaned: 'hammerhead|document-was-cleaned',
|
|
documentCharset: 'hammerhead|document-charset',
|
|
iframeNativeMethods: 'hammerhead|iframe-native-methods',
|
|
hammerhead: '%hammerhead%',
|
|
selection: 'hammerhead|selection',
|
|
shadowUIElement: 'hammerhead|shadow-ui-element',
|
|
forceProxySrcForImage: 'hammerhead|image|force-proxy-src-flag',
|
|
skipNextLoadEventForImage: 'hammerhead|image|skip-next-load-event-flag',
|
|
cachedImage: 'hammerhead|image|cached-image',
|
|
sandboxIsReattached: 'hammerhead|sandbox-is-reattached',
|
|
nativeStrRepresentation: 'hammerhead|native-string-representation',
|
|
currentBaseUrl: 'hammerhead|current-base-url',
|
|
};
|
|
|
|
// -------------------------------------------------------------
|
|
// WARNING: this file is used by both the client and the server.
|
|
// Do not use any browser or node-specific API!
|
|
// -------------------------------------------------------------
|
|
var INTERNAL_ATTRS = {
|
|
storedAttrPostfix: '-hammerhead-stored-value',
|
|
hoverPseudoClass: 'data-hammerhead-hovered',
|
|
focusPseudoClass: 'data-hammerhead-focused',
|
|
uploadInfoHiddenInputName: 'hammerhead|upload-info-hidden-input-name',
|
|
};
|
|
|
|
var isInWorker = typeof window === 'undefined' && typeof self === 'object';
|
|
var global$1 = (isInWorker ? self : window);
|
|
var globalContextInfo = {
|
|
isInWorker: isInWorker,
|
|
global: global$1,
|
|
isServiceWorker: isInWorker && !global$1.XMLHttpRequest,
|
|
};
|
|
|
|
function replaceNativeAccessor(descriptor, accessorName, newAccessor) {
|
|
if (newAccessor && descriptor[accessorName]) {
|
|
var stringifiedNativeAccessor_1 = descriptor[accessorName].toString();
|
|
newAccessor.toString = function () { return stringifiedNativeAccessor_1; };
|
|
}
|
|
descriptor[accessorName] = newAccessor;
|
|
}
|
|
function createOverriddenDescriptor(obj, prop, _a) {
|
|
var getter = _a.getter, setter = _a.setter, value = _a.value;
|
|
var descriptor = nativeMethods.objectGetOwnPropertyDescriptor(obj, prop);
|
|
if ((getter || setter) && value)
|
|
throw new Error('Cannot both specify accessors and a value or writable attribute.');
|
|
if (!descriptor)
|
|
return void 0;
|
|
if (value) {
|
|
if (!nativeMethods.objectHasOwnProperty.call(descriptor, 'writable')) {
|
|
descriptor.writable = !!descriptor.set;
|
|
delete descriptor.get;
|
|
delete descriptor.set;
|
|
}
|
|
descriptor.value = value; // eslint-disable-line no-restricted-properties
|
|
}
|
|
else {
|
|
if (nativeMethods.objectHasOwnProperty.call(descriptor, 'writable')) {
|
|
delete descriptor.value; // eslint-disable-line no-restricted-properties
|
|
delete descriptor.writable;
|
|
}
|
|
if (getter !== null)
|
|
replaceNativeAccessor(descriptor, 'get', getter);
|
|
if (setter !== null)
|
|
replaceNativeAccessor(descriptor, 'set', setter);
|
|
}
|
|
return descriptor;
|
|
}
|
|
function overrideDescriptor(obj, prop, propertyAccessors) {
|
|
if (!obj)
|
|
return;
|
|
var descriptor = createOverriddenDescriptor(obj, prop, propertyAccessors);
|
|
if (descriptor)
|
|
nativeMethods.objectDefineProperty(obj, prop, descriptor);
|
|
else
|
|
overrideDescriptor(nativeMethods.objectGetPrototypeOf(obj), prop, propertyAccessors);
|
|
}
|
|
function overrideFunctionName(fn, name) {
|
|
var nameDescriptor = nativeMethods.objectGetOwnPropertyDescriptor(fn, 'name');
|
|
if (!nameDescriptor)
|
|
return;
|
|
nameDescriptor.value = name; // eslint-disable-line no-restricted-properties
|
|
nativeMethods.objectDefineProperty(fn, 'name', nameDescriptor);
|
|
}
|
|
function overrideToString(nativeFnWrapper, nativeFn) {
|
|
nativeMethods.objectDefineProperty(nativeFnWrapper, INTERNAL_PROPS.nativeStrRepresentation, {
|
|
value: nativeMethods.Function.prototype.toString.call(nativeFn),
|
|
configurable: true,
|
|
});
|
|
}
|
|
// TODO: this function should not be used outside this file
|
|
// for now it's used to flag cases in which we assign our wrapper to a native function when it is missing
|
|
function overrideStringRepresentation(nativeFnWrapper, nativeFn) {
|
|
overrideFunctionName(nativeFnWrapper, nativeFn.name);
|
|
overrideToString(nativeFnWrapper, nativeFn);
|
|
}
|
|
function isNativeFunction(fn) {
|
|
return !nativeMethods.objectHasOwnProperty.call(fn, INTERNAL_PROPS.nativeStrRepresentation);
|
|
}
|
|
function overrideFunction(obj, fnName, wrapper) {
|
|
var fn = obj[fnName];
|
|
if (isNativeFunction(fn)) {
|
|
overrideStringRepresentation(wrapper, fn);
|
|
obj[fnName] = wrapper;
|
|
}
|
|
}
|
|
function overrideConstructor(obj, fnName, wrapper, overrideProtoConstructor) {
|
|
if (overrideProtoConstructor === void 0) { overrideProtoConstructor = false; }
|
|
var nativePrototype = obj[fnName]['prototype'];
|
|
overrideFunction(obj, fnName, wrapper);
|
|
// NOTE: restore native prototype (to make `instanceof` work as expected)
|
|
wrapper.prototype = nativePrototype;
|
|
// NOTE: we need to override the `constructor` property of a prototype
|
|
// because sometimes native constructor can be retrieved from it
|
|
if (overrideProtoConstructor)
|
|
nativePrototype.constructor = wrapper;
|
|
}
|
|
|
|
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
|
|
|
|
function createCommonjsModule(fn) {
|
|
var module = { exports: {} };
|
|
return fn(module, module.exports), module.exports;
|
|
}
|
|
|
|
/*!
|
|
* Bowser - a browser detector
|
|
* https://github.com/ded/bowser
|
|
* MIT License | (c) Dustin Diaz 2015
|
|
*/
|
|
|
|
var bowser = createCommonjsModule(function (module) {
|
|
!function (root, name, definition) {
|
|
if (module.exports) module.exports = definition();
|
|
else root[name] = definition();
|
|
}(commonjsGlobal, 'bowser', function () {
|
|
/**
|
|
* See useragents.js for examples of navigator.userAgent
|
|
*/
|
|
|
|
var t = true;
|
|
|
|
function detect(ua) {
|
|
|
|
function getFirstMatch(regex) {
|
|
var match = ua.match(regex);
|
|
return (match && match.length > 1 && match[1]) || '';
|
|
}
|
|
|
|
function getSecondMatch(regex) {
|
|
var match = ua.match(regex);
|
|
return (match && match.length > 1 && match[2]) || '';
|
|
}
|
|
|
|
var iosdevice = getFirstMatch(/(ipod|iphone|ipad)/i).toLowerCase()
|
|
, likeAndroid = /like android/i.test(ua)
|
|
, android = !likeAndroid && /android/i.test(ua)
|
|
, nexusMobile = /nexus\s*[0-6]\s*/i.test(ua)
|
|
, nexusTablet = !nexusMobile && /nexus\s*[0-9]+/i.test(ua)
|
|
, chromeos = /CrOS/.test(ua)
|
|
, silk = /silk/i.test(ua)
|
|
, sailfish = /sailfish/i.test(ua)
|
|
, tizen = /tizen/i.test(ua)
|
|
, webos = /(web|hpw)os/i.test(ua)
|
|
, windowsphone = /windows phone/i.test(ua)
|
|
; /SamsungBrowser/i.test(ua)
|
|
; var windows = !windowsphone && /windows/i.test(ua)
|
|
, mac = !iosdevice && !silk && /macintosh/i.test(ua)
|
|
, linux = !android && !sailfish && !tizen && !webos && /linux/i.test(ua)
|
|
, edgeVersion = getFirstMatch(/edge\/(\d+(\.\d+)?)/i)
|
|
, versionIdentifier = getFirstMatch(/version\/(\d+(\.\d+)?)/i)
|
|
, tablet = /tablet/i.test(ua)
|
|
, mobile = !tablet && /[^-]mobi/i.test(ua)
|
|
, xbox = /xbox/i.test(ua)
|
|
, result;
|
|
|
|
if (/opera/i.test(ua)) {
|
|
// an old Opera
|
|
result = {
|
|
name: 'Opera'
|
|
, opera: t
|
|
, version: versionIdentifier || getFirstMatch(/(?:opera|opr|opios)[\s\/](\d+(\.\d+)?)/i)
|
|
};
|
|
} else if (/opr|opios/i.test(ua)) {
|
|
// a new Opera
|
|
result = {
|
|
name: 'Opera'
|
|
, opera: t
|
|
, version: getFirstMatch(/(?:opr|opios)[\s\/](\d+(\.\d+)?)/i) || versionIdentifier
|
|
};
|
|
}
|
|
else if (/SamsungBrowser/i.test(ua)) {
|
|
result = {
|
|
name: 'Samsung Internet for Android'
|
|
, samsungBrowser: t
|
|
, version: versionIdentifier || getFirstMatch(/(?:SamsungBrowser)[\s\/](\d+(\.\d+)?)/i)
|
|
};
|
|
}
|
|
else if (/coast/i.test(ua)) {
|
|
result = {
|
|
name: 'Opera Coast'
|
|
, coast: t
|
|
, version: versionIdentifier || getFirstMatch(/(?:coast)[\s\/](\d+(\.\d+)?)/i)
|
|
};
|
|
}
|
|
else if (/yabrowser/i.test(ua)) {
|
|
result = {
|
|
name: 'Yandex Browser'
|
|
, yandexbrowser: t
|
|
, version: versionIdentifier || getFirstMatch(/(?:yabrowser)[\s\/](\d+(\.\d+)?)/i)
|
|
};
|
|
}
|
|
else if (/ucbrowser/i.test(ua)) {
|
|
result = {
|
|
name: 'UC Browser'
|
|
, ucbrowser: t
|
|
, version: getFirstMatch(/(?:ucbrowser)[\s\/](\d+(?:\.\d+)+)/i)
|
|
};
|
|
}
|
|
else if (/mxios/i.test(ua)) {
|
|
result = {
|
|
name: 'Maxthon'
|
|
, maxthon: t
|
|
, version: getFirstMatch(/(?:mxios)[\s\/](\d+(?:\.\d+)+)/i)
|
|
};
|
|
}
|
|
else if (/epiphany/i.test(ua)) {
|
|
result = {
|
|
name: 'Epiphany'
|
|
, epiphany: t
|
|
, version: getFirstMatch(/(?:epiphany)[\s\/](\d+(?:\.\d+)+)/i)
|
|
};
|
|
}
|
|
else if (/puffin/i.test(ua)) {
|
|
result = {
|
|
name: 'Puffin'
|
|
, puffin: t
|
|
, version: getFirstMatch(/(?:puffin)[\s\/](\d+(?:\.\d+)?)/i)
|
|
};
|
|
}
|
|
else if (/sleipnir/i.test(ua)) {
|
|
result = {
|
|
name: 'Sleipnir'
|
|
, sleipnir: t
|
|
, version: getFirstMatch(/(?:sleipnir)[\s\/](\d+(?:\.\d+)+)/i)
|
|
};
|
|
}
|
|
else if (/k-meleon/i.test(ua)) {
|
|
result = {
|
|
name: 'K-Meleon'
|
|
, kMeleon: t
|
|
, version: getFirstMatch(/(?:k-meleon)[\s\/](\d+(?:\.\d+)+)/i)
|
|
};
|
|
}
|
|
else if (windowsphone) {
|
|
result = {
|
|
name: 'Windows Phone'
|
|
, windowsphone: t
|
|
};
|
|
if (edgeVersion) {
|
|
result.msedge = t;
|
|
result.version = edgeVersion;
|
|
}
|
|
else {
|
|
result.msie = t;
|
|
result.version = getFirstMatch(/iemobile\/(\d+(\.\d+)?)/i);
|
|
}
|
|
}
|
|
else if (/msie|trident/i.test(ua)) {
|
|
result = {
|
|
name: 'Internet Explorer'
|
|
, msie: t
|
|
, version: getFirstMatch(/(?:msie |rv:)(\d+(\.\d+)?)/i)
|
|
};
|
|
} else if (chromeos) {
|
|
result = {
|
|
name: 'Chrome'
|
|
, chromeos: t
|
|
, chromeBook: t
|
|
, chrome: t
|
|
, version: getFirstMatch(/(?:chrome|crios|crmo)\/(\d+(\.\d+)?)/i)
|
|
};
|
|
} else if (/chrome.+? edge/i.test(ua)) {
|
|
result = {
|
|
name: 'Microsoft Edge'
|
|
, msedge: t
|
|
, version: edgeVersion
|
|
};
|
|
}
|
|
else if (/vivaldi/i.test(ua)) {
|
|
result = {
|
|
name: 'Vivaldi'
|
|
, vivaldi: t
|
|
, version: getFirstMatch(/vivaldi\/(\d+(\.\d+)?)/i) || versionIdentifier
|
|
};
|
|
}
|
|
else if (sailfish) {
|
|
result = {
|
|
name: 'Sailfish'
|
|
, sailfish: t
|
|
, version: getFirstMatch(/sailfish\s?browser\/(\d+(\.\d+)?)/i)
|
|
};
|
|
}
|
|
else if (/seamonkey\//i.test(ua)) {
|
|
result = {
|
|
name: 'SeaMonkey'
|
|
, seamonkey: t
|
|
, version: getFirstMatch(/seamonkey\/(\d+(\.\d+)?)/i)
|
|
};
|
|
}
|
|
else if (/firefox|iceweasel|fxios/i.test(ua)) {
|
|
result = {
|
|
name: 'Firefox'
|
|
, firefox: t
|
|
, version: getFirstMatch(/(?:firefox|iceweasel|fxios)[ \/](\d+(\.\d+)?)/i)
|
|
};
|
|
if (/\((mobile|tablet);[^\)]*rv:[\d\.]+\)/i.test(ua)) {
|
|
result.firefoxos = t;
|
|
}
|
|
}
|
|
else if (silk) {
|
|
result = {
|
|
name: 'Amazon Silk'
|
|
, silk: t
|
|
, version : getFirstMatch(/silk\/(\d+(\.\d+)?)/i)
|
|
};
|
|
}
|
|
else if (/phantom/i.test(ua)) {
|
|
result = {
|
|
name: 'PhantomJS'
|
|
, phantom: t
|
|
, version: getFirstMatch(/phantomjs\/(\d+(\.\d+)?)/i)
|
|
};
|
|
}
|
|
else if (/slimerjs/i.test(ua)) {
|
|
result = {
|
|
name: 'SlimerJS'
|
|
, slimer: t
|
|
, version: getFirstMatch(/slimerjs\/(\d+(\.\d+)?)/i)
|
|
};
|
|
}
|
|
else if (/blackberry|\bbb\d+/i.test(ua) || /rim\stablet/i.test(ua)) {
|
|
result = {
|
|
name: 'BlackBerry'
|
|
, blackberry: t
|
|
, version: versionIdentifier || getFirstMatch(/blackberry[\d]+\/(\d+(\.\d+)?)/i)
|
|
};
|
|
}
|
|
else if (webos) {
|
|
result = {
|
|
name: 'WebOS'
|
|
, webos: t
|
|
, version: versionIdentifier || getFirstMatch(/w(?:eb)?osbrowser\/(\d+(\.\d+)?)/i)
|
|
};
|
|
/touchpad\//i.test(ua) && (result.touchpad = t);
|
|
}
|
|
else if (/bada/i.test(ua)) {
|
|
result = {
|
|
name: 'Bada'
|
|
, bada: t
|
|
, version: getFirstMatch(/dolfin\/(\d+(\.\d+)?)/i)
|
|
};
|
|
}
|
|
else if (tizen) {
|
|
result = {
|
|
name: 'Tizen'
|
|
, tizen: t
|
|
, version: getFirstMatch(/(?:tizen\s?)?browser\/(\d+(\.\d+)?)/i) || versionIdentifier
|
|
};
|
|
}
|
|
else if (/qupzilla/i.test(ua)) {
|
|
result = {
|
|
name: 'QupZilla'
|
|
, qupzilla: t
|
|
, version: getFirstMatch(/(?:qupzilla)[\s\/](\d+(?:\.\d+)+)/i) || versionIdentifier
|
|
};
|
|
}
|
|
else if (/chromium/i.test(ua)) {
|
|
result = {
|
|
name: 'Chromium'
|
|
, chromium: t
|
|
, version: getFirstMatch(/(?:chromium)[\s\/](\d+(?:\.\d+)?)/i) || versionIdentifier
|
|
};
|
|
}
|
|
else if (/chrome|crios|crmo/i.test(ua)) {
|
|
result = {
|
|
name: 'Chrome'
|
|
, chrome: t
|
|
, version: getFirstMatch(/(?:chrome|crios|crmo)\/(\d+(\.\d+)?)/i)
|
|
};
|
|
}
|
|
else if (android) {
|
|
result = {
|
|
name: 'Android'
|
|
, version: versionIdentifier
|
|
};
|
|
}
|
|
else if (/safari|applewebkit/i.test(ua)) {
|
|
result = {
|
|
name: 'Safari'
|
|
, safari: t
|
|
};
|
|
if (versionIdentifier) {
|
|
result.version = versionIdentifier;
|
|
}
|
|
}
|
|
else if (iosdevice) {
|
|
result = {
|
|
name : iosdevice == 'iphone' ? 'iPhone' : iosdevice == 'ipad' ? 'iPad' : 'iPod'
|
|
};
|
|
// WTF: version is not part of user agent in web apps
|
|
if (versionIdentifier) {
|
|
result.version = versionIdentifier;
|
|
}
|
|
}
|
|
else if(/googlebot/i.test(ua)) {
|
|
result = {
|
|
name: 'Googlebot'
|
|
, googlebot: t
|
|
, version: getFirstMatch(/googlebot\/(\d+(\.\d+))/i) || versionIdentifier
|
|
};
|
|
}
|
|
else {
|
|
result = {
|
|
name: getFirstMatch(/^(.*)\/(.*) /),
|
|
version: getSecondMatch(/^(.*)\/(.*) /)
|
|
};
|
|
}
|
|
|
|
// set webkit or gecko flag for browsers based on these engines
|
|
if (!result.msedge && /(apple)?webkit/i.test(ua)) {
|
|
if (/(apple)?webkit\/537\.36/i.test(ua)) {
|
|
result.name = result.name || "Blink";
|
|
result.blink = t;
|
|
} else {
|
|
result.name = result.name || "Webkit";
|
|
result.webkit = t;
|
|
}
|
|
if (!result.version && versionIdentifier) {
|
|
result.version = versionIdentifier;
|
|
}
|
|
} else if (!result.opera && /gecko\//i.test(ua)) {
|
|
result.name = result.name || "Gecko";
|
|
result.gecko = t;
|
|
result.version = result.version || getFirstMatch(/gecko\/(\d+(\.\d+)?)/i);
|
|
}
|
|
|
|
// set OS flags for platforms that have multiple browsers
|
|
if (!result.windowsphone && !result.msedge && (android || result.silk)) {
|
|
result.android = t;
|
|
} else if (!result.windowsphone && !result.msedge && iosdevice) {
|
|
result[iosdevice] = t;
|
|
result.ios = t;
|
|
} else if (mac) {
|
|
result.mac = t;
|
|
} else if (xbox) {
|
|
result.xbox = t;
|
|
} else if (windows) {
|
|
result.windows = t;
|
|
} else if (linux) {
|
|
result.linux = t;
|
|
}
|
|
|
|
// OS version extraction
|
|
var osVersion = '';
|
|
if (result.windowsphone) {
|
|
osVersion = getFirstMatch(/windows phone (?:os)?\s?(\d+(\.\d+)*)/i);
|
|
} else if (iosdevice) {
|
|
osVersion = getFirstMatch(/os (\d+([_\s]\d+)*) like mac os x/i);
|
|
osVersion = osVersion.replace(/[_\s]/g, '.');
|
|
} else if (android) {
|
|
osVersion = getFirstMatch(/android[ \/-](\d+(\.\d+)*)/i);
|
|
} else if (result.webos) {
|
|
osVersion = getFirstMatch(/(?:web|hpw)os\/(\d+(\.\d+)*)/i);
|
|
} else if (result.blackberry) {
|
|
osVersion = getFirstMatch(/rim\stablet\sos\s(\d+(\.\d+)*)/i);
|
|
} else if (result.bada) {
|
|
osVersion = getFirstMatch(/bada\/(\d+(\.\d+)*)/i);
|
|
} else if (result.tizen) {
|
|
osVersion = getFirstMatch(/tizen[\/\s](\d+(\.\d+)*)/i);
|
|
}
|
|
if (osVersion) {
|
|
result.osversion = osVersion;
|
|
}
|
|
|
|
// device type extraction
|
|
var osMajorVersion = osVersion.split('.')[0];
|
|
if (
|
|
tablet
|
|
|| nexusTablet
|
|
|| iosdevice == 'ipad'
|
|
|| (android && (osMajorVersion == 3 || (osMajorVersion >= 4 && !mobile)))
|
|
|| result.silk
|
|
) {
|
|
result.tablet = t;
|
|
} else if (
|
|
mobile
|
|
|| iosdevice == 'iphone'
|
|
|| iosdevice == 'ipod'
|
|
|| android
|
|
|| nexusMobile
|
|
|| result.blackberry
|
|
|| result.webos
|
|
|| result.bada
|
|
) {
|
|
result.mobile = t;
|
|
}
|
|
|
|
// Graded Browser Support
|
|
// http://developer.yahoo.com/yui/articles/gbs
|
|
if (result.msedge ||
|
|
(result.msie && result.version >= 10) ||
|
|
(result.yandexbrowser && result.version >= 15) ||
|
|
(result.vivaldi && result.version >= 1.0) ||
|
|
(result.chrome && result.version >= 20) ||
|
|
(result.samsungBrowser && result.version >= 4) ||
|
|
(result.firefox && result.version >= 20.0) ||
|
|
(result.safari && result.version >= 6) ||
|
|
(result.opera && result.version >= 10.0) ||
|
|
(result.ios && result.osversion && result.osversion.split(".")[0] >= 6) ||
|
|
(result.blackberry && result.version >= 10.1)
|
|
|| (result.chromium && result.version >= 20)
|
|
) {
|
|
result.a = t;
|
|
}
|
|
else if ((result.msie && result.version < 10) ||
|
|
(result.chrome && result.version < 20) ||
|
|
(result.firefox && result.version < 20.0) ||
|
|
(result.safari && result.version < 6) ||
|
|
(result.opera && result.version < 10.0) ||
|
|
(result.ios && result.osversion && result.osversion.split(".")[0] < 6)
|
|
|| (result.chromium && result.version < 20)
|
|
) {
|
|
result.c = t;
|
|
} else result.x = t;
|
|
|
|
return result
|
|
}
|
|
|
|
var bowser = detect(typeof navigator !== 'undefined' ? navigator.userAgent || '' : '');
|
|
|
|
bowser.test = function (browserList) {
|
|
for (var i = 0; i < browserList.length; ++i) {
|
|
var browserItem = browserList[i];
|
|
if (typeof browserItem=== 'string') {
|
|
if (browserItem in bowser) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
|
|
/**
|
|
* Get version precisions count
|
|
*
|
|
* @example
|
|
* getVersionPrecision("1.10.3") // 3
|
|
*
|
|
* @param {string} version
|
|
* @return {number}
|
|
*/
|
|
function getVersionPrecision(version) {
|
|
return version.split(".").length;
|
|
}
|
|
|
|
/**
|
|
* Array::map polyfill
|
|
*
|
|
* @param {Array} arr
|
|
* @param {Function} iterator
|
|
* @return {Array}
|
|
*/
|
|
function map(arr, iterator) {
|
|
var result = [], i;
|
|
if (Array.prototype.map) {
|
|
return Array.prototype.map.call(arr, iterator);
|
|
}
|
|
for (i = 0; i < arr.length; i++) {
|
|
result.push(iterator(arr[i]));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Calculate browser version weight
|
|
*
|
|
* @example
|
|
* compareVersions(['1.10.2.1', '1.8.2.1.90']) // 1
|
|
* compareVersions(['1.010.2.1', '1.09.2.1.90']); // 1
|
|
* compareVersions(['1.10.2.1', '1.10.2.1']); // 0
|
|
* compareVersions(['1.10.2.1', '1.0800.2']); // -1
|
|
*
|
|
* @param {Array<String>} versions versions to compare
|
|
* @return {Number} comparison result
|
|
*/
|
|
function compareVersions(versions) {
|
|
// 1) get common precision for both versions, for example for "10.0" and "9" it should be 2
|
|
var precision = Math.max(getVersionPrecision(versions[0]), getVersionPrecision(versions[1]));
|
|
var chunks = map(versions, function (version) {
|
|
var delta = precision - getVersionPrecision(version);
|
|
|
|
// 2) "9" -> "9.0" (for precision = 2)
|
|
version = version + new Array(delta + 1).join(".0");
|
|
|
|
// 3) "9.0" -> ["000000000"", "000000009"]
|
|
return map(version.split("."), function (chunk) {
|
|
return new Array(20 - chunk.length).join("0") + chunk;
|
|
}).reverse();
|
|
});
|
|
|
|
// iterate in reverse order by reversed chunks array
|
|
while (--precision >= 0) {
|
|
// 4) compare: "000000009" > "000000010" = false (but "9" > "10" = true)
|
|
if (chunks[0][precision] > chunks[1][precision]) {
|
|
return 1;
|
|
}
|
|
else if (chunks[0][precision] === chunks[1][precision]) {
|
|
if (precision === 0) {
|
|
// all version chunks are same
|
|
return 0;
|
|
}
|
|
}
|
|
else {
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if browser is unsupported
|
|
*
|
|
* @example
|
|
* bowser.isUnsupportedBrowser({
|
|
* msie: "10",
|
|
* firefox: "23",
|
|
* chrome: "29",
|
|
* safari: "5.1",
|
|
* opera: "16",
|
|
* phantom: "534"
|
|
* });
|
|
*
|
|
* @param {Object} minVersions map of minimal version to browser
|
|
* @param {Boolean} [strictMode = false] flag to return false if browser wasn't found in map
|
|
* @param {String} [ua] user agent string
|
|
* @return {Boolean}
|
|
*/
|
|
function isUnsupportedBrowser(minVersions, strictMode, ua) {
|
|
var _bowser = bowser;
|
|
|
|
// make strictMode param optional with ua param usage
|
|
if (typeof strictMode === 'string') {
|
|
ua = strictMode;
|
|
strictMode = void(0);
|
|
}
|
|
|
|
if (strictMode === void(0)) {
|
|
strictMode = false;
|
|
}
|
|
if (ua) {
|
|
_bowser = detect(ua);
|
|
}
|
|
|
|
var version = "" + _bowser.version;
|
|
for (var browser in minVersions) {
|
|
if (minVersions.hasOwnProperty(browser)) {
|
|
if (_bowser[browser]) {
|
|
if (typeof minVersions[browser] !== 'string') {
|
|
throw new Error('Browser version in the minVersion map should be a string: ' + browser + ': ' + String(minVersions));
|
|
}
|
|
|
|
// browser version and min supported version.
|
|
return compareVersions([version, minVersions[browser]]) < 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
return strictMode; // not found
|
|
}
|
|
|
|
/**
|
|
* Check if browser is supported
|
|
*
|
|
* @param {Object} minVersions map of minimal version to browser
|
|
* @param {Boolean} [strictMode = false] flag to return false if browser wasn't found in map
|
|
* @param {String} [ua] user agent string
|
|
* @return {Boolean}
|
|
*/
|
|
function check(minVersions, strictMode, ua) {
|
|
return !isUnsupportedBrowser(minVersions, strictMode, ua);
|
|
}
|
|
|
|
bowser.isUnsupportedBrowser = isUnsupportedBrowser;
|
|
bowser.compareVersions = compareVersions;
|
|
bowser.check = check;
|
|
|
|
/*
|
|
* Set our detect method to the main bowser object so we can
|
|
* reuse it to test other user agents.
|
|
* This is needed to implement future tests.
|
|
*/
|
|
bowser._detect = detect;
|
|
|
|
return bowser
|
|
});
|
|
});
|
|
|
|
var userAgent = navigator.userAgent.toLowerCase();
|
|
//@ts-ignore
|
|
var info = bowser._detect(userAgent);
|
|
var webkitVersionMatch = userAgent.match(/applewebkit\/(\d+(:?\.\d+)*)/);
|
|
//Helper
|
|
//@ts-ignore
|
|
bowser.compareVersions;
|
|
//Platforms
|
|
!!info.mac;
|
|
!!info.android;
|
|
!!info.ios;
|
|
!!info.mobile;
|
|
!!info.tablet;
|
|
//Browsers
|
|
parseInt(info.version, 10);
|
|
info.version;
|
|
webkitVersionMatch && webkitVersionMatch[1] || '';
|
|
var isIE = !!(info.msie || info.msedge);
|
|
!!info.firefox;
|
|
!!info.msedge;
|
|
!!info.chrome;
|
|
var isSafari = !!info.safari;
|
|
!!(info.webkit || info.blink);
|
|
/electron/g.test(userAgent);
|
|
|
|
function isFunction(val) {
|
|
return typeof val === 'function';
|
|
}
|
|
|
|
/*global Document, Window */
|
|
var NATIVE_CODE_RE = /\[native code]/;
|
|
var NativeMethods = /** @class */ (function () {
|
|
function NativeMethods(doc, win) {
|
|
win = win || globalContextInfo.global;
|
|
this.refreshWindowMeths(win, globalContextInfo.isInWorker);
|
|
this.refreshWorkerMeths(win);
|
|
if (globalContextInfo.isInWorker)
|
|
return;
|
|
this.refreshDocumentMeths(doc, win);
|
|
this.refreshElementMeths(doc, win);
|
|
}
|
|
NativeMethods._getDocumentPropOwnerName = function (docPrototype, propName) {
|
|
return docPrototype.hasOwnProperty(propName) ? 'Document' : 'HTMLDocument'; // eslint-disable-line no-prototype-builtins
|
|
};
|
|
NativeMethods.prototype.getStoragesPropsOwner = function (win) {
|
|
return this.isStoragePropsLocatedInProto ? win.Window.prototype : win;
|
|
};
|
|
NativeMethods.prototype.refreshWorkerMeths = function (scope /* WorkerGlobalScope */) {
|
|
this.importScripts = scope.importScripts;
|
|
};
|
|
NativeMethods.prototype.refreshDocumentMeths = function (doc, win) {
|
|
doc = doc || document;
|
|
win = win || window;
|
|
var docPrototype = win.Document.prototype;
|
|
// Dom
|
|
this.createDocumentFragment = docPrototype.createDocumentFragment;
|
|
this.createElement = docPrototype.createElement;
|
|
this.createElementNS = docPrototype.createElementNS;
|
|
this.createTextNode = docPrototype.createTextNode;
|
|
this.documentOpenPropOwnerName = NativeMethods._getDocumentPropOwnerName(docPrototype, 'open');
|
|
this.documentClosePropOwnerName = NativeMethods._getDocumentPropOwnerName(docPrototype, 'close');
|
|
this.documentWritePropOwnerName = NativeMethods._getDocumentPropOwnerName(docPrototype, 'write');
|
|
this.documentWriteLnPropOwnerName = NativeMethods._getDocumentPropOwnerName(docPrototype, 'writeln');
|
|
this.documentOpen = win[this.documentOpenPropOwnerName].prototype.open;
|
|
this.documentClose = win[this.documentClosePropOwnerName].prototype.close;
|
|
this.documentWrite = win[this.documentWritePropOwnerName].prototype.write;
|
|
this.documentWriteLn = win[this.documentWriteLnPropOwnerName].prototype.writeln;
|
|
this.elementFromPoint = docPrototype.elementFromPoint;
|
|
this.caretRangeFromPoint = docPrototype.caretRangeFromPoint;
|
|
// @ts-ignore Experimental method in Firefox
|
|
this.caretPositionFromPoint = docPrototype.caretPositionFromPoint;
|
|
this.getElementById = docPrototype.getElementById;
|
|
this.getElementsByClassName = docPrototype.getElementsByClassName;
|
|
this.getElementsByName = docPrototype.getElementsByName;
|
|
this.getElementsByTagName = docPrototype.getElementsByTagName;
|
|
this.querySelector = docPrototype.querySelector;
|
|
this.querySelectorAll = docPrototype.querySelectorAll;
|
|
this.createHTMLDocument = win.DOMImplementation.prototype.createHTMLDocument;
|
|
// @ts-ignore
|
|
if (doc.registerElement) {
|
|
// @ts-ignore
|
|
this.registerElement = docPrototype.registerElement;
|
|
}
|
|
// Event
|
|
// NOTE: IE11 has no EventTarget so we should save "Event" methods separately
|
|
if (!win.EventTarget) {
|
|
this.documentAddEventListener = docPrototype.addEventListener;
|
|
this.documentRemoveEventListener = docPrototype.removeEventListener;
|
|
}
|
|
this.documentCreateEvent = docPrototype.createEvent;
|
|
// @ts-ignore Deprecated
|
|
this.documentCreateTouch = docPrototype.createTouch;
|
|
// @ts-ignore Deprecated
|
|
this.documentCreateTouchList = docPrototype.createTouchList;
|
|
// getters/setters
|
|
this.documentCookiePropOwnerName = NativeMethods._getDocumentPropOwnerName(docPrototype, 'cookie');
|
|
var documentCookieDescriptor = win.Object.getOwnPropertyDescriptor(win[this.documentCookiePropOwnerName].prototype, 'cookie');
|
|
// TODO: remove this condition after the GH-1649 fix
|
|
if (!this.isNativeCode(documentCookieDescriptor.get) ||
|
|
!this.isNativeCode(documentCookieDescriptor.get.toString)) {
|
|
try {
|
|
var parentNativeMethods = win.parent['%hammerhead%'].nativeMethods;
|
|
documentCookieDescriptor.get = parentNativeMethods.documentCookieGetter;
|
|
documentCookieDescriptor.set = parentNativeMethods.documentCookieSetter;
|
|
}
|
|
catch (_a) { } // eslint-disable-line no-empty
|
|
}
|
|
this.documentReferrerGetter = win.Object.getOwnPropertyDescriptor(docPrototype, 'referrer').get;
|
|
this.documentStyleSheetsGetter = win.Object.getOwnPropertyDescriptor(docPrototype, 'styleSheets').get;
|
|
this.documentActiveElementGetter = win.Object.getOwnPropertyDescriptor(docPrototype, 'activeElement').get;
|
|
this.documentCookieGetter = documentCookieDescriptor.get;
|
|
this.documentCookieSetter = documentCookieDescriptor.set;
|
|
var documentDocumentURIDescriptor = win.Object.getOwnPropertyDescriptor(docPrototype, 'documentURI');
|
|
if (documentDocumentURIDescriptor)
|
|
this.documentDocumentURIGetter = documentDocumentURIDescriptor.get;
|
|
var documentTitleDescriptor = win.Object.getOwnPropertyDescriptor(docPrototype, 'title');
|
|
this.documentTitleGetter = documentTitleDescriptor.get;
|
|
this.documentTitleSetter = documentTitleDescriptor.set;
|
|
};
|
|
NativeMethods.prototype.refreshElementMeths = function (doc, win) {
|
|
var _this = this;
|
|
win = win || window;
|
|
var createElement = (function (tagName) { return _this.createElement.call(doc || document, tagName); });
|
|
var nativeElement = createElement('div');
|
|
var createTextNode = function (data) { return _this.createTextNode.call(doc || document, data); };
|
|
var textNode = createTextNode('text');
|
|
// Dom
|
|
this.appendChild = win.Node.prototype.appendChild;
|
|
this.append = win.Element.prototype.append;
|
|
this.prepend = win.Element.prototype.prepend;
|
|
this.after = win.Element.prototype.after;
|
|
this.attachShadow = win.Element.prototype.attachShadow;
|
|
this.replaceChild = nativeElement.replaceChild;
|
|
this.cloneNode = nativeElement.cloneNode;
|
|
this.elementGetElementsByClassName = nativeElement.getElementsByClassName;
|
|
this.elementGetElementsByTagName = nativeElement.getElementsByTagName;
|
|
this.elementQuerySelector = nativeElement.querySelector;
|
|
this.elementQuerySelectorAll = nativeElement.querySelectorAll;
|
|
this.getAttribute = nativeElement.getAttribute;
|
|
this.getAttributeNS = nativeElement.getAttributeNS;
|
|
this.getAttributeNode = nativeElement.getAttributeNode;
|
|
this.getAttributeNodeNS = nativeElement.getAttributeNodeNS;
|
|
this.insertBefore = nativeElement.insertBefore;
|
|
this.insertCell = createElement('tr').insertCell;
|
|
this.insertTableRow = createElement('table').insertRow;
|
|
this.insertTBodyRow = createElement('tbody').insertRow;
|
|
this.removeAttribute = nativeElement.removeAttribute;
|
|
this.removeAttributeNS = nativeElement.removeAttributeNS;
|
|
this.removeAttributeNode = nativeElement.removeAttributeNode;
|
|
this.removeChild = win.Node.prototype.removeChild;
|
|
this.remove = win.Element.prototype.remove;
|
|
this.elementReplaceWith = win.Element.prototype.replaceWith;
|
|
this.setAttribute = nativeElement.setAttribute;
|
|
this.setAttributeNS = nativeElement.setAttributeNS;
|
|
this.hasAttribute = nativeElement.hasAttribute;
|
|
this.hasAttributeNS = nativeElement.hasAttributeNS;
|
|
this.hasAttributes = nativeElement.hasAttributes;
|
|
this.anchorToString = win.HTMLAnchorElement.prototype.toString;
|
|
this.matches = nativeElement.matches || nativeElement.msMatchesSelector;
|
|
this.closest = nativeElement.closest;
|
|
// NOTE: The 'insertAdjacent...' methods is located in HTMLElement prototype in IE11 only
|
|
this.insertAdjacentMethodsOwner = win.Element.prototype.hasOwnProperty('insertAdjacentElement') // eslint-disable-line no-prototype-builtins
|
|
? win.Element.prototype
|
|
: win.HTMLElement.prototype;
|
|
this.insertAdjacentElement = this.insertAdjacentMethodsOwner.insertAdjacentElement;
|
|
this.insertAdjacentHTML = this.insertAdjacentMethodsOwner.insertAdjacentHTML;
|
|
this.insertAdjacentText = this.insertAdjacentMethodsOwner.insertAdjacentText;
|
|
// Text node
|
|
this.appendData = textNode.appendData;
|
|
// TODO: remove this condition after the GH-1649 fix
|
|
if (!this.isNativeCode(this.elementGetElementsByTagName)) {
|
|
try {
|
|
var parentNativeMethods = win.parent['%hammerhead%'].nativeMethods;
|
|
this.elementGetElementsByTagName = parentNativeMethods.elementGetElementsByTagName;
|
|
}
|
|
// eslint-disable-next-line no-empty
|
|
catch (e) {
|
|
}
|
|
}
|
|
// Event
|
|
if (win.EventTarget) {
|
|
this.addEventListener = win.EventTarget.prototype.addEventListener;
|
|
this.removeEventListener = win.EventTarget.prototype.removeEventListener;
|
|
this.dispatchEvent = win.EventTarget.prototype.dispatchEvent;
|
|
}
|
|
// NOTE: IE11 has no EventTarget
|
|
else {
|
|
this.addEventListener = nativeElement.addEventListener;
|
|
this.removeEventListener = nativeElement.removeEventListener;
|
|
this.dispatchEvent = nativeElement.dispatchEvent;
|
|
}
|
|
this.blur = nativeElement.blur;
|
|
this.click = nativeElement.click;
|
|
this.focus = nativeElement.focus;
|
|
// @ts-ignore
|
|
this.select = window.TextRange ? createElement('body').createTextRange().select : null;
|
|
this.setSelectionRange = createElement('input').setSelectionRange;
|
|
this.textAreaSetSelectionRange = createElement('textarea').setSelectionRange;
|
|
this.svgFocus = win.SVGElement ? win.SVGElement.prototype.focus : this.focus;
|
|
this.svgBlur = win.SVGElement ? win.SVGElement.prototype.blur : this.blur;
|
|
// Style
|
|
// NOTE: The 'style' descriptor is located in the Element.prototype in the Safari on IOS
|
|
this.htmlElementStylePropOwnerName = win.Element.prototype.hasOwnProperty('style') ? 'Element' : 'HTMLElement'; // eslint-disable-line no-prototype-builtins
|
|
var htmlElementStyleDescriptor = win.Object.getOwnPropertyDescriptor(win[this.htmlElementStylePropOwnerName].prototype, 'style');
|
|
this.htmlElementStyleGetter = htmlElementStyleDescriptor.get;
|
|
// NOTE: IE does not allow to set a style property
|
|
if (htmlElementStyleDescriptor.set)
|
|
this.htmlElementStyleSetter = htmlElementStyleDescriptor.set;
|
|
var styleCssTextDescriptor = win.Object.getOwnPropertyDescriptor(win.CSSStyleDeclaration.prototype, 'cssText');
|
|
this.styleCssTextGetter = styleCssTextDescriptor.get;
|
|
this.styleCssTextSetter = styleCssTextDescriptor.set;
|
|
};
|
|
NativeMethods.prototype._refreshGettersAndSetters = function (win, isInWorker) {
|
|
if (isInWorker === void 0) { isInWorker = false; }
|
|
win = win || window;
|
|
var winProto = win.constructor.prototype;
|
|
// NOTE: Event properties is located in window prototype only in IE11
|
|
this.isEventPropsLocatedInProto = winProto.hasOwnProperty('onerror'); // eslint-disable-line no-prototype-builtins
|
|
var eventPropsOwner = this.isEventPropsLocatedInProto ? winProto : win;
|
|
var winOnBeforeUnloadDescriptor = win.Object.getOwnPropertyDescriptor(eventPropsOwner, 'onbeforeunload');
|
|
var winOnUnloadDescriptor = win.Object.getOwnPropertyDescriptor(eventPropsOwner, 'onunload');
|
|
var winOnPageHideDescriptor = win.Object.getOwnPropertyDescriptor(eventPropsOwner, 'onpagehide');
|
|
var winOnMessageDescriptor = win.Object.getOwnPropertyDescriptor(eventPropsOwner, 'onmessage');
|
|
var winOnErrorDescriptor = win.Object.getOwnPropertyDescriptor(eventPropsOwner, 'onerror');
|
|
var winOnHashChangeDescriptor = win.Object.getOwnPropertyDescriptor(eventPropsOwner, 'onhashchange');
|
|
this.winOnBeforeUnloadSetter = winOnBeforeUnloadDescriptor && winOnBeforeUnloadDescriptor.set;
|
|
this.winOnUnloadSetter = winOnUnloadDescriptor && winOnUnloadDescriptor.set;
|
|
this.winOnPageHideSetter = winOnPageHideDescriptor && winOnPageHideDescriptor.set;
|
|
this.winOnMessageSetter = winOnMessageDescriptor && winOnMessageDescriptor.set;
|
|
this.winOnErrorSetter = winOnErrorDescriptor && winOnErrorDescriptor.set;
|
|
this.winOnHashChangeSetter = winOnHashChangeDescriptor && winOnHashChangeDescriptor.set;
|
|
var winOnUnhandledRejectionDescriptor = win.Object.getOwnPropertyDescriptor(eventPropsOwner, 'onunhandledrejection');
|
|
if (winOnUnhandledRejectionDescriptor)
|
|
this.winOnUnhandledRejectionSetter = winOnUnhandledRejectionDescriptor.set;
|
|
// Getters
|
|
if (win.WebSocket) {
|
|
var urlPropDescriptor = win.Object.getOwnPropertyDescriptor(win.WebSocket.prototype, 'url');
|
|
if (urlPropDescriptor && urlPropDescriptor.get && urlPropDescriptor.configurable)
|
|
this.webSocketUrlGetter = urlPropDescriptor.get;
|
|
}
|
|
this.messageEventOriginGetter = win.Object.getOwnPropertyDescriptor(win.MessageEvent.prototype, 'origin').get;
|
|
// NOTE: At present we proxy only the PerformanceNavigationTiming.
|
|
// Another types of the PerformanceEntry will be fixed later
|
|
// https://developer.mozilla.org/en-US/docs/Web/API/PerformanceEntry
|
|
if (win.PerformanceNavigationTiming)
|
|
this.performanceEntryNameGetter = win.Object.getOwnPropertyDescriptor(win.PerformanceEntry.prototype, 'name').get;
|
|
var dataPropDescriptor = win.Object.getOwnPropertyDescriptor(win.MessageEvent.prototype, 'data');
|
|
// NOTE: This condition is used for the Android 6.0 browser
|
|
if (dataPropDescriptor)
|
|
this.messageEventDataGetter = dataPropDescriptor.get;
|
|
if (win.fetch) {
|
|
this.responseStatusGetter = win.Object.getOwnPropertyDescriptor(win.Response.prototype, 'status').get;
|
|
this.responseTypeGetter = win.Object.getOwnPropertyDescriptor(win.Response.prototype, 'type').get;
|
|
this.responseUrlGetter = win.Object.getOwnPropertyDescriptor(win.Response.prototype, 'url').get;
|
|
this.requestUrlGetter = win.Object.getOwnPropertyDescriptor(win.Request.prototype, 'url').get;
|
|
this.requestReferrerGetter = win.Object.getOwnPropertyDescriptor(win.Request.prototype, 'referrer').get;
|
|
}
|
|
if (win.XMLHttpRequest) {
|
|
var xhrResponseURLDescriptor = win.Object.getOwnPropertyDescriptor(win.XMLHttpRequest.prototype, 'responseURL');
|
|
// NOTE: IE doesn't support the 'responseURL' property
|
|
if (xhrResponseURLDescriptor)
|
|
this.xhrResponseURLGetter = xhrResponseURLDescriptor.get;
|
|
}
|
|
// eslint-disable-next-line no-restricted-properties
|
|
if (win.Window) {
|
|
// NOTE: The 'localStorage' and 'sessionStorage' properties is located in window prototype only in IE11
|
|
this.isStoragePropsLocatedInProto = win.Window.prototype.hasOwnProperty('localStorage'); // eslint-disable-line no-prototype-builtins
|
|
var storagesPropsOwner = this.getStoragesPropsOwner(win);
|
|
this.winLocalStorageGetter = win.Object.getOwnPropertyDescriptor(storagesPropsOwner, 'localStorage').get;
|
|
this.winSessionStorageGetter = win.Object.getOwnPropertyDescriptor(storagesPropsOwner, 'sessionStorage').get;
|
|
}
|
|
if (isInWorker)
|
|
return;
|
|
this.storageGetItem = win.Storage.prototype.getItem;
|
|
this.storageSetItem = win.Storage.prototype.setItem;
|
|
this.storageRemoveItem = win.Storage.prototype.removeItem;
|
|
this.storageClear = win.Storage.prototype.clear;
|
|
this.storageKey = win.Storage.prototype.key;
|
|
this.storageLengthGetter = win.Object.getOwnPropertyDescriptor(win.Storage.prototype, 'length');
|
|
var objectDataDescriptor = win.Object.getOwnPropertyDescriptor(win.HTMLObjectElement.prototype, 'data');
|
|
var inputTypeDescriptor = win.Object.getOwnPropertyDescriptor(win.HTMLInputElement.prototype, 'type');
|
|
var inputValueDescriptor = win.Object.getOwnPropertyDescriptor(win.HTMLInputElement.prototype, 'value');
|
|
var inputDisabledDescriptor = win.Object.getOwnPropertyDescriptor(win.HTMLInputElement.prototype, 'disabled');
|
|
var inputRequiredDescriptor = win.Object.getOwnPropertyDescriptor(win.HTMLInputElement.prototype, 'required');
|
|
var textAreaValueDescriptor = win.Object.getOwnPropertyDescriptor(win.HTMLTextAreaElement.prototype, 'value');
|
|
var imageSrcDescriptor = win.Object.getOwnPropertyDescriptor(win.HTMLImageElement.prototype, 'src');
|
|
var imageSrcsetDescriptor = win.Object.getOwnPropertyDescriptor(win.HTMLImageElement.prototype, 'srcset');
|
|
var scriptSrcDescriptor = win.Object.getOwnPropertyDescriptor(win.HTMLScriptElement.prototype, 'src');
|
|
var scriptIntegrityDescriptor = win.Object.getOwnPropertyDescriptor(win.HTMLScriptElement.prototype, 'integrity');
|
|
var embedSrcDescriptor = win.Object.getOwnPropertyDescriptor(win.HTMLEmbedElement.prototype, 'src');
|
|
var sourceSrcDescriptor = win.Object.getOwnPropertyDescriptor(win.HTMLSourceElement.prototype, 'src');
|
|
var mediaSrcDescriptor = win.Object.getOwnPropertyDescriptor(win.HTMLMediaElement.prototype, 'src');
|
|
var inputSrcDescriptor = win.Object.getOwnPropertyDescriptor(win.HTMLInputElement.prototype, 'src');
|
|
var frameSrcDescriptor = win.Object.getOwnPropertyDescriptor(win.HTMLFrameElement.prototype, 'src');
|
|
var iframeSrcDescriptor = win.Object.getOwnPropertyDescriptor(win.HTMLIFrameElement.prototype, 'src');
|
|
var anchorHrefDescriptor = win.Object.getOwnPropertyDescriptor(win.HTMLAnchorElement.prototype, 'href');
|
|
var linkHrefDescriptor = win.Object.getOwnPropertyDescriptor(win.HTMLLinkElement.prototype, 'href');
|
|
var linkIntegrityDescriptor = win.Object.getOwnPropertyDescriptor(win.HTMLLinkElement.prototype, 'integrity');
|
|
var linkRelDescriptor = win.Object.getOwnPropertyDescriptor(win.HTMLLinkElement.prototype, 'rel');
|
|
var linkAsDescriptor = win.Object.getOwnPropertyDescriptor(win.HTMLLinkElement.prototype, 'as');
|
|
var areaHrefDescriptor = win.Object.getOwnPropertyDescriptor(win.HTMLAreaElement.prototype, 'href');
|
|
var baseHrefDescriptor = win.Object.getOwnPropertyDescriptor(win.HTMLBaseElement.prototype, 'href');
|
|
var anchorHostDescriptor = win.Object.getOwnPropertyDescriptor(win.HTMLAnchorElement.prototype, 'host');
|
|
var anchorHostnameDescriptor = win.Object.getOwnPropertyDescriptor(win.HTMLAnchorElement.prototype, 'hostname');
|
|
var anchorPathnameDescriptor = win.Object.getOwnPropertyDescriptor(win.HTMLAnchorElement.prototype, 'pathname');
|
|
var anchorPortDescriptor = win.Object.getOwnPropertyDescriptor(win.HTMLAnchorElement.prototype, 'port');
|
|
var anchorProtocolDescriptor = win.Object.getOwnPropertyDescriptor(win.HTMLAnchorElement.prototype, 'protocol');
|
|
var anchorSearchDescriptor = win.Object.getOwnPropertyDescriptor(win.HTMLAnchorElement.prototype, 'search');
|
|
var anchorTargetDescriptor = win.Object.getOwnPropertyDescriptor(win.HTMLAnchorElement.prototype, 'target');
|
|
var formTargetDescriptor = win.Object.getOwnPropertyDescriptor(win.HTMLFormElement.prototype, 'target');
|
|
var areaTargetDescriptor = win.Object.getOwnPropertyDescriptor(win.HTMLAreaElement.prototype, 'target');
|
|
var baseTargetDescriptor = win.Object.getOwnPropertyDescriptor(win.HTMLBaseElement.prototype, 'target');
|
|
var inputFormTargetDescriptor = win.Object.getOwnPropertyDescriptor(win.HTMLInputElement.prototype, 'formTarget');
|
|
var buttonFormTargetDescriptor = win.Object.getOwnPropertyDescriptor(win.HTMLButtonElement.prototype, 'formTarget');
|
|
var svgImageHrefDescriptor = win.Object.getOwnPropertyDescriptor(win.SVGImageElement.prototype, 'href');
|
|
var svgAnimStrAnimValDescriptor = win.Object.getOwnPropertyDescriptor(win.SVGAnimatedString.prototype, 'animVal');
|
|
var svgAnimStrBaseValDescriptor = win.Object.getOwnPropertyDescriptor(win.SVGAnimatedString.prototype, 'baseVal');
|
|
var inputAutocompleteDescriptor = win.Object.getOwnPropertyDescriptor(win.HTMLInputElement.prototype, 'autocomplete');
|
|
var formActionDescriptor = win.Object.getOwnPropertyDescriptor(win.HTMLFormElement.prototype, 'action');
|
|
var inputFormActionDescriptor = win.Object.getOwnPropertyDescriptor(win.HTMLInputElement.prototype, 'formAction');
|
|
var buttonFormActionDescriptor = win.Object.getOwnPropertyDescriptor(win.HTMLButtonElement.prototype, 'formAction');
|
|
var nodeTextContentDescriptor = win.Object.getOwnPropertyDescriptor(win.Node.prototype, 'textContent');
|
|
var htmlElementInnerTextDescriptor = win.Object.getOwnPropertyDescriptor(win.HTMLElement.prototype, 'innerText');
|
|
var scriptTextDescriptor = win.Object.getOwnPropertyDescriptor(win.HTMLScriptElement.prototype, 'text');
|
|
var anchorTextDescriptor = win.Object.getOwnPropertyDescriptor(win.HTMLAnchorElement.prototype, 'text');
|
|
var titleElementTextDescriptor = win.Object.getOwnPropertyDescriptor(win.HTMLTitleElement.prototype, 'text');
|
|
var iframeSandboxDescriptor = win.Object.getOwnPropertyDescriptor(win.HTMLIFrameElement.prototype, 'sandbox');
|
|
var metaHttpEquivDescriptor = win.Object.getOwnPropertyDescriptor(win.HTMLMetaElement.prototype, 'httpEquiv');
|
|
var windowOriginDescriptor = win.Object.getOwnPropertyDescriptor(win, 'origin');
|
|
if (windowOriginDescriptor) {
|
|
this.windowOriginGetter = windowOriginDescriptor.get;
|
|
this.windowOriginSetter = windowOriginDescriptor.set;
|
|
}
|
|
// NOTE: We need 'disabled' property only for Chrome.
|
|
// In Chrome it's located in HTMLInputElement.prototype
|
|
// But in IE11 it's located in HTMLElement.prototype
|
|
// So we need the null check
|
|
if (inputDisabledDescriptor) {
|
|
this.inputDisabledSetter = inputDisabledDescriptor.set;
|
|
this.inputDisabledGetter = inputDisabledDescriptor.get;
|
|
}
|
|
// NOTE: Html properties is located in HTMLElement prototype in IE11 only
|
|
this.elementHTMLPropOwnerName = win.Element.prototype.hasOwnProperty('innerHTML') ? 'Element' : 'HTMLElement'; // eslint-disable-line no-prototype-builtins
|
|
var elementInnerHTMLDescriptor = win.Object.getOwnPropertyDescriptor(win[this.elementHTMLPropOwnerName].prototype, 'innerHTML');
|
|
var elementOuterHTMLDescriptor = win.Object.getOwnPropertyDescriptor(win[this.elementHTMLPropOwnerName].prototype, 'outerHTML');
|
|
// Setters
|
|
this.objectDataSetter = objectDataDescriptor.set;
|
|
this.inputTypeSetter = inputTypeDescriptor.set;
|
|
this.inputValueSetter = inputValueDescriptor.set;
|
|
this.inputRequiredSetter = inputRequiredDescriptor.set;
|
|
this.textAreaValueSetter = textAreaValueDescriptor.set;
|
|
this.imageSrcSetter = imageSrcDescriptor.set;
|
|
this.scriptSrcSetter = scriptSrcDescriptor.set;
|
|
this.embedSrcSetter = embedSrcDescriptor.set;
|
|
this.sourceSrcSetter = sourceSrcDescriptor.set;
|
|
this.mediaSrcSetter = mediaSrcDescriptor.set;
|
|
this.inputSrcSetter = inputSrcDescriptor.set;
|
|
this.frameSrcSetter = frameSrcDescriptor.set;
|
|
this.iframeSrcSetter = iframeSrcDescriptor.set;
|
|
this.anchorHrefSetter = anchorHrefDescriptor.set;
|
|
this.linkHrefSetter = linkHrefDescriptor.set;
|
|
this.linkRelSetter = linkRelDescriptor.set;
|
|
this.linkAsSetter = linkAsDescriptor && linkAsDescriptor.set;
|
|
this.areaHrefSetter = areaHrefDescriptor.set;
|
|
this.baseHrefSetter = baseHrefDescriptor.set;
|
|
this.anchorHostSetter = anchorHostDescriptor.set;
|
|
this.anchorHostnameSetter = anchorHostnameDescriptor.set;
|
|
this.anchorPathnameSetter = anchorPathnameDescriptor.set;
|
|
this.anchorPortSetter = anchorPortDescriptor.set;
|
|
this.anchorProtocolSetter = anchorProtocolDescriptor.set;
|
|
this.anchorSearchSetter = anchorSearchDescriptor.set;
|
|
this.anchorTargetSetter = anchorTargetDescriptor.set;
|
|
this.formTargetSetter = formTargetDescriptor.set;
|
|
this.areaTargetSetter = areaTargetDescriptor.set;
|
|
this.baseTargetSetter = baseTargetDescriptor.set;
|
|
this.inputFormTargetSetter = inputFormTargetDescriptor.set;
|
|
this.buttonFormTargetSetter = buttonFormTargetDescriptor.set;
|
|
this.svgAnimStrBaseValSetter = svgAnimStrBaseValDescriptor.set;
|
|
this.inputAutocompleteSetter = inputAutocompleteDescriptor.set;
|
|
this.formActionSetter = formActionDescriptor.set;
|
|
this.inputFormActionSetter = inputFormActionDescriptor.set;
|
|
this.buttonFormActionSetter = buttonFormActionDescriptor.set;
|
|
this.iframeSandboxSetter = iframeSandboxDescriptor.set;
|
|
this.metaHttpEquivSetter = metaHttpEquivDescriptor.set;
|
|
this.htmlElementOnloadSetter = win.Object.getOwnPropertyDescriptor(win.HTMLElement.prototype, 'onload').set;
|
|
this.nodeTextContentSetter = nodeTextContentDescriptor.set;
|
|
this.htmlElementInnerTextSetter = htmlElementInnerTextDescriptor.set;
|
|
this.scriptTextSetter = scriptTextDescriptor.set;
|
|
this.anchorTextSetter = anchorTextDescriptor.set;
|
|
this.elementInnerHTMLSetter = elementInnerHTMLDescriptor.set;
|
|
this.elementOuterHTMLSetter = elementOuterHTMLDescriptor.set;
|
|
// NOTE: Some browsers (for example, Edge, Internet Explorer 11, Safari) don't support the 'integrity' property.
|
|
if (scriptIntegrityDescriptor && linkIntegrityDescriptor) {
|
|
this.scriptIntegritySetter = scriptIntegrityDescriptor.set;
|
|
this.linkIntegritySetter = linkIntegrityDescriptor.set;
|
|
}
|
|
this.titleElementTextSetter = titleElementTextDescriptor.set;
|
|
// NOTE: the classList property is located in HTMLElement prototype in IE11
|
|
this.elementClassListPropOwnerName = win.Element.prototype.hasOwnProperty('classList') ? 'Element' : 'HTMLElement'; // eslint-disable-line no-prototype-builtins
|
|
this.elementClassListGetter = win.Object.getOwnPropertyDescriptor(win[this.elementClassListPropOwnerName].prototype, 'classList').get;
|
|
this.htmlCollectionLengthGetter = win.Object.getOwnPropertyDescriptor(win.HTMLCollection.prototype, 'length').get;
|
|
this.nodeListLengthGetter = win.Object.getOwnPropertyDescriptor(win.NodeList.prototype, 'length').get;
|
|
this.elementChildElementCountGetter = win.Object.getOwnPropertyDescriptor(win.Element.prototype, 'childElementCount').get;
|
|
this.inputFilesGetter = win.Object.getOwnPropertyDescriptor(win.HTMLInputElement.prototype, 'files').get;
|
|
this.styleSheetHrefGetter = win.Object.getOwnPropertyDescriptor(win.StyleSheet.prototype, 'href').get;
|
|
this.objectDataGetter = objectDataDescriptor.get;
|
|
this.inputTypeGetter = inputTypeDescriptor.get;
|
|
this.inputValueGetter = inputValueDescriptor.get;
|
|
this.inputRequiredGetter = inputRequiredDescriptor.get;
|
|
this.textAreaValueGetter = textAreaValueDescriptor.get;
|
|
this.imageSrcGetter = imageSrcDescriptor.get;
|
|
this.scriptSrcGetter = scriptSrcDescriptor.get;
|
|
this.embedSrcGetter = embedSrcDescriptor.get;
|
|
this.sourceSrcGetter = sourceSrcDescriptor.get;
|
|
this.mediaSrcGetter = mediaSrcDescriptor.get;
|
|
this.inputSrcGetter = inputSrcDescriptor.get;
|
|
this.frameSrcGetter = frameSrcDescriptor.get;
|
|
this.iframeSrcGetter = iframeSrcDescriptor.get;
|
|
this.anchorHrefGetter = anchorHrefDescriptor.get;
|
|
this.linkHrefGetter = linkHrefDescriptor.get;
|
|
this.linkRelGetter = linkRelDescriptor.get;
|
|
this.areaHrefGetter = areaHrefDescriptor.get;
|
|
this.baseHrefGetter = baseHrefDescriptor.get;
|
|
this.anchorHostGetter = anchorHostDescriptor.get;
|
|
this.anchorHostnameGetter = anchorHostnameDescriptor.get;
|
|
this.anchorPathnameGetter = anchorPathnameDescriptor.get;
|
|
this.anchorPortGetter = anchorPortDescriptor.get;
|
|
this.anchorProtocolGetter = anchorProtocolDescriptor.get;
|
|
this.anchorSearchGetter = anchorSearchDescriptor.get;
|
|
this.anchorTargetGetter = anchorTargetDescriptor.get;
|
|
this.formTargetGetter = formTargetDescriptor.get;
|
|
this.areaTargetGetter = areaTargetDescriptor.get;
|
|
this.baseTargetGetter = baseTargetDescriptor.get;
|
|
this.inputFormTargetGetter = inputFormTargetDescriptor.get;
|
|
this.buttonFormTargetGetter = buttonFormTargetDescriptor.get;
|
|
this.svgImageHrefGetter = svgImageHrefDescriptor.get;
|
|
this.svgAnimStrAnimValGetter = svgAnimStrAnimValDescriptor.get;
|
|
this.svgAnimStrBaseValGetter = svgAnimStrBaseValDescriptor.get;
|
|
this.inputAutocompleteGetter = inputAutocompleteDescriptor.get;
|
|
this.formActionGetter = formActionDescriptor.get;
|
|
this.inputFormActionGetter = inputFormActionDescriptor.get;
|
|
this.buttonFormActionGetter = buttonFormActionDescriptor.get;
|
|
this.iframeSandboxGetter = iframeSandboxDescriptor.get;
|
|
this.metaHttpEquivGetter = metaHttpEquivDescriptor.get;
|
|
this.contentWindowGetter = win.Object.getOwnPropertyDescriptor(win.HTMLIFrameElement.prototype, 'contentWindow').get;
|
|
this.contentDocumentGetter = win.Object.getOwnPropertyDescriptor(win.HTMLIFrameElement.prototype, 'contentDocument').get;
|
|
this.frameContentWindowGetter = win.Object.getOwnPropertyDescriptor(win.HTMLFrameElement.prototype, 'contentWindow').get;
|
|
this.nodeTextContentGetter = nodeTextContentDescriptor.get;
|
|
this.htmlElementInnerTextGetter = htmlElementInnerTextDescriptor.get;
|
|
this.scriptTextGetter = scriptTextDescriptor.get;
|
|
this.anchorTextGetter = anchorTextDescriptor.get;
|
|
this.elementInnerHTMLGetter = elementInnerHTMLDescriptor.get;
|
|
this.elementOuterHTMLGetter = elementOuterHTMLDescriptor.get;
|
|
this.nodeFirstChildGetter = win.Object.getOwnPropertyDescriptor(win.Node.prototype, 'firstChild').get;
|
|
this.nodeLastChildGetter = win.Object.getOwnPropertyDescriptor(win.Node.prototype, 'lastChild').get;
|
|
this.nodeNextSiblingGetter = win.Object.getOwnPropertyDescriptor(win.Node.prototype, 'nextSibling').get;
|
|
this.nodePrevSiblingGetter = win.Object.getOwnPropertyDescriptor(win.Node.prototype, 'previousSibling').get;
|
|
this.nodeParentNodeGetter = win.Object.getOwnPropertyDescriptor(win.Node.prototype, 'parentNode').get;
|
|
this.nodeChildNodesGetter = win.Object.getOwnPropertyDescriptor(win.Node.prototype, 'childNodes').get;
|
|
this.elementFirstElementChildGetter = win.Object.getOwnPropertyDescriptor(win.Element.prototype, 'firstElementChild').get;
|
|
this.elementLastElementChildGetter = win.Object.getOwnPropertyDescriptor(win.Element.prototype, 'lastElementChild').get;
|
|
this.elementNextElementSiblingGetter = win.Object.getOwnPropertyDescriptor(win.Element.prototype, 'nextElementSibling').get;
|
|
this.elementPrevElementSiblingGetter = win.Object.getOwnPropertyDescriptor(win.Element.prototype, 'previousElementSibling').get;
|
|
// NOTE: Some browsers (for example, Edge, Internet Explorer 11, Safari) don't support the 'integrity' property.
|
|
if (scriptIntegrityDescriptor && linkIntegrityDescriptor) {
|
|
this.scriptIntegrityGetter = scriptIntegrityDescriptor.get;
|
|
this.linkIntegrityGetter = linkIntegrityDescriptor.get;
|
|
}
|
|
// NOTE: In the Internet Explorer 11 the children property is located in HTMLElement.
|
|
var childrenPropOwner = win.Element.prototype.hasOwnProperty('children') // eslint-disable-line no-prototype-builtins
|
|
? win.Element.prototype
|
|
: win.HTMLElement.prototype;
|
|
this.elementChildrenGetter = win.Object.getOwnPropertyDescriptor(childrenPropOwner, 'children').get;
|
|
var anchorOriginDescriptor = win.Object.getOwnPropertyDescriptor(win.HTMLAnchorElement.prototype, 'origin');
|
|
// NOTE: IE and Edge don't support origin property
|
|
if (anchorOriginDescriptor)
|
|
this.anchorOriginGetter = anchorOriginDescriptor.get;
|
|
var iframeSrcdocDescriptor = win.Object.getOwnPropertyDescriptor(win.HTMLIFrameElement.prototype, 'srcdoc');
|
|
// NOTE: IE11 doesn't support the 'srcdoc' property
|
|
if (iframeSrcdocDescriptor) {
|
|
this.iframeSrcdocGetter = iframeSrcdocDescriptor.get;
|
|
this.iframeSrcdocSetter = iframeSrcdocDescriptor.set;
|
|
}
|
|
var cssStyleSheetHrefDescriptor = win.Object.getOwnPropertyDescriptor(win.CSSStyleSheet.prototype, 'href');
|
|
// NOTE: IE11 doesn't support the 'href' property
|
|
if (cssStyleSheetHrefDescriptor)
|
|
this.cssStyleSheetHrefGetter = cssStyleSheetHrefDescriptor.get;
|
|
var nodeBaseURIDescriptor = win.Object.getOwnPropertyDescriptor(win.Node.prototype, 'baseURI');
|
|
// NOTE: IE11 doesn't support the 'baseURI' property
|
|
if (nodeBaseURIDescriptor)
|
|
this.nodeBaseURIGetter = nodeBaseURIDescriptor.get;
|
|
// NOTE: The 'attributes' property is located in Node prototype in IE11 only
|
|
this.elementAttributesPropOwnerName = win.Element.prototype.hasOwnProperty('attributes') ? 'Element' : 'Node'; // eslint-disable-line no-prototype-builtins
|
|
this.elementAttributesGetter = win.Object.getOwnPropertyDescriptor(win[this.elementAttributesPropOwnerName].prototype, 'attributes').get;
|
|
var htmlManifestDescriptor = win.Object.getOwnPropertyDescriptor(win.HTMLHtmlElement.prototype, 'manifest');
|
|
// NOTE: Only the Safari browser supports the 'manifest' property
|
|
if (htmlManifestDescriptor) {
|
|
this.htmlManifestGetter = htmlManifestDescriptor.get;
|
|
this.htmlManifestSetter = htmlManifestDescriptor.set;
|
|
}
|
|
// NOTE: IE11 doesn't support the 'srcset' property
|
|
if (iframeSrcdocDescriptor) {
|
|
this.imageSrcsetSetter = imageSrcsetDescriptor.set;
|
|
this.imageSrcsetGetter = imageSrcsetDescriptor.get;
|
|
}
|
|
this.titleElementTextGetter = titleElementTextDescriptor.get;
|
|
// MutationRecord
|
|
this.mutationRecordNextSiblingGetter = win.Object.getOwnPropertyDescriptor(win.MutationRecord.prototype, 'nextSibling').get;
|
|
this.mutationRecordPrevSiblingGetter = win.Object.getOwnPropertyDescriptor(win.MutationRecord.prototype, 'previousSibling').get;
|
|
};
|
|
NativeMethods.prototype.refreshWindowMeths = function (win, isInWorker) {
|
|
if (isInWorker === void 0) { isInWorker = false; }
|
|
win = win || window;
|
|
var winProto = win.constructor.prototype;
|
|
// Dom
|
|
this.eval = win.eval;
|
|
this.formSubmit = win.HTMLFormElement && win.HTMLFormElement.prototype.submit;
|
|
this.documentFragmentQuerySelector = win.DocumentFragment && win.DocumentFragment.prototype.querySelector;
|
|
this.documentFragmentQuerySelectorAll = win.DocumentFragment && win.DocumentFragment.prototype.querySelectorAll;
|
|
this.preventDefault = win.Event.prototype.preventDefault;
|
|
this.historyPushState = win.history && win.history.pushState;
|
|
this.historyReplaceState = win.history && win.history.replaceState;
|
|
this.postMessage = win.postMessage || winProto.postMessage;
|
|
this.windowOpen = win.open || winProto.open;
|
|
this.setTimeout = win.setTimeout || winProto.setTimeout;
|
|
this.setInterval = win.setInterval || winProto.setInterval;
|
|
this.clearTimeout = win.clearTimeout || winProto.clearTimeout;
|
|
this.clearInterval = win.clearInterval || winProto.clearInterval;
|
|
this.registerProtocolHandler = win.navigator.registerProtocolHandler;
|
|
this.sendBeacon = win.Navigator && win.Navigator.prototype.sendBeacon;
|
|
if (win.XMLHttpRequest) {
|
|
// NOTE: IE11 has no EventTarget so we should save "Event" methods separately
|
|
var xhrEventProto = (win.EventTarget || win.XMLHttpRequest).prototype;
|
|
this.xhrAbort = win.XMLHttpRequest.prototype.abort;
|
|
this.xhrOpen = win.XMLHttpRequest.prototype.open;
|
|
this.xhrSend = win.XMLHttpRequest.prototype.send;
|
|
this.xhrAddEventListener = xhrEventProto.addEventListener;
|
|
this.xhrRemoveEventListener = xhrEventProto.removeEventListener;
|
|
this.xhrDispatchEvent = xhrEventProto.dispatchEvent;
|
|
this.xhrGetResponseHeader = win.XMLHttpRequest.prototype.getResponseHeader;
|
|
this.xhrGetAllResponseHeaders = win.XMLHttpRequest.prototype.getAllResponseHeaders;
|
|
this.xhrSetRequestHeader = win.XMLHttpRequest.prototype.setRequestHeader;
|
|
this.xhrOverrideMimeType = win.XMLHttpRequest.prototype.overrideMimeType;
|
|
}
|
|
try {
|
|
this.registerServiceWorker = win.navigator.serviceWorker.register;
|
|
this.getRegistrationServiceWorker = win.navigator.serviceWorker.getRegistration;
|
|
}
|
|
catch (e) {
|
|
this.registerServiceWorker = null;
|
|
this.getRegistrationServiceWorker = null;
|
|
}
|
|
this.createContextualFragment = win.Range && win.Range.prototype.createContextualFragment;
|
|
var nativePerformance = win.performance;
|
|
if (nativePerformance) {
|
|
// eslint-disable-next-line no-restricted-properties
|
|
var nativePerformanceNow_1 = win.performance.now || win.Performance.prototype.now;
|
|
this.performanceNow = function () {
|
|
var args = [];
|
|
for (var _i = 0; _i < arguments.length; _i++) {
|
|
args[_i] = arguments[_i];
|
|
}
|
|
return nativePerformanceNow_1.apply(nativePerformance, args);
|
|
};
|
|
}
|
|
// Fetch
|
|
this.fetch = win.fetch;
|
|
this.Request = win.Request;
|
|
if (win.Headers) {
|
|
this.Headers = win.Headers;
|
|
this.headersSet = win.Headers.prototype.set;
|
|
this.headersGet = win.Headers.prototype.get;
|
|
this.headersDelete = win.Headers.prototype.delete;
|
|
this.headersEntries = win.Headers.prototype.entries;
|
|
this.headersForEach = win.Headers.prototype.forEach;
|
|
this.headersValues = win.Headers.prototype.values;
|
|
}
|
|
// Event
|
|
this.windowAddEventListener = win.addEventListener || winProto.addEventListener;
|
|
this.windowRemoveEventListener = win.removeEventListener || winProto.removeEventListener;
|
|
this.windowDispatchEvent = win.dispatchEvent;
|
|
this.WindowPointerEvent = win.PointerEvent || winProto.PointerEvent;
|
|
this.WindowMSPointerEvent = win.MSPointerEvent || winProto.MSPointerEvent;
|
|
this.WindowTouch = win.Touch || winProto.Touch;
|
|
this.WindowTouchEvent = win.TouchEvent || winProto.TouchEvent;
|
|
this.WindowKeyboardEvent = win.KeyboardEvent || winProto.KeyboardEvent;
|
|
this.WindowFocusEvent = win.FocusEvent || winProto.FocusEvent;
|
|
this.WindowTextEvent = win.TextEvent || winProto.TextEvent;
|
|
this.WindowInputEvent = win.InputEvent || winProto.InputEvent;
|
|
this.WindowMouseEvent = win.MouseEvent || winProto.MouseEvent;
|
|
this.eventTargetGetter = win.Object.getOwnPropertyDescriptor(win.Event.prototype, 'target').get;
|
|
this.canvasContextDrawImage = win.CanvasRenderingContext2D && win.CanvasRenderingContext2D.prototype.drawImage;
|
|
// FormData
|
|
this.formDataAppend = win.FormData && win.FormData.prototype.append;
|
|
// DateTime
|
|
this.date = win.Date;
|
|
this.dateNow = win.Date.now; // eslint-disable-line no-restricted-properties
|
|
// Math
|
|
this.math = win.Math;
|
|
this.mathRandom = win.Math.random;
|
|
// Object
|
|
this.objectToString = win.Object.prototype.toString;
|
|
this.objectAssign = win.Object.assign;
|
|
this.objectKeys = win.Object.keys;
|
|
this.objectDefineProperty = win.Object.defineProperty;
|
|
this.objectDefineProperties = win.Object.defineProperties;
|
|
this.objectCreate = win.Object.create;
|
|
this.objectIsExtensible = win.Object.isExtensible;
|
|
this.objectIsFrozen = win.Object.isFrozen;
|
|
this.objectGetOwnPropertyDescriptor = win.Object.getOwnPropertyDescriptor;
|
|
this.objectHasOwnProperty = win.Object.hasOwnProperty;
|
|
this.objectGetOwnPropertyNames = win.Object.getOwnPropertyNames;
|
|
this.objectGetPrototypeOf = win.Object.getPrototypeOf;
|
|
this.objectSetPrototypeOf = win.Object.setPrototypeOf;
|
|
this.objectGetOwnPropertySymbols = win.Object.getOwnPropertySymbols;
|
|
// Array
|
|
this.arraySlice = win.Array.prototype.slice;
|
|
this.arrayConcat = win.Array.prototype.concat;
|
|
this.arrayFilter = win.Array.prototype.filter;
|
|
this.arrayFind = win.Array.prototype.find;
|
|
this.arrayMap = win.Array.prototype.map;
|
|
this.arrayJoin = win.Array.prototype.join;
|
|
this.arraySplice = win.Array.prototype.splice;
|
|
this.arrayUnshift = win.Array.prototype.unshift;
|
|
this.arrayForEach = win.Array.prototype.forEach;
|
|
this.arrayIndexOf = win.Array.prototype.indexOf;
|
|
this.arraySome = win.Array.prototype.some;
|
|
this.arrayEvery = win.Array.prototype.every;
|
|
this.arrayReverse = win.Array.prototype.reverse;
|
|
this.arrayReduce = win.Array.prototype.reduce;
|
|
this.arrayFrom = win.Array.from;
|
|
this.isArray = win.Array.isArray;
|
|
this.DOMParserParseFromString = win.DOMParser && win.DOMParser.prototype.parseFromString;
|
|
this.arrayBufferIsView = win.ArrayBuffer.prototype.constructor.isView;
|
|
// NOTE: this section relates to getting properties from DOM classes
|
|
if (!isInWorker) {
|
|
// DOMTokenList
|
|
this.tokenListAdd = win.DOMTokenList.prototype.add;
|
|
this.tokenListRemove = win.DOMTokenList.prototype.remove;
|
|
this.tokenListReplace = win.DOMTokenList.prototype.replace;
|
|
this.tokenListSupports = win.DOMTokenList.prototype.supports;
|
|
this.tokenListToggle = win.DOMTokenList.prototype.toggle;
|
|
this.tokenListContains = win.DOMTokenList.prototype.contains;
|
|
var tokenListValueDescriptor = win.Object.getOwnPropertyDescriptor(win.DOMTokenList.prototype, 'value');
|
|
// NOTE: IE11 doesn't support the 'value' property of the DOMTokenList interface
|
|
if (tokenListValueDescriptor)
|
|
this.tokenListValueSetter = tokenListValueDescriptor.set;
|
|
// Stylesheets
|
|
this.styleGetPropertyValue = win.CSSStyleDeclaration.prototype.getPropertyValue;
|
|
this.styleSetProperty = win.CSSStyleDeclaration.prototype.setProperty;
|
|
this.styleRemoveProperty = win.CSSStyleDeclaration.prototype.removeProperty;
|
|
this.styleInsertRule = win.CSSStyleSheet.prototype.insertRule;
|
|
this.scrollTo = win.scrollTo;
|
|
}
|
|
if (win.Promise) {
|
|
this.promiseThen = win.Promise.prototype.then;
|
|
this.promiseReject = win.Promise.reject;
|
|
}
|
|
// Console
|
|
this.console = win.console;
|
|
if (this.console) {
|
|
this.consoleMeths = {
|
|
log: win.console.log,
|
|
warn: win.console.warn,
|
|
error: win.console.error,
|
|
info: win.console.info,
|
|
};
|
|
}
|
|
this.crypto = win.crypto || win.msCrypto;
|
|
this.cryptoGetRandomValues = this.crypto && this.crypto.getRandomValues;
|
|
this.refreshClasses(win);
|
|
this._refreshGettersAndSetters(win, isInWorker);
|
|
};
|
|
NativeMethods.prototype.refreshClasses = function (win) {
|
|
this.windowClass = win.Window;
|
|
this.documentClass = win.Document;
|
|
this.locationClass = win.Location;
|
|
this.elementClass = win.Element;
|
|
this.svgElementClass = win.SVGElement;
|
|
this.Worker = win.Worker;
|
|
this.MessageChannel = win.MessageChannel;
|
|
this.Array = win.Array;
|
|
this.ArrayBuffer = win.ArrayBuffer;
|
|
this.Uint8Array = win.Uint8Array;
|
|
this.Uint16Array = win.Uint16Array;
|
|
this.Uint32Array = win.Uint32Array;
|
|
this.DataView = win.DataView;
|
|
this.Blob = win.Blob;
|
|
this.XMLHttpRequest = win.XMLHttpRequest;
|
|
this.Image = win.Image;
|
|
this.Function = win.Function;
|
|
this.functionToString = win.Function.prototype.toString;
|
|
this.functionBind = win.Function.prototype.bind;
|
|
this.Error = win.Error;
|
|
this.FontFace = win.FontFace;
|
|
this.StorageEvent = win.StorageEvent;
|
|
this.MutationObserver = win.MutationObserver;
|
|
this.EventSource = win.EventSource;
|
|
this.Proxy = win.Proxy;
|
|
this.WebSocket = win.WebSocket;
|
|
this.HTMLCollection = win.HTMLCollection;
|
|
this.NodeList = win.NodeList;
|
|
this.Node = win.Node;
|
|
this.URL = win.URL;
|
|
this.DataTransfer = win.DataTransfer;
|
|
this.DataTransferItemList = win.DataTransferItemList;
|
|
this.DataTransferItem = win.DataTransferItem;
|
|
this.FileList = win.FileList;
|
|
// NOTE: non-IE11 case. window.File in IE11 is not constructable.
|
|
if (win.File && isFunction(win.File))
|
|
this.File = win.File;
|
|
};
|
|
NativeMethods.prototype.refreshElectronMeths = function (vmModule) {
|
|
if (this.createScript && isNativeFunction(vmModule.createScript))
|
|
return false;
|
|
this.createScript = vmModule.createScript;
|
|
this.runInDebugContext = vmModule.runInDebugContext;
|
|
this.runInContext = vmModule.runInContext;
|
|
this.runInNewContext = vmModule.runInNewContext;
|
|
this.runInThisContext = vmModule.runInThisContext;
|
|
return true;
|
|
};
|
|
NativeMethods._ensureDocumentMethodRestore = function (document, prototype, methodName, savedNativeMethod) {
|
|
prototype[methodName] = savedNativeMethod;
|
|
if (document[methodName] !== prototype[methodName])
|
|
document[methodName] = savedNativeMethod;
|
|
};
|
|
NativeMethods.prototype.restoreDocumentMeths = function (window, document) {
|
|
var docPrototype = window.Document.prototype;
|
|
NativeMethods._ensureDocumentMethodRestore(document, docPrototype, 'createDocumentFragment', this.createDocumentFragment);
|
|
NativeMethods._ensureDocumentMethodRestore(document, docPrototype, 'createElement', this.createElement);
|
|
NativeMethods._ensureDocumentMethodRestore(document, docPrototype, 'createElementNS', this.createElementNS);
|
|
NativeMethods._ensureDocumentMethodRestore(document, docPrototype, 'elementFromPoint', this.elementFromPoint);
|
|
NativeMethods._ensureDocumentMethodRestore(document, docPrototype, 'caretRangeFromPoint', this.caretRangeFromPoint);
|
|
NativeMethods._ensureDocumentMethodRestore(document, docPrototype, 'caretPositionFromPoint', this.caretPositionFromPoint);
|
|
NativeMethods._ensureDocumentMethodRestore(document, docPrototype, 'getElementById', this.getElementById);
|
|
NativeMethods._ensureDocumentMethodRestore(document, docPrototype, 'getElementsByClassName', this.getElementsByClassName);
|
|
NativeMethods._ensureDocumentMethodRestore(document, docPrototype, 'getElementsByName', this.getElementsByName);
|
|
NativeMethods._ensureDocumentMethodRestore(document, docPrototype, 'getElementsByTagName', this.getElementsByTagName);
|
|
NativeMethods._ensureDocumentMethodRestore(document, docPrototype, 'querySelector', this.querySelector);
|
|
NativeMethods._ensureDocumentMethodRestore(document, docPrototype, 'querySelectorAll', this.querySelectorAll);
|
|
// Event
|
|
// NOTE: IE11 has no EventTarget
|
|
if (!window.EventTarget) {
|
|
NativeMethods._ensureDocumentMethodRestore(document, docPrototype, 'addEventListener', this.documentAddEventListener);
|
|
NativeMethods._ensureDocumentMethodRestore(document, docPrototype, 'removeEventListener', this.documentRemoveEventListener);
|
|
}
|
|
NativeMethods._ensureDocumentMethodRestore(document, docPrototype, 'createEvent', this.documentCreateEvent);
|
|
NativeMethods._ensureDocumentMethodRestore(document, docPrototype, 'createTouch', this.documentCreateTouch);
|
|
NativeMethods._ensureDocumentMethodRestore(document, docPrototype, 'createTouchList', this.documentCreateTouchList);
|
|
NativeMethods._ensureDocumentMethodRestore(document, window[this.documentOpenPropOwnerName].prototype, 'open', this.documentOpen);
|
|
NativeMethods._ensureDocumentMethodRestore(document, window[this.documentClosePropOwnerName].prototype, 'close', this.documentClose);
|
|
NativeMethods._ensureDocumentMethodRestore(document, window[this.documentWritePropOwnerName].prototype, 'write', this.documentWrite);
|
|
NativeMethods._ensureDocumentMethodRestore(document, window[this.documentWriteLnPropOwnerName].prototype, 'writeln', this.documentWriteLn);
|
|
};
|
|
NativeMethods.prototype.refreshIfNecessary = function (doc, win) {
|
|
var _this = this;
|
|
var tryToExecuteCode = function (func) {
|
|
try {
|
|
return func();
|
|
}
|
|
catch (e) {
|
|
return true;
|
|
}
|
|
};
|
|
var needToRefreshDocumentMethods = tryToExecuteCode(function () { return !doc.createElement || isNativeFunction(document.createElement); });
|
|
var needToRefreshElementMethods = tryToExecuteCode(function () {
|
|
var nativeElement = _this.createElement.call(doc, 'div');
|
|
return isNativeFunction(nativeElement.getAttribute);
|
|
});
|
|
var needToRefreshWindowMethods = tryToExecuteCode(function () {
|
|
_this.setTimeout.call(win, function () { return void 0; }, 0);
|
|
return isNativeFunction(win.XMLHttpRequest.prototype.open);
|
|
});
|
|
// NOTE: T173709
|
|
if (needToRefreshDocumentMethods)
|
|
this.refreshDocumentMeths(doc, win);
|
|
if (needToRefreshElementMethods)
|
|
this.refreshElementMeths(doc, win);
|
|
// NOTE: T239109
|
|
if (needToRefreshWindowMethods)
|
|
this.refreshWindowMeths(win);
|
|
};
|
|
NativeMethods.prototype.isNativeCode = function (fn) {
|
|
return NATIVE_CODE_RE.test(this.functionToString.call(fn));
|
|
};
|
|
return NativeMethods;
|
|
}());
|
|
var nativeMethods = new NativeMethods();
|
|
|
|
var instanceAndPrototypeToStringAreEqual = false;
|
|
if (nativeMethods.createElement) {
|
|
var form = nativeMethods.createElement.call(document, 'form');
|
|
var elements = nativeMethods.getElementsByName.call(document, '');
|
|
// NOTE: In some browsers, elements without the url attribute return the location url
|
|
// when accessing this attribute directly. See form.action in Edge 25 as an example.
|
|
nativeMethods.formActionGetter.call(form) === window.location.toString();
|
|
// NOTE: In Chrome, toString(window) equals '[object Window]' and toString(Window.prototype) equals '[object Blob]',
|
|
// this condition is also satisfied for Blob, Document, XMLHttpRequest, etc
|
|
instanceAndPrototypeToStringAreEqual = nativeMethods.objectToString.call(window) ===
|
|
nativeMethods.objectToString.call(Window.prototype);
|
|
// NOTE: In the Edge 17, the getNamedItem method of attributes object is not enumerable
|
|
!!nativeMethods.objectGetOwnPropertyDescriptor.call(window.Object, NamedNodeMap.prototype, 'getNamedItem');
|
|
// Both IE and Edge return an HTMLCollection, not a NodeList
|
|
// @ts-ignore
|
|
nativeMethods.objectGetPrototypeOf.call(window.Object, elements) ===
|
|
nativeMethods.HTMLCollection.prototype;
|
|
}
|
|
|
|
var WINDOW_IS_UNDEFINED = typeof window === 'undefined';
|
|
WINDOW_IS_UNDEFINED ? '' : instanceToString(window);
|
|
WINDOW_IS_UNDEFINED ? '' : instanceToString(nativeMethods.createElement.call(document, 'td'));
|
|
var ELEMENT_NODE_TYPE = WINDOW_IS_UNDEFINED ? -1 : Node.ELEMENT_NODE;
|
|
function instanceToString(instance) {
|
|
if (!instanceAndPrototypeToStringAreEqual)
|
|
return nativeMethods.objectToString.call(instance);
|
|
return instance && typeof instance === 'object'
|
|
? nativeMethods.objectToString.call(nativeMethods.objectGetPrototypeOf(instance))
|
|
: '';
|
|
}
|
|
function getIframeLocation(iframe) {
|
|
var documentLocation = null;
|
|
try {
|
|
// eslint-disable-next-line no-restricted-properties
|
|
documentLocation = nativeMethods.contentDocumentGetter.call(iframe).location.href;
|
|
}
|
|
catch (e) {
|
|
documentLocation = null;
|
|
}
|
|
var srcLocation = nativeMethods.getAttribute.call(iframe, 'src' + INTERNAL_ATTRS.storedAttrPostfix) ||
|
|
nativeMethods.getAttribute.call(iframe, 'src') || nativeMethods.iframeSrcGetter.call(iframe);
|
|
var parsedProxyDocumentLocation = documentLocation && isSupportedProtocol(documentLocation) &&
|
|
parseProxyUrl(documentLocation);
|
|
var parsedProxySrcLocation = srcLocation && isSupportedProtocol(srcLocation) &&
|
|
parseProxyUrl(srcLocation);
|
|
return {
|
|
documentLocation: parsedProxyDocumentLocation ? parsedProxyDocumentLocation.destUrl : documentLocation,
|
|
srcLocation: parsedProxySrcLocation ? parsedProxySrcLocation.destUrl : srcLocation,
|
|
};
|
|
}
|
|
function getFrameElement(win) {
|
|
try {
|
|
return win.frameElement;
|
|
}
|
|
catch (e) {
|
|
return null;
|
|
}
|
|
}
|
|
function findDocument(el) {
|
|
if (el.documentElement)
|
|
return el;
|
|
if (el.ownerDocument && el.ownerDocument.defaultView)
|
|
return el.ownerDocument;
|
|
var parent = isElementNode(el) && nativeMethods.nodeParentNodeGetter.call(el);
|
|
return parent ? findDocument(parent) : document;
|
|
}
|
|
var SHADOW_ROOT_PARENT_ELEMENT = 'hammerhead|element|shadow-root-parent';
|
|
function getNodeShadowRootParent(el) {
|
|
var parent = nativeMethods.nodeParentNodeGetter.call(el);
|
|
while (parent && parent.nodeType !== Node.DOCUMENT_FRAGMENT_NODE)
|
|
parent = nativeMethods.nodeParentNodeGetter.call(parent);
|
|
return parent && parent[SHADOW_ROOT_PARENT_ELEMENT];
|
|
}
|
|
function isElementInDocument(el, currentDocument) {
|
|
var doc = currentDocument || document;
|
|
if (!doc.documentElement)
|
|
return false;
|
|
if (doc.documentElement.contains(el))
|
|
return true;
|
|
var shadowRootParent = getNodeShadowRootParent(el);
|
|
return shadowRootParent ? isElementInDocument(shadowRootParent) : false;
|
|
}
|
|
function isIframeWithoutSrc(iframe) {
|
|
var iframeLocation = getIframeLocation(iframe);
|
|
var iframeSrcLocation = iframeLocation.srcLocation;
|
|
var iframeDocumentLocation = iframeLocation.documentLocation;
|
|
// NOTE: is a cross-domain iframe
|
|
if (iframeDocumentLocation === null)
|
|
return false;
|
|
// NOTE: after 'document.write' or 'document.open' call for iframe with/without src
|
|
// we will process it as iframe without src
|
|
if (nativeMethods.contentWindowGetter.call(iframe)[INTERNAL_PROPS.documentWasCleaned])
|
|
return true;
|
|
var iframeDocumentLocationHaveSupportedProtocol = isSupportedProtocol(iframeDocumentLocation);
|
|
// NOTE: When an iframe has an empty src attribute (<iframe src></iframe>) or has no src attribute (<iframe></iframe>),
|
|
// the iframe.src property is not empty but has different values in different browsers.
|
|
// Its document location is 'about:blank'. Therefore, we should check the src attribute.
|
|
if (!iframeDocumentLocationHaveSupportedProtocol && !nativeMethods.getAttribute.call(iframe, 'src'))
|
|
return true;
|
|
// In Chrome, when an iframe with the src attribute is added to DOM,
|
|
// its documentLocation is set to "about:blank" until the iframe has been loaded.
|
|
// So, we should check srcLocation in this case.
|
|
if (iframeSrcLocation && isSupportedProtocol(iframeSrcLocation))
|
|
return false;
|
|
return !iframeDocumentLocationHaveSupportedProtocol;
|
|
}
|
|
function isFetchHeaders(instance) {
|
|
if (nativeMethods.Headers && instance instanceof nativeMethods.Headers)
|
|
return true;
|
|
return instance && instanceToString(instance) === '[object Headers]';
|
|
}
|
|
function isFetchRequest(instance) {
|
|
if (nativeMethods.Request && instance instanceof nativeMethods.Request)
|
|
return true;
|
|
return instance && instanceToString(instance) === '[object Request]';
|
|
}
|
|
function isElementNode(node) {
|
|
return node && node.nodeType === ELEMENT_NODE_TYPE;
|
|
}
|
|
|
|
var DOCUMENT_URL_RESOLVER = 'hammerhead|document-url-resolver';
|
|
var urlResolver = {
|
|
_createResolver: function (doc) {
|
|
var htmlDocument = nativeMethods.createHTMLDocument.call(doc.implementation, 'title');
|
|
var a = nativeMethods.createElement.call(htmlDocument, 'a');
|
|
var base = nativeMethods.createElement.call(htmlDocument, 'base');
|
|
nativeMethods.appendChild.call(htmlDocument.body, a);
|
|
nativeMethods.appendChild.call(htmlDocument.head, base);
|
|
return htmlDocument;
|
|
},
|
|
_getResolver: function (doc) {
|
|
// NOTE: Once a document is recreated (document.open, document.write is called), nativeMethods will be refreshed.
|
|
// If we call urlResolve.updateBase after this,
|
|
// we will use native methods from an actual document.
|
|
// However, a document that contains an element for url resolving is created using a previous version of nativeMethods.
|
|
if (!doc[DOCUMENT_URL_RESOLVER]) {
|
|
nativeMethods.objectDefineProperty(doc, DOCUMENT_URL_RESOLVER, {
|
|
value: this._createResolver(doc),
|
|
writable: true,
|
|
});
|
|
}
|
|
return doc[DOCUMENT_URL_RESOLVER];
|
|
},
|
|
_isNestedIframeWithoutSrc: function (win) {
|
|
if (!win || !win.parent || win.parent === win || win.parent.parent === win.parent)
|
|
return false;
|
|
var iframeElement = getFrameElement(window);
|
|
return !!iframeElement && isIframeWithoutSrc(iframeElement);
|
|
},
|
|
init: function (doc) {
|
|
this.updateBase(get(), doc);
|
|
},
|
|
getResolverElement: function (doc) {
|
|
return nativeMethods.nodeFirstChildGetter.call(this._getResolver(doc).body);
|
|
},
|
|
resolve: function (url, doc) {
|
|
var resolver = this.getResolverElement(doc);
|
|
var href = null;
|
|
if (url === null)
|
|
nativeMethods.removeAttribute.call(resolver, 'href');
|
|
else {
|
|
nativeMethods.anchorHrefSetter.call(resolver, url);
|
|
href = nativeMethods.anchorHrefGetter.call(resolver);
|
|
// NOTE: It looks like a Chrome bug: in a nested iframe without src (when an iframe is placed into another
|
|
// iframe) you cannot set a relative link href while the iframe loading is not completed. So, we'll do it with
|
|
// the parent's urlResolver Safari demonstrates similar behavior, but urlResolver.href has a relative URL value.
|
|
var needUseParentResolver = url && (!href || href.charAt(0) === '/') &&
|
|
this._isNestedIframeWithoutSrc(doc.defaultView);
|
|
if (needUseParentResolver)
|
|
return this.resolve(url, window.parent.document);
|
|
}
|
|
return ensureTrailingSlash(url, href);
|
|
},
|
|
updateBase: function (url, doc) {
|
|
if (this.proxyless)
|
|
return;
|
|
var resolverDocument = this._getResolver(doc);
|
|
var baseElement = nativeMethods.elementGetElementsByTagName.call(resolverDocument.head, 'base')[0];
|
|
url = url || get();
|
|
/*eslint-disable no-restricted-properties*/
|
|
var parsedUrl = parseUrl$1(url);
|
|
var isRelativeUrl = parsedUrl.protocol !== 'file:' && parsedUrl.protocol !== 'about:' && !parsedUrl.host;
|
|
var isProtocolRelativeUrl = /^\/\//.test(url) && !!parsedUrl.host;
|
|
/*eslint-enable no-restricted-properties*/
|
|
if (isRelativeUrl || isProtocolRelativeUrl) {
|
|
var destinationLocation = get();
|
|
this.updateBase(destinationLocation, doc);
|
|
url = this.resolve(url, doc);
|
|
}
|
|
nativeMethods.setAttribute.call(baseElement, 'href', url);
|
|
},
|
|
getBaseUrl: function (doc) {
|
|
var baseElement = nativeMethods.elementGetElementsByTagName.call(this._getResolver(doc).head, 'base')[0];
|
|
return nativeMethods.getAttribute.call(baseElement, 'href');
|
|
},
|
|
changeUrlPart: function (url, nativePropSetter, value, doc) {
|
|
var resolver = this.getResolverElement(doc);
|
|
nativeMethods.anchorHrefSetter.call(resolver, url);
|
|
nativePropSetter.call(resolver, value);
|
|
return nativeMethods.anchorHrefGetter.call(resolver);
|
|
},
|
|
dispose: function (doc) {
|
|
doc[DOCUMENT_URL_RESOLVER] = null;
|
|
},
|
|
get proxyless() {
|
|
return this._proxyless;
|
|
},
|
|
set proxyless(value) {
|
|
this._proxyless = value;
|
|
},
|
|
};
|
|
|
|
var Settings = /** @class */ (function () {
|
|
function Settings() {
|
|
this._settings = {
|
|
isFirstPageLoad: true,
|
|
sessionId: '',
|
|
forceProxySrcForImage: false,
|
|
crossDomainProxyPort: '',
|
|
referer: '',
|
|
serviceMsgUrl: '',
|
|
transportWorkerUrl: '',
|
|
iframeTaskScriptTemplate: '',
|
|
cookie: '',
|
|
allowMultipleWindows: false,
|
|
isRecordMode: false,
|
|
windowId: '',
|
|
proxyless: false,
|
|
disableCrossDomain: false,
|
|
};
|
|
}
|
|
Settings.prototype.set = function (value) {
|
|
this._settings = value;
|
|
};
|
|
Settings.prototype.get = function () {
|
|
return this._settings;
|
|
};
|
|
return Settings;
|
|
}());
|
|
var settings = new Settings();
|
|
|
|
var forcedLocation = null;
|
|
// NOTE: exposed only for tests
|
|
function getLocation() {
|
|
// NOTE: Used for testing. Unfortunately, we cannot override the 'getLocation' method in a test.
|
|
if (forcedLocation)
|
|
return forcedLocation;
|
|
var frameElement = getFrameElement(globalContextInfo.global);
|
|
// NOTE: Fallback to the owner page's URL if we are in an iframe without src.
|
|
if (frameElement && isIframeWithoutSrc(frameElement))
|
|
return settings.get().referer;
|
|
return globalContextInfo.global.location.toString();
|
|
}
|
|
// NOTE: We need to be able to force the page location. During the test, Hammerhead should think that it is on the
|
|
// proxied page, not in the test environment. Unfortunately, we cannot do it in any other way.
|
|
function forceLocation(url) {
|
|
forcedLocation = url;
|
|
}
|
|
function sameOriginCheck(location, checkedUrl) {
|
|
if (checkedUrl)
|
|
checkedUrl = resolveUrl(checkedUrl);
|
|
return settings.get().disableCrossDomain || sameOriginCheck$1(location, checkedUrl);
|
|
}
|
|
function resolveUrl(url, doc) {
|
|
var preProcessedUrl = getURLString(url);
|
|
if (preProcessedUrl && preProcessedUrl.indexOf('//') === 0) {
|
|
// eslint-disable-next-line no-restricted-properties
|
|
var pageProtocol = getParsed().protocol;
|
|
preProcessedUrl = pageProtocol + correctMultipleSlashes(preProcessedUrl, pageProtocol);
|
|
}
|
|
else
|
|
preProcessedUrl = correctMultipleSlashes(preProcessedUrl);
|
|
if (globalContextInfo.isInWorker) {
|
|
if (self.location.protocol !== 'blob:') // eslint-disable-line no-restricted-properties
|
|
return new nativeMethods.URL(preProcessedUrl, get()).href; // eslint-disable-line no-restricted-properties
|
|
return String(url);
|
|
}
|
|
return urlResolver.resolve(preProcessedUrl, doc || document);
|
|
}
|
|
var get = function () {
|
|
var location = getLocation();
|
|
var parsedProxyUrl = parseProxyUrl$1(location);
|
|
return parsedProxyUrl ? parsedProxyUrl.destUrl : location;
|
|
};
|
|
function parseLocationThroughAnchor(url) {
|
|
var resolver = urlResolver.getResolverElement(document);
|
|
// eslint-disable-next-line no-restricted-properties
|
|
var destPort = parseUrl$1(url).port;
|
|
// NOTE: IE browser adds the default port for the https protocol while resolving.
|
|
nativeMethods.anchorHrefSetter.call(resolver, get());
|
|
var hostname = nativeMethods.anchorHostnameGetter.call(resolver);
|
|
var pathname = nativeMethods.anchorPathnameGetter.call(resolver);
|
|
// NOTE: IE ignores the first '/' symbol in the pathname.
|
|
if (pathname.charAt(0) !== '/')
|
|
pathname = '/' + pathname;
|
|
// TODO: Describe default ports logic.
|
|
return {
|
|
protocol: nativeMethods.anchorProtocolGetter.call(resolver),
|
|
// NOTE: Remove the default port.
|
|
port: destPort ? nativeMethods.anchorPortGetter.call(resolver) : '',
|
|
hostname: hostname,
|
|
// NOTE: Remove the default port from the host.
|
|
host: destPort ? nativeMethods.anchorHostGetter.call(resolver) : hostname,
|
|
pathname: pathname,
|
|
hash: resolver.hash,
|
|
search: nativeMethods.anchorSearchGetter.call(resolver),
|
|
};
|
|
}
|
|
function parseLocationThroughURL(url) {
|
|
var parsedUrl = new nativeMethods.URL(url);
|
|
/* eslint-disable no-restricted-properties */
|
|
return {
|
|
protocol: parsedUrl.protocol,
|
|
port: parsedUrl.port,
|
|
hostname: parsedUrl.hostname,
|
|
host: parsedUrl.host,
|
|
pathname: parsedUrl.pathname,
|
|
hash: parsedUrl.hash,
|
|
search: parsedUrl.search,
|
|
};
|
|
/* eslint-enable no-restricted-properties */
|
|
}
|
|
function getParsed() {
|
|
var dest = get();
|
|
return globalContextInfo.isInWorker ? parseLocationThroughURL(dest) : parseLocationThroughAnchor(dest);
|
|
}
|
|
function getOriginHeader() {
|
|
return getDomain(getParsed());
|
|
}
|
|
|
|
var SUPPORTED_WEB_SOCKET_PROTOCOL_RE = /^wss?:/i;
|
|
// NOTE: The window.location equals 'about:blank' in iframes without src
|
|
// therefore we need to find a window with src to get the proxy settings
|
|
var DEFAULT_PROXY_SETTINGS = (function () {
|
|
/*eslint-disable no-restricted-properties*/
|
|
var locationWindow = globalContextInfo.isInWorker ? { location: parseUrl(self.location.origin), parent: null } : window;
|
|
var proxyLocation = locationWindow.location;
|
|
while (!proxyLocation.hostname) {
|
|
// about:blank page in proxyless mode
|
|
if (!globalContextInfo.isInWorker
|
|
&& locationWindow === locationWindow.top)
|
|
break;
|
|
locationWindow = locationWindow.parent;
|
|
proxyLocation = locationWindow.location;
|
|
}
|
|
return {
|
|
hostname: proxyLocation.hostname,
|
|
port: proxyLocation.port.toString(),
|
|
protocol: proxyLocation.protocol,
|
|
};
|
|
/*eslint-enable no-restricted-properties*/
|
|
})();
|
|
function getCharsetFromDocument(parsedResourceType) {
|
|
if (!parsedResourceType.isScript && !parsedResourceType.isServiceWorker)
|
|
return null;
|
|
return self.document && document[INTERNAL_PROPS.documentCharset] || null;
|
|
}
|
|
var getProxyUrl = function (url, opts, proxyless) {
|
|
if (opts === void 0) { opts = {}; }
|
|
if (proxyless === void 0) { proxyless = false; }
|
|
if (opts.isUrlsSet) {
|
|
opts.isUrlsSet = false;
|
|
return handleUrlsSet(getProxyUrl, String(url), opts, proxyless);
|
|
}
|
|
if (proxyless)
|
|
return String(url);
|
|
url = getURLString(url);
|
|
var resourceType = opts && opts.resourceType;
|
|
var parsedResourceType = parseResourceType(resourceType);
|
|
if (!parsedResourceType.isWebSocket && !isSupportedProtocol(url) && !isSpecialPage(url))
|
|
return url;
|
|
// NOTE: Resolves relative URLs.
|
|
var resolvedUrl = resolveUrl(url, opts && opts.doc);
|
|
if (parsedResourceType.isWebSocket && !isValidWebSocketUrl(resolvedUrl) || !isValidUrl(resolvedUrl))
|
|
return url;
|
|
/*eslint-disable no-restricted-properties*/
|
|
var proxyHostname = opts && opts.proxyHostname || DEFAULT_PROXY_SETTINGS.hostname;
|
|
var proxyPort = opts && opts.proxyPort || DEFAULT_PROXY_SETTINGS.port;
|
|
var proxyServerProtocol = opts && opts.proxyProtocol || DEFAULT_PROXY_SETTINGS.protocol;
|
|
/*eslint-enable no-restricted-properties*/
|
|
var proxyProtocol = parsedResourceType.isWebSocket
|
|
? proxyServerProtocol.replace('http', 'ws')
|
|
: proxyServerProtocol;
|
|
var sessionId = opts && opts.sessionId || settings.get().sessionId;
|
|
var windowId = opts && opts.windowId || settings.get().windowId;
|
|
var credentials = opts && opts.credentials;
|
|
var charset = opts && opts.charset;
|
|
var reqOrigin = opts && opts.reqOrigin;
|
|
var crossDomainPort = getCrossDomainProxyPort(proxyPort);
|
|
// NOTE: If the relative URL contains no slash (e.g. 'img123'), the resolver will keep
|
|
// the original proxy information, so that we can return such URL as is.
|
|
// TODO: Implement the isProxyURL function.
|
|
var parsedProxyUrl = parseProxyUrl$1(resolvedUrl);
|
|
/*eslint-disable no-restricted-properties*/
|
|
var isValidProxyUrl = !!parsedProxyUrl && parsedProxyUrl.proxy.hostname === proxyHostname &&
|
|
(parsedProxyUrl.proxy.port === proxyPort || parsedProxyUrl.proxy.port === crossDomainPort);
|
|
/*eslint-enable no-restricted-properties*/
|
|
if (isValidProxyUrl) {
|
|
if (resourceType && parsedProxyUrl.resourceType === resourceType)
|
|
return resolvedUrl;
|
|
// NOTE: Need to change the proxy URL resource type.
|
|
var destUrl = formatUrl(parsedProxyUrl.destResourceInfo);
|
|
return getProxyUrl(destUrl, {
|
|
proxyProtocol: proxyProtocol,
|
|
proxyHostname: proxyHostname,
|
|
proxyPort: proxyPort,
|
|
sessionId: sessionId,
|
|
resourceType: resourceType,
|
|
charset: charset,
|
|
reqOrigin: reqOrigin,
|
|
credentials: credentials,
|
|
});
|
|
}
|
|
var parsedUrl = parseUrl$1(resolvedUrl);
|
|
if (!parsedUrl.protocol) // eslint-disable-line no-restricted-properties
|
|
return url;
|
|
charset = charset || getCharsetFromDocument(parsedResourceType);
|
|
// NOTE: It seems that the relative URL had the leading slash or dots, so that the proxy info path part was
|
|
// removed by the resolver and we have an origin URL with the incorrect host and protocol.
|
|
/*eslint-disable no-restricted-properties*/
|
|
if (parsedUrl.protocol === proxyServerProtocol && parsedUrl.hostname === proxyHostname &&
|
|
parsedUrl.port === proxyPort) {
|
|
var parsedDestLocation = getParsed();
|
|
parsedUrl.protocol = parsedDestLocation.protocol;
|
|
parsedUrl.host = parsedDestLocation.host;
|
|
parsedUrl.hostname = parsedDestLocation.hostname;
|
|
parsedUrl.port = parsedDestLocation.port || '';
|
|
resolvedUrl = formatUrl(parsedUrl);
|
|
}
|
|
/*eslint-enable no-restricted-properties*/
|
|
if (parsedResourceType.isWebSocket) {
|
|
// eslint-disable-next-line no-restricted-properties
|
|
parsedUrl.protocol = parsedUrl.protocol.replace('ws', 'http');
|
|
resolvedUrl = formatUrl(parsedUrl);
|
|
reqOrigin = reqOrigin || getOriginHeader();
|
|
}
|
|
if (parsedResourceType.isIframe && proxyPort === settings.get().crossDomainProxyPort)
|
|
reqOrigin = reqOrigin || getOriginHeader();
|
|
return getProxyUrl$1(resolvedUrl, {
|
|
proxyProtocol: proxyProtocol,
|
|
proxyHostname: proxyHostname,
|
|
proxyPort: proxyPort,
|
|
sessionId: sessionId,
|
|
resourceType: resourceType,
|
|
charset: charset,
|
|
reqOrigin: reqOrigin,
|
|
windowId: windowId,
|
|
credentials: credentials,
|
|
});
|
|
};
|
|
function getCrossDomainProxyPort(proxyPort) {
|
|
return settings.get().crossDomainProxyPort === proxyPort
|
|
// eslint-disable-next-line no-restricted-properties
|
|
? location.port.toString()
|
|
: settings.get().crossDomainProxyPort;
|
|
}
|
|
var resolveUrlAsDest = function (url, isUrlsSet) {
|
|
if (isUrlsSet === void 0) { isUrlsSet = false; }
|
|
return resolveUrlAsDest$1(url, getProxyUrl, isUrlsSet);
|
|
};
|
|
var parseProxyUrl = function (proxyUrl) {
|
|
return parseProxyUrl$1(proxyUrl);
|
|
};
|
|
function parseUrl(url) {
|
|
return parseUrl$1(url);
|
|
}
|
|
function isValidWebSocketUrl(url) {
|
|
var resolvedUrl = resolveUrlAsDest(url);
|
|
return SUPPORTED_WEB_SOCKET_PROTOCOL_RE.test(resolvedUrl);
|
|
}
|
|
function isSupportedProtocol(url) {
|
|
return isSupportedProtocol$1(url);
|
|
}
|
|
function isSpecialPage(url) {
|
|
return isSpecialPage$1(url);
|
|
}
|
|
function stringifyResourceType(resourceType) {
|
|
return getResourceTypeString(resourceType);
|
|
}
|
|
function getDestinationUrl(proxyUrl) {
|
|
var parsedProxyUrl = parseProxyUrl(proxyUrl);
|
|
return parsedProxyUrl ? parsedProxyUrl.destUrl : proxyUrl;
|
|
}
|
|
function getAjaxProxyUrl(url, credentials, proxyless) {
|
|
if (proxyless === void 0) { proxyless = false; }
|
|
if (proxyless)
|
|
return String(url);
|
|
var isCrossDomain = !sameOriginCheck(getLocation(), url);
|
|
var opts = { resourceType: stringifyResourceType({ isAjax: true }), credentials: credentials };
|
|
if (isCrossDomain) {
|
|
opts.proxyPort = settings.get().crossDomainProxyPort;
|
|
opts.reqOrigin = getOriginHeader();
|
|
}
|
|
return getProxyUrl(url, opts);
|
|
}
|
|
|
|
var EventEmitter = /** @class */ (function () {
|
|
function EventEmitter() {
|
|
this.eventsListeners = nativeMethods.objectCreate(null);
|
|
}
|
|
EventEmitter.prototype.emit = function (evt) {
|
|
var args = [];
|
|
for (var _i = 1; _i < arguments.length; _i++) {
|
|
args[_i - 1] = arguments[_i];
|
|
}
|
|
var listeners = this.eventsListeners[evt];
|
|
if (!listeners)
|
|
return;
|
|
var index = 0;
|
|
while (listeners[index]) {
|
|
// HACK: For IE: after calling document.write, the IFrameSandbox event handler throws the
|
|
// 'Can't execute code from a freed script' exception because the document has been
|
|
// recreated.
|
|
if (isIE) {
|
|
try {
|
|
listeners[index].toString();
|
|
}
|
|
catch (e) {
|
|
nativeMethods.arraySplice.call(listeners, index, 1);
|
|
continue;
|
|
}
|
|
}
|
|
listeners[index++].apply(this, args);
|
|
}
|
|
};
|
|
EventEmitter.prototype.off = function (evt, listener) {
|
|
var listeners = this.eventsListeners[evt];
|
|
if (!listeners)
|
|
return;
|
|
this.eventsListeners[evt] = nativeMethods.arrayFilter.call(listeners, function (currentListener) { return currentListener !== listener; });
|
|
};
|
|
EventEmitter.prototype.on = function (evt, listener) {
|
|
this.eventsListeners[evt] = this.eventsListeners[evt] || [];
|
|
if (this.eventsListeners[evt].indexOf(listener) === -1)
|
|
this.eventsListeners[evt].push(listener);
|
|
return listener;
|
|
};
|
|
return EventEmitter;
|
|
}());
|
|
|
|
var SandboxBase = /** @class */ (function (_super) {
|
|
__extends(SandboxBase, _super);
|
|
function SandboxBase() {
|
|
var _this = _super !== null && _super.apply(this, arguments) || this;
|
|
_this.window = null;
|
|
_this.nativeMethods = nativeMethods;
|
|
_this.document = null;
|
|
_this.proxyless = false;
|
|
return _this;
|
|
}
|
|
// NOTE: The sandbox is deactivated when its window is removed from the DOM.
|
|
SandboxBase.prototype.isDeactivated = function () {
|
|
try {
|
|
// NOTE: In IE11, a situation when the document is not active may occur.
|
|
// eslint-disable-next-line no-unused-expressions
|
|
this.document.body;
|
|
if (this.window[INTERNAL_PROPS.hammerhead]) {
|
|
var frameElement_1 = getFrameElement(this.window);
|
|
return !!frameElement_1 && !isElementInDocument(frameElement_1, findDocument(frameElement_1));
|
|
}
|
|
}
|
|
catch (e) { // eslint-disable-line no-empty
|
|
}
|
|
return true;
|
|
};
|
|
SandboxBase.prototype.attach = function (window, document) {
|
|
this.window = window;
|
|
this.document = document || window.document;
|
|
this.proxyless = !!settings.get().proxyless;
|
|
};
|
|
return SandboxBase;
|
|
}(EventEmitter));
|
|
|
|
var SandboxBaseWithDelayedSettings = /** @class */ (function (_super) {
|
|
__extends(SandboxBaseWithDelayedSettings, _super);
|
|
function SandboxBaseWithDelayedSettings(_waitHammerheadSettings) {
|
|
var _this = _super.call(this) || this;
|
|
_this._waitHammerheadSettings = _waitHammerheadSettings;
|
|
if (_waitHammerheadSettings) {
|
|
_waitHammerheadSettings.then(function () {
|
|
_this._waitHammerheadSettings = null;
|
|
});
|
|
}
|
|
return _this;
|
|
}
|
|
SandboxBaseWithDelayedSettings.prototype.gettingSettingInProgress = function () {
|
|
return !!this._waitHammerheadSettings;
|
|
};
|
|
SandboxBaseWithDelayedSettings.prototype.delayUntilGetSettings = function (action) {
|
|
return this._waitHammerheadSettings.then(action);
|
|
};
|
|
return SandboxBaseWithDelayedSettings;
|
|
}(SandboxBase));
|
|
|
|
// -------------------------------------------------------------
|
|
// WARNING: this file is used by both the client and the server.
|
|
// Do not use any browser or node-specific API!
|
|
// -------------------------------------------------------------
|
|
/* eslint hammerhead/proto-methods: 2 */
|
|
var BUILTIN_HEADERS = {
|
|
authorization: 'authorization',
|
|
wwwAuthenticate: 'www-authenticate',
|
|
proxyAuthorization: 'proxy-authorization',
|
|
proxyAuthenticate: 'proxy-authenticate',
|
|
host: 'host',
|
|
referer: 'referer',
|
|
origin: 'origin',
|
|
contentLength: 'content-length',
|
|
cookie: 'cookie',
|
|
setCookie: 'set-cookie',
|
|
ifModifiedSince: 'if-modified-since',
|
|
ifNoneMatch: 'if-none-match',
|
|
contentType: 'content-type',
|
|
location: 'location',
|
|
xFrameOptions: 'x-frame-options',
|
|
sourceMap: 'sourcemap',
|
|
referrerPolicy: 'referrer-policy',
|
|
refresh: 'refresh',
|
|
link: 'link',
|
|
cacheControl: 'cache-control',
|
|
pragma: 'pragma',
|
|
eTag: 'etag',
|
|
contentDisposition: 'content-disposition',
|
|
accept: 'accept',
|
|
contentEncoding: 'content-encoding',
|
|
expires: 'expires',
|
|
trailer: 'trailer',
|
|
transferEncoding: 'transfer-encoding',
|
|
serviceWorkerAllowed: 'service-worker-allowed',
|
|
accessControlAllowOrigin: 'access-control-allow-origin',
|
|
accessControlAllowCredentials: 'access-control-allow-credentials',
|
|
contentSecurityPolicy: 'content-security-policy',
|
|
contentSecurityPolicyReportOnly: 'content-security-policy-report-only',
|
|
xContentSecurityPolicy: 'x-content-security-policy',
|
|
xContentSecurityPolicyReportOnly: 'x-content-security-policy-report-only',
|
|
xWebkitCsp: 'x-webkit-csp',
|
|
isApiRequest: 'is-api-request',
|
|
userAgent: 'user-agent',
|
|
};
|
|
|
|
// -------------------------------------------------------------
|
|
var AUTHENTICATE_PREFIX = '~~~TestCafe added this prefix to hide the authentication dialog box~~~';
|
|
var AUTHORIZATION_PREFIX = '~~~TestCafe added this prefix to control the authorization flow~~~';
|
|
function hasAuthenticatePrefix(value) {
|
|
return value.indexOf(AUTHENTICATE_PREFIX) > -1;
|
|
}
|
|
function removeAuthenticatePrefix(value) {
|
|
return value.replace(AUTHENTICATE_PREFIX, '');
|
|
}
|
|
function isAuthenticateHeader(headerName) {
|
|
var headerNameStr = String(headerName).toLowerCase();
|
|
return headerNameStr === BUILTIN_HEADERS.wwwAuthenticate || headerNameStr === BUILTIN_HEADERS.proxyAuthenticate;
|
|
}
|
|
function addAuthorizationPrefix(value) {
|
|
return AUTHORIZATION_PREFIX + value;
|
|
}
|
|
function hasAuthorizationPrefix(value) {
|
|
return value.indexOf(AUTHORIZATION_PREFIX) > -1;
|
|
}
|
|
function removeAuthorizationPrefix(value) {
|
|
return value.replace(AUTHORIZATION_PREFIX, '');
|
|
}
|
|
function isAuthorizationHeader(headerName) {
|
|
var headerNameStr = String(headerName).toLowerCase();
|
|
return headerNameStr === BUILTIN_HEADERS.authorization || headerNameStr === BUILTIN_HEADERS.proxyAuthorization;
|
|
}
|
|
|
|
var XHR_READY_STATES = ['UNSENT', 'OPENED', 'HEADERS_RECEIVED', 'LOADING', 'DONE'];
|
|
var XhrSandbox = /** @class */ (function (_super) {
|
|
__extends(XhrSandbox, _super);
|
|
function XhrSandbox(_cookieSandbox, waitHammerheadSettings) {
|
|
var _this = _super.call(this, waitHammerheadSettings) || this;
|
|
_this._cookieSandbox = _cookieSandbox;
|
|
_this.XHR_COMPLETED_EVENT = 'hammerhead|event|xhr-completed';
|
|
_this.XHR_ERROR_EVENT = 'hammerhead|event|xhr-error';
|
|
_this.BEFORE_XHR_SEND_EVENT = 'hammerhead|event|before-xhr-send';
|
|
return _this;
|
|
}
|
|
XhrSandbox.setRequestOptions = function (req, withCredentials, args) {
|
|
XhrSandbox.REQUESTS_OPTIONS.set(req, {
|
|
withCredentials: withCredentials,
|
|
openArgs: args,
|
|
headers: [],
|
|
});
|
|
};
|
|
XhrSandbox.createNativeXHR = function () {
|
|
var xhr = new nativeMethods.XMLHttpRequest();
|
|
xhr.open = nativeMethods.xhrOpen;
|
|
xhr.abort = nativeMethods.xhrAbort;
|
|
xhr.send = nativeMethods.xhrSend;
|
|
xhr.addEventListener = nativeMethods.xhrAddEventListener || nativeMethods.addEventListener;
|
|
xhr.removeEventListener = nativeMethods.xhrRemoveEventListener || nativeMethods.removeEventListener;
|
|
xhr.setRequestHeader = nativeMethods.xhrSetRequestHeader;
|
|
xhr.getResponseHeader = nativeMethods.xhrGetResponseHeader;
|
|
xhr.getAllResponseHeaders = nativeMethods.xhrGetAllResponseHeaders;
|
|
xhr.overrideMimeType = nativeMethods.xhrOverrideMimeType;
|
|
xhr.dispatchEvent = nativeMethods.xhrDispatchEvent || nativeMethods.dispatchEvent;
|
|
return xhr;
|
|
};
|
|
XhrSandbox.openNativeXhr = function (xhr, url, isAsync) {
|
|
xhr.open('POST', url, isAsync);
|
|
xhr.setRequestHeader(BUILTIN_HEADERS.cacheControl, 'no-cache, no-store, must-revalidate');
|
|
};
|
|
XhrSandbox._reopenXhr = function (xhr, reqOpts, proxyless) {
|
|
var url = reqOpts.openArgs[1];
|
|
var withCredentials = xhr.withCredentials;
|
|
reqOpts.withCredentials = withCredentials;
|
|
reqOpts.openArgs[1] = getAjaxProxyUrl(url, withCredentials ? Credentials.include : Credentials.sameOrigin, proxyless);
|
|
nativeMethods.xhrOpen.apply(xhr, reqOpts.openArgs);
|
|
reqOpts.openArgs[1] = url;
|
|
for (var _i = 0, _a = reqOpts.headers; _i < _a.length; _i++) {
|
|
var header = _a[_i];
|
|
nativeMethods.xhrSetRequestHeader.apply(xhr, header);
|
|
}
|
|
};
|
|
XhrSandbox.prototype.attach = function (window) {
|
|
_super.prototype.attach.call(this, window);
|
|
var xhrSandbox = this;
|
|
var xmlHttpRequestProto = window.XMLHttpRequest.prototype;
|
|
var emitXhrCompletedEvent = function () {
|
|
var nativeRemoveEventListener = nativeMethods.xhrRemoveEventListener || nativeMethods.removeEventListener;
|
|
xhrSandbox.emit(xhrSandbox.XHR_COMPLETED_EVENT, { xhr: this });
|
|
nativeRemoveEventListener.call(this, 'loadend', emitXhrCompletedEvent);
|
|
};
|
|
var syncCookieWithClientIfNecessary = function () {
|
|
if (this.readyState < this.HEADERS_RECEIVED)
|
|
return;
|
|
var nativeRemoveEventListener = nativeMethods.xhrRemoveEventListener || nativeMethods.removeEventListener;
|
|
xhrSandbox._cookieSandbox.syncCookie();
|
|
nativeRemoveEventListener.call(this, 'readystatechange', syncCookieWithClientIfNecessary);
|
|
};
|
|
var xmlHttpRequestWrapper = function () {
|
|
var nativeAddEventListener = nativeMethods.xhrAddEventListener || nativeMethods.addEventListener;
|
|
var xhr = new nativeMethods.XMLHttpRequest();
|
|
nativeAddEventListener.call(xhr, 'loadend', emitXhrCompletedEvent);
|
|
nativeAddEventListener.call(xhr, 'readystatechange', syncCookieWithClientIfNecessary);
|
|
return xhr;
|
|
};
|
|
for (var _i = 0, XHR_READY_STATES_1 = XHR_READY_STATES; _i < XHR_READY_STATES_1.length; _i++) {
|
|
var readyState = XHR_READY_STATES_1[_i];
|
|
nativeMethods.objectDefineProperty(xmlHttpRequestWrapper, readyState, nativeMethods.objectGetOwnPropertyDescriptor(nativeMethods.XMLHttpRequest, readyState));
|
|
}
|
|
// NOTE: We cannot just assign constructor property of the prototype of XMLHttpRequest starts from safari 9.0
|
|
overrideConstructor(window, 'XMLHttpRequest', xmlHttpRequestWrapper);
|
|
nativeMethods.objectDefineProperty(xmlHttpRequestProto, 'constructor', {
|
|
value: xmlHttpRequestWrapper,
|
|
});
|
|
overrideFunction(xmlHttpRequestProto, 'abort', function () {
|
|
var _this = this;
|
|
var args = [];
|
|
for (var _i = 0; _i < arguments.length; _i++) {
|
|
args[_i] = arguments[_i];
|
|
}
|
|
if (xhrSandbox.gettingSettingInProgress())
|
|
return void xhrSandbox.delayUntilGetSettings(function () { return _this.abort.apply(_this, args); });
|
|
nativeMethods.xhrAbort.apply(this, args);
|
|
xhrSandbox.emit(xhrSandbox.XHR_ERROR_EVENT, {
|
|
err: new Error('XHR aborted'),
|
|
xhr: this,
|
|
});
|
|
});
|
|
// NOTE: Redirect all requests to the Hammerhead proxy and ensure that requests don't
|
|
// violate Same Origin Policy.
|
|
overrideFunction(xmlHttpRequestProto, 'open', function () {
|
|
var _this = this;
|
|
var args = [];
|
|
for (var _i = 0; _i < arguments.length; _i++) {
|
|
args[_i] = arguments[_i];
|
|
}
|
|
var url = args[1];
|
|
if (getProxyUrl(url, {}, xhrSandbox.proxyless) === url) {
|
|
XhrSandbox.setRequestOptions(this, this.withCredentials, args);
|
|
return void nativeMethods.xhrOpen.apply(this, args);
|
|
}
|
|
if (xhrSandbox.gettingSettingInProgress())
|
|
return void xhrSandbox.delayUntilGetSettings(function () { return _this.open.apply(_this, args); });
|
|
url = typeof url === 'string' ? url : String(url);
|
|
args[1] = getAjaxProxyUrl(url, this.withCredentials ? Credentials.include : Credentials.sameOrigin, xhrSandbox.proxyless);
|
|
nativeMethods.xhrOpen.apply(this, args);
|
|
args[1] = url;
|
|
XhrSandbox.setRequestOptions(this, this.withCredentials, args);
|
|
});
|
|
overrideFunction(xmlHttpRequestProto, 'send', function () {
|
|
var _this = this;
|
|
var args = [];
|
|
for (var _i = 0; _i < arguments.length; _i++) {
|
|
args[_i] = arguments[_i];
|
|
}
|
|
if (xhrSandbox.gettingSettingInProgress())
|
|
return void xhrSandbox.delayUntilGetSettings(function () { return _this.send.apply(_this, args); });
|
|
var reqOpts = XhrSandbox.REQUESTS_OPTIONS.get(this);
|
|
if (reqOpts && reqOpts.withCredentials !== this.withCredentials)
|
|
XhrSandbox._reopenXhr(this, reqOpts, xhrSandbox.proxyless);
|
|
xhrSandbox.emit(xhrSandbox.BEFORE_XHR_SEND_EVENT, { xhr: this });
|
|
nativeMethods.xhrSend.apply(this, args);
|
|
// NOTE: For xhr with the sync mode
|
|
if (this.readyState === this.DONE)
|
|
emitXhrCompletedEvent.call(this);
|
|
syncCookieWithClientIfNecessary.call(this);
|
|
});
|
|
overrideFunction(xmlHttpRequestProto, 'setRequestHeader', function () {
|
|
var args = [];
|
|
for (var _i = 0; _i < arguments.length; _i++) {
|
|
args[_i] = arguments[_i];
|
|
}
|
|
if (isAuthorizationHeader(args[0]))
|
|
args[1] = addAuthorizationPrefix(args[1]);
|
|
nativeMethods.xhrSetRequestHeader.apply(this, args);
|
|
var reqOpts = XhrSandbox.REQUESTS_OPTIONS.get(this);
|
|
if (reqOpts)
|
|
reqOpts.headers.push([String(args[0]), String(args[1])]);
|
|
});
|
|
if (nativeMethods.xhrResponseURLGetter) {
|
|
overrideDescriptor(window.XMLHttpRequest.prototype, 'responseURL', {
|
|
getter: function () {
|
|
var nativeResponseURL = nativeMethods.xhrResponseURLGetter.call(this);
|
|
return xhrSandbox.proxyless ? nativeResponseURL : getDestinationUrl(nativeResponseURL);
|
|
},
|
|
});
|
|
}
|
|
overrideFunction(xmlHttpRequestProto, 'getResponseHeader', function () {
|
|
var args = [];
|
|
for (var _i = 0; _i < arguments.length; _i++) {
|
|
args[_i] = arguments[_i];
|
|
}
|
|
var value = nativeMethods.xhrGetResponseHeader.apply(this, args);
|
|
if (value && isAuthenticateHeader(args[0]))
|
|
value = removeAuthenticatePrefix(value);
|
|
return value;
|
|
});
|
|
overrideFunction(xmlHttpRequestProto, 'getAllResponseHeaders', function () {
|
|
var args = [];
|
|
for (var _i = 0; _i < arguments.length; _i++) {
|
|
args[_i] = arguments[_i];
|
|
}
|
|
var allHeaders = nativeMethods.xhrGetAllResponseHeaders.apply(this, args);
|
|
while (hasAuthenticatePrefix(allHeaders))
|
|
allHeaders = removeAuthenticatePrefix(allHeaders);
|
|
return allHeaders;
|
|
});
|
|
};
|
|
XhrSandbox.REQUESTS_OPTIONS = new WeakMap();
|
|
return XhrSandbox;
|
|
}(SandboxBaseWithDelayedSettings));
|
|
|
|
function getCredentialsMode(credentialsOpt) {
|
|
credentialsOpt = String(credentialsOpt).toLowerCase();
|
|
switch (credentialsOpt) {
|
|
case 'omit': return Credentials.omit;
|
|
case 'same-origin': return Credentials.sameOrigin;
|
|
case 'include': return Credentials.include;
|
|
default: return Credentials.unknown;
|
|
}
|
|
}
|
|
var DEFAULT_REQUEST_CREDENTIALS = getCredentialsMode(nativeMethods.Request && new nativeMethods.Request(location.toString()).credentials);
|
|
var FetchSandbox = /** @class */ (function (_super) {
|
|
__extends(FetchSandbox, _super);
|
|
function FetchSandbox(cookieSandbox, waitHammerheadSettings) {
|
|
var _this = _super.call(this, waitHammerheadSettings) || this;
|
|
_this.cookieSandbox = cookieSandbox;
|
|
_this.FETCH_REQUEST_SENT_EVENT = 'hammerhead|event|fetch-request-sent-event';
|
|
return _this;
|
|
}
|
|
FetchSandbox._removeAuthHeadersPrefix = function (name, value) {
|
|
if (isAuthorizationHeader(name))
|
|
return removeAuthorizationPrefix(value);
|
|
else if (isAuthenticateHeader(name))
|
|
return removeAuthenticatePrefix(value);
|
|
return value;
|
|
};
|
|
FetchSandbox._processInit = function (init) {
|
|
var headers = init.headers;
|
|
if (!headers)
|
|
return init;
|
|
if (!isFetchHeaders(headers)) {
|
|
headers = headers ? new nativeMethods.Headers(headers) : new nativeMethods.Headers();
|
|
init.headers = headers;
|
|
}
|
|
var authorizationValue = nativeMethods.headersGet.call(headers, BUILTIN_HEADERS.authorization);
|
|
var proxyAuthorizationValue = nativeMethods.headersGet.call(headers, BUILTIN_HEADERS.proxyAuthorization);
|
|
if (authorizationValue !== null && !hasAuthorizationPrefix(authorizationValue))
|
|
nativeMethods.headersSet.call(headers, BUILTIN_HEADERS.authorization, addAuthorizationPrefix(authorizationValue));
|
|
if (proxyAuthorizationValue !== null && !hasAuthorizationPrefix(proxyAuthorizationValue))
|
|
nativeMethods.headersSet.call(headers, BUILTIN_HEADERS.proxyAuthorization, addAuthorizationPrefix(proxyAuthorizationValue));
|
|
return init;
|
|
};
|
|
FetchSandbox._processArguments = function (args, proxyless) {
|
|
var input = args[0], init = args[1];
|
|
var inputIsString = typeof input === 'string';
|
|
var optsCredentials = getCredentialsMode(init && init.credentials);
|
|
if (!isFetchRequest(input)) {
|
|
var url = inputIsString ? input : String(input);
|
|
var credentials = optsCredentials === Credentials.unknown ? DEFAULT_REQUEST_CREDENTIALS : optsCredentials;
|
|
args[0] = getAjaxProxyUrl(url, credentials, proxyless);
|
|
args[1] = FetchSandbox._processInit(init || {});
|
|
}
|
|
else {
|
|
if (optsCredentials !== Credentials.unknown)
|
|
args[0] = getAjaxProxyUrl(input.url, optsCredentials);
|
|
if (init && init.headers && input.destination !== 'worker')
|
|
args[1] = FetchSandbox._processInit(init);
|
|
}
|
|
};
|
|
FetchSandbox._processHeaderEntry = function (entry, isOnlyValue) {
|
|
if (isOnlyValue === void 0) { isOnlyValue = false; }
|
|
if (entry.done)
|
|
return entry;
|
|
/* eslint-disable no-restricted-properties */
|
|
var processedValue = FetchSandbox._removeAuthHeadersPrefix(entry.value[0], entry.value[1]);
|
|
if (isOnlyValue)
|
|
entry.value = processedValue;
|
|
else
|
|
entry.value[1] = processedValue;
|
|
/* eslint-enable no-restricted-properties */
|
|
return entry;
|
|
};
|
|
FetchSandbox._entriesWrapper = function () {
|
|
var args = [];
|
|
for (var _i = 0; _i < arguments.length; _i++) {
|
|
args[_i] = arguments[_i];
|
|
}
|
|
var iterator = nativeMethods.headersEntries.apply(this, args);
|
|
var nativeNext = iterator.next;
|
|
iterator.next = function () { return FetchSandbox._processHeaderEntry(nativeNext.call(iterator)); };
|
|
return iterator;
|
|
};
|
|
FetchSandbox._valuesWrapper = function () {
|
|
var args = [];
|
|
for (var _i = 0; _i < arguments.length; _i++) {
|
|
args[_i] = arguments[_i];
|
|
}
|
|
var iterator = nativeMethods.headersEntries.apply(this, args);
|
|
var nativeNext = iterator.next;
|
|
iterator.next = function () { return FetchSandbox._processHeaderEntry(nativeNext.call(iterator), true); };
|
|
return iterator;
|
|
};
|
|
FetchSandbox.prototype.attach = function (window) {
|
|
_super.prototype.attach.call(this, window, window.document);
|
|
if (!nativeMethods.fetch)
|
|
return;
|
|
var sandbox = this;
|
|
if (!this.proxyless) {
|
|
overrideConstructor(window, 'Request', function () {
|
|
var args = [];
|
|
for (var _i = 0; _i < arguments.length; _i++) {
|
|
args[_i] = arguments[_i];
|
|
}
|
|
FetchSandbox._processArguments(args, sandbox.proxyless);
|
|
window.Headers.prototype.entries = window.Headers.prototype[Symbol.iterator] = nativeMethods.headersEntries;
|
|
var request = args.length === 1
|
|
? new nativeMethods.Request(args[0])
|
|
: new nativeMethods.Request(args[0], args[1]);
|
|
window.Headers.prototype.entries = window.Headers.prototype[Symbol.iterator] = FetchSandbox._entriesWrapper;
|
|
return request;
|
|
});
|
|
overrideDescriptor(window.Request.prototype, 'url', {
|
|
getter: function () {
|
|
var nativeRequestUrl = nativeMethods.requestUrlGetter.call(this);
|
|
return sandbox.proxyless ? nativeRequestUrl : getDestinationUrl(nativeRequestUrl);
|
|
},
|
|
});
|
|
overrideDescriptor(window.Request.prototype, 'referrer', {
|
|
getter: function () {
|
|
var nativeReferrer = nativeMethods.requestReferrerGetter.call(this);
|
|
return sandbox.proxyless ? nativeReferrer : getDestinationUrl(nativeReferrer);
|
|
},
|
|
});
|
|
overrideDescriptor(window.Response.prototype, 'url', {
|
|
getter: function () {
|
|
var nativeResponseUrl = nativeMethods.responseUrlGetter.call(this);
|
|
return sandbox.proxyless ? nativeResponseUrl : getDestinationUrl(nativeResponseUrl);
|
|
},
|
|
});
|
|
overrideFunction(window.Headers.prototype, 'entries', FetchSandbox._entriesWrapper);
|
|
overrideFunction(window.Headers.prototype, Symbol.iterator, FetchSandbox._entriesWrapper);
|
|
overrideFunction(window.Headers.prototype, 'values', FetchSandbox._valuesWrapper);
|
|
overrideFunction(window.Headers.prototype, 'forEach', function () {
|
|
var args = [];
|
|
for (var _i = 0; _i < arguments.length; _i++) {
|
|
args[_i] = arguments[_i];
|
|
}
|
|
var callback = args[0];
|
|
if (isFunction(callback)) {
|
|
args[0] = function (value, name, headers) {
|
|
value = FetchSandbox._removeAuthHeadersPrefix(name, value);
|
|
callback.call(this, value, name, headers);
|
|
};
|
|
}
|
|
return nativeMethods.headersForEach.apply(this, args);
|
|
});
|
|
overrideFunction(window.Headers.prototype, 'get', function () {
|
|
var args = [];
|
|
for (var _i = 0; _i < arguments.length; _i++) {
|
|
args[_i] = arguments[_i];
|
|
}
|
|
var value = nativeMethods.headersGet.apply(this, args);
|
|
return value && FetchSandbox._removeAuthHeadersPrefix(args[0], value);
|
|
});
|
|
overrideFunction(window.Headers.prototype, 'set', function () {
|
|
var args = [];
|
|
for (var _i = 0; _i < arguments.length; _i++) {
|
|
args[_i] = arguments[_i];
|
|
}
|
|
if (isAuthorizationHeader(args[0]))
|
|
args[1] = addAuthorizationPrefix(args[1]);
|
|
return nativeMethods.headersSet.apply(this, args);
|
|
});
|
|
}
|
|
overrideFunction(window, 'fetch', function () {
|
|
var _this = this;
|
|
var args = [];
|
|
for (var _i = 0; _i < arguments.length; _i++) {
|
|
args[_i] = arguments[_i];
|
|
}
|
|
if (!sandbox.proxyless && sandbox.gettingSettingInProgress())
|
|
return sandbox.delayUntilGetSettings(function () { return _this.fetch.apply(_this, args); });
|
|
// NOTE: Safari processed the empty `fetch()` request without `Promise` rejection (GH-1613)
|
|
if (!args.length && !isSafari)
|
|
return nativeMethods.fetch.apply(this, args);
|
|
if (sandbox.proxyless) {
|
|
var fetchPromise_1 = nativeMethods.fetch.apply(this, args);
|
|
sandbox.emit(sandbox.FETCH_REQUEST_SENT_EVENT, fetchPromise_1);
|
|
return fetchPromise_1;
|
|
}
|
|
try {
|
|
FetchSandbox._processArguments(args, sandbox.proxyless);
|
|
}
|
|
catch (e) {
|
|
return nativeMethods.promiseReject.call(sandbox.window.Promise, e);
|
|
}
|
|
window.Headers.prototype.entries = window.Headers.prototype[Symbol.iterator] = nativeMethods.headersEntries;
|
|
var fetchPromise = nativeMethods.fetch.apply(this, args);
|
|
window.Headers.prototype.entries = window.Headers.prototype[Symbol.iterator] = FetchSandbox._entriesWrapper;
|
|
sandbox.emit(sandbox.FETCH_REQUEST_SENT_EVENT, fetchPromise);
|
|
return nativeMethods.promiseThen.call(fetchPromise, function (response) {
|
|
sandbox.cookieSandbox.syncCookie();
|
|
return response;
|
|
});
|
|
});
|
|
};
|
|
return FetchSandbox;
|
|
}(SandboxBaseWithDelayedSettings));
|
|
|
|
function stopPropagation(ev) {
|
|
if (ev.stopImmediatePropagation)
|
|
ev.stopImmediatePropagation();
|
|
else if (ev.stopPropagation)
|
|
ev.stopPropagation();
|
|
ev.cancelBubble = true;
|
|
}
|
|
!!(nativeMethods.WindowPointerEvent || nativeMethods.WindowMSPointerEvent);
|
|
|
|
var SET_SERVICE_WORKER_SETTINGS = 'hammerhead|set-service-worker-settings';
|
|
|
|
// -------------------------------------------------------------
|
|
// WARNING: this file is used by both the client and the server.
|
|
// Do not use any browser or node-specific API!
|
|
// -------------------------------------------------------------
|
|
var INSTRUCTION = {
|
|
getLocation: '__get$Loc',
|
|
setLocation: '__set$Loc',
|
|
getProperty: '__get$',
|
|
setProperty: '__set$',
|
|
callMethod: '__call$',
|
|
processScript: '__proc$Script',
|
|
processHtml: '__proc$Html',
|
|
getEval: '__get$Eval',
|
|
getPostMessage: '__get$PostMessage',
|
|
getProxyUrl: '__get$ProxyUrl',
|
|
restArray: '__rest$Array',
|
|
arrayFrom: '__arrayFrom$',
|
|
restObject: '__rest$Object',
|
|
swScopeHeaderValue: '__swScopeHeaderValue',
|
|
getWorkerSettings: '__getWorkerSettings$',
|
|
};
|
|
|
|
/*eslint-disable*/
|
|
var swFetchCheckSettings = {
|
|
protocol: '',
|
|
host: '',
|
|
scope: ''
|
|
};
|
|
function isCorrectScope(parsedUrl) {
|
|
return parsedUrl.protocol === swFetchCheckSettings.protocol &&
|
|
parsedUrl.host === swFetchCheckSettings.host &&
|
|
parsedUrl.partAfterHost.startsWith(swFetchCheckSettings.scope);
|
|
}
|
|
function overrideFetchEvent() {
|
|
var waitSettingsPromise = new Promise(function (resolve, reject) {
|
|
nativeMethods.windowAddEventListener.call(self, 'message', function onMessage(e /*ExtendableMessageEvent*/) {
|
|
var data = e.data;
|
|
if (data.cmd !== SET_SERVICE_WORKER_SETTINGS)
|
|
return;
|
|
var swScopeHeaderExists = self[INSTRUCTION.swScopeHeaderValue] !== void 0;
|
|
var currentScope = swScopeHeaderExists ? self[INSTRUCTION.swScopeHeaderValue] : data.currentScope;
|
|
var scope = data.optsScope;
|
|
if (!scope)
|
|
scope = currentScope;
|
|
else if (!scope.startsWith(currentScope)) {
|
|
// @ts-ignore
|
|
self.registration.unregister();
|
|
var errorMessage = "The path of the provided scope ('".concat(data.optsScope, "') is not under the max ") +
|
|
"scope allowed (".concat(swScopeHeaderExists ? 'set by Service-Worker-Allowed: ' : '', "'") +
|
|
"".concat(currentScope, "'). Adjust the scope, move the Service Worker script, ") +
|
|
'or use the Service-Worker-Allowed HTTP header to allow the scope.';
|
|
e.ports[0].postMessage({ error: errorMessage });
|
|
reject(new Error(errorMessage));
|
|
return;
|
|
}
|
|
e.ports[0].postMessage({});
|
|
swFetchCheckSettings.protocol = data.protocol;
|
|
swFetchCheckSettings.host = data.host;
|
|
swFetchCheckSettings.scope = scope;
|
|
nativeMethods.windowRemoveEventListener.call(self, 'message', onMessage);
|
|
stopPropagation(e);
|
|
waitSettingsPromise = null;
|
|
resolve();
|
|
});
|
|
});
|
|
self.addEventListener('install', function (e /*InstallEvent*/) { return e.waitUntil(waitSettingsPromise); });
|
|
nativeMethods.windowAddEventListener.call(self, 'fetch', function (e /*FetchEvent*/) {
|
|
var request = e.request;
|
|
var proxyUrl = nativeMethods.requestUrlGetter.call(request);
|
|
var parsedProxyUrl = parseProxyUrl(proxyUrl);
|
|
var isInternalRequest = !parsedProxyUrl;
|
|
if (!isInternalRequest) {
|
|
// @ts-ignore Chrome has a non-standard the "iframe" destination
|
|
var isPage = request.destination === 'document' || request.destination === 'iframe';
|
|
if (isPage) {
|
|
if (isCorrectScope(parsedProxyUrl.destResourceInfo))
|
|
return;
|
|
}
|
|
else {
|
|
var proxyReferrer = nativeMethods.requestReferrerGetter.call(request);
|
|
var parsedProxyReferrer = parseProxyUrl(proxyReferrer);
|
|
if (parsedProxyReferrer && isCorrectScope(parsedProxyReferrer.destResourceInfo))
|
|
return;
|
|
}
|
|
}
|
|
// NOTE: This request should not have gotten into this service worker
|
|
e.respondWith(nativeMethods.fetch.call(self, request));
|
|
stopPropagation(e);
|
|
});
|
|
}
|
|
|
|
function noop () {
|
|
// NOTE: empty function
|
|
}
|
|
|
|
var WorkerHammerhead = /** @class */ (function () {
|
|
function WorkerHammerhead() {
|
|
var parsedLocation = parseProxyUrl$1(location.toString());
|
|
var cookieSandboxMock = { syncCookie: noop };
|
|
// NOTE: the blob location case
|
|
if (!parsedLocation)
|
|
this._getBlobSettings();
|
|
else
|
|
WorkerHammerhead._setProxySettings(parsedLocation.sessionId, parsedLocation.windowId);
|
|
this.fetch = new FetchSandbox(cookieSandboxMock);
|
|
this.fetch.attach(self);
|
|
WorkerHammerhead._overrideImportScripts();
|
|
if (!globalContextInfo.isServiceWorker) {
|
|
this.xhr = new XhrSandbox(cookieSandboxMock);
|
|
this.xhr.attach(self);
|
|
}
|
|
else
|
|
overrideFetchEvent();
|
|
}
|
|
WorkerHammerhead._setProxySettings = function (sessionId, windowId) {
|
|
var currentSettings = settings.get();
|
|
currentSettings.sessionId = sessionId;
|
|
currentSettings.windowId = windowId;
|
|
settings.set(currentSettings);
|
|
};
|
|
WorkerHammerhead._overrideImportScripts = function () {
|
|
// @ts-ignore
|
|
overrideFunction(self, 'importScripts', function () {
|
|
var urls = [];
|
|
for (var _i = 0; _i < arguments.length; _i++) {
|
|
urls[_i] = arguments[_i];
|
|
}
|
|
for (var i = 0; i < urls.length; i++)
|
|
urls[i] = getProxyUrl(urls[i], { resourceType: stringifyResourceType({ isScript: true }) });
|
|
return nativeMethods.importScripts.apply(self, urls);
|
|
});
|
|
};
|
|
WorkerHammerhead.prototype._getBlobSettings = function () {
|
|
var data = self[INSTRUCTION.getWorkerSettings]();
|
|
WorkerHammerhead._setProxySettings(data.sessionId, data.windowId);
|
|
forceLocation(data.origin); // eslint-disable-line no-restricted-properties
|
|
};
|
|
return WorkerHammerhead;
|
|
}());
|
|
var index = new WorkerHammerhead();
|
|
|
|
return index;
|
|
|
|
})();
|