Innovenergy_trunk/frontend/node_modules/testcafe-hammerhead/lib/processing/resources/page.js

238 lines
12 KiB
JavaScript
Raw Normal View History

"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const util_1 = __importDefault(require("util"));
const parse5_1 = __importDefault(require("parse5"));
const class_name_1 = __importDefault(require("../../shadow-ui/class-name"));
const dom_1 = __importDefault(require("../dom"));
const parse5_dom_adapter_1 = __importDefault(require("../dom/parse5-dom-adapter"));
const resource_processor_base_1 = __importDefault(require("./resource-processor-base"));
const parse5Utils = __importStar(require("../../utils/parse5"));
const get_bom_1 = __importDefault(require("../../utils/get-bom"));
const get_storage_key_1 = __importDefault(require("../../utils/get-storage-key"));
const self_removing_scripts_1 = __importDefault(require("../../utils/self-removing-scripts"));
const service_routes_1 = __importDefault(require("../../proxy/service-routes"));
const json_1 = require("../../utils/json");
const PARSED_BODY_CREATED_EVENT_SCRIPT = parse5_1.default.parseFragment(self_removing_scripts_1.default.onBodyCreated).childNodes[0];
const PARSED_ORIGIN_FIRST_TITLE_ELEMENT_LOADED_SCRIPT = parse5_1.default.parseFragment(self_removing_scripts_1.default.onOriginFirstTitleLoaded).childNodes[0];
const PARSED_INIT_SCRIPT_FOR_IFRAME_TEMPLATE = parse5_1.default.parseFragment(self_removing_scripts_1.default.iframeInit).childNodes[0];
class PageProcessor extends resource_processor_base_1.default {
constructor() {
super();
this.RESTART_PROCESSING = Symbol();
}
static _createShadowUIStyleLinkNode(url) {
return parse5Utils.createElement('link', [
{ name: 'rel', value: 'stylesheet' },
{ name: 'type', value: 'text/css' },
{ name: 'class', value: class_name_1.default.uiStylesheet },
{ name: 'href', value: url },
]);
}
static _createShadowUIScriptWithUrlNode(url) {
return parse5Utils.createElement('script', [
{ name: 'type', value: 'text/javascript' },
{ name: 'class', value: class_name_1.default.script },
{ name: 'charset', value: 'UTF-8' },
{ name: 'src', value: url },
]);
}
static _createShadowUIScriptWithContentNode(content) {
const scriptAsContentElement = parse5Utils.createElement('script', [
{ name: 'type', value: 'text/javascript' },
{ name: 'class', value: class_name_1.default.script },
{ name: 'charset', value: 'UTF-8' },
]);
scriptAsContentElement.childNodes = [parse5Utils.createTextNode(content, scriptAsContentElement)];
return scriptAsContentElement;
}
static _createRestoreStoragesScript(storageKey, storages) {
const parsedDocumentFragment = parse5_1.default.parseFragment(util_1.default.format(self_removing_scripts_1.default.restoreStorages, storageKey, (0, json_1.stringify)(storages.localStorage), storageKey, (0, json_1.stringify)(storages.sessionStorage)));
return parsedDocumentFragment.childNodes[0];
}
static _getPageProcessingOptions(ctx, urlReplacer) {
return {
crossDomainProxyPort: ctx.serverInfo.crossDomainPort,
isIframe: ctx.isIframe,
stylesheets: ctx.getInjectableStyles(),
scripts: ctx.getInjectableScripts(),
urlReplacer: urlReplacer,
isIframeWithImageSrc: ctx.contentInfo && ctx.contentInfo.isIframeWithImageSrc,
};
}
static _getPageMetas(metaEls, domAdapter) {
const metas = [];
for (let i = 0; i < metaEls.length; i++) {
metas.push({
httpEquiv: domAdapter.getAttr(metaEls[i], 'http-equiv'),
content: domAdapter.getAttr(metaEls[i], 'content'),
charset: domAdapter.getAttr(metaEls[i], 'charset'),
});
}
return metas;
}
static _addPageResources(head, processingOptions, options) {
const injectedResources = [];
if (processingOptions.storages && options) {
const storages = processingOptions.storages;
const script = PageProcessor._createRestoreStoragesScript((0, get_storage_key_1.default)(options.sessionId, options.host), storages);
injectedResources.push(script);
}
if (processingOptions.stylesheets) {
processingOptions.stylesheets.forEach(stylesheetUrl => {
injectedResources.unshift(PageProcessor._createShadowUIStyleLinkNode(stylesheetUrl));
});
}
if (processingOptions.scripts) {
processingOptions.scripts.forEach(scriptUrl => {
injectedResources.push(PageProcessor._createShadowUIScriptWithUrlNode(scriptUrl));
});
}
if (processingOptions.embeddedScripts) {
processingOptions.embeddedScripts.forEach(script => {
injectedResources.push(PageProcessor._createShadowUIScriptWithContentNode(script));
});
}
if (processingOptions.userScripts) {
processingOptions.userScripts.forEach(script => {
injectedResources.push(PageProcessor._createShadowUIScriptWithUrlNode(script));
});
}
for (let i = injectedResources.length - 1; i > -1; i--)
parse5Utils.insertBeforeFirstScript(injectedResources[i], head);
return injectedResources;
}
static _getTaskScriptNodeIndex(head, ctx) {
const taskScriptUrls = [
ctx.resolveInjectableUrl(service_routes_1.default.task),
ctx.resolveInjectableUrl(service_routes_1.default.iframeTask),
];
return parse5Utils.findNodeIndex(head, node => {
return node.tagName === 'script' &&
!!node.attrs.find(attr => attr.name === 'class' && attr.value === class_name_1.default.script) &&
!!node.attrs.find(attr => attr.name === 'src' && taskScriptUrls.includes(attr.value));
});
}
/**
* Inject the service script after the first title element
* or after injected resources,
* if they are placed right after the <title> tag
**/
static _addPageOriginFirstTitleParsedScript(head, ctx) {
const firstTitleNodeIndex = parse5Utils.findNodeIndex(head, node => node.tagName === 'title');
if (firstTitleNodeIndex === -1)
return;
const taskScriptNodeIndex = PageProcessor._getTaskScriptNodeIndex(head, ctx);
const insertIndex = taskScriptNodeIndex > firstTitleNodeIndex
? taskScriptNodeIndex + 1
: firstTitleNodeIndex + 1;
parse5Utils.appendNode(PARSED_ORIGIN_FIRST_TITLE_ELEMENT_LOADED_SCRIPT, head, insertIndex);
}
static _addCharsetInfo(head, charset) {
parse5Utils.unshiftElement(parse5Utils.createElement('meta', [
{ name: 'class', value: class_name_1.default.charset },
{ name: 'charset', value: charset },
]), head);
}
static _changeMetas(metas, domAdapter) {
if (metas) {
metas.forEach(meta => {
// TODO: Figure out how to emulate the tag behavior.
if (domAdapter.getAttr(meta, 'name') === 'referrer')
parse5Utils.setAttr(meta, 'content', 'unsafe-url');
});
}
}
static _prepareHtml(html, processingOpts) {
if (processingOpts && processingOpts.iframeImageSrc)
return `<html><body><img src="${processingOpts.iframeImageSrc}" /></body></html>`;
return html;
}
_addRestoreStoragesScript(ctx, head) {
const storageKey = (0, get_storage_key_1.default)(ctx.session.id, ctx.dest.host);
const restoreStoragesScript = PageProcessor._createRestoreStoragesScript(storageKey, ctx.restoringStorages);
parse5Utils.insertBeforeFirstScript(restoreStoragesScript, head);
}
static _addBodyCreatedEventScript(body) {
parse5Utils.unshiftElement(PARSED_BODY_CREATED_EVENT_SCRIPT, body);
}
shouldProcessResource(ctx) {
// NOTE: In some cases, Firefox sends the default accept header for the script.
// We should not try to process it as a page in this case.
return (ctx.isPage || ctx.contentInfo.isIframeWithImageSrc) && !ctx.contentInfo.isScript &&
!ctx.contentInfo.isFileDownload;
}
processResource(html, ctx, charset, urlReplacer, isSrcdoc = false) {
const processingOpts = PageProcessor._getPageProcessingOptions(ctx, urlReplacer);
const bom = (0, get_bom_1.default)(html);
if (isSrcdoc)
processingOpts.isIframe = true;
html = bom ? html.replace(bom, '') : html;
PageProcessor._prepareHtml(html, processingOpts);
const root = parse5_1.default.parse(html);
const domAdapter = new parse5_dom_adapter_1.default(processingOpts.isIframe, ctx, charset, urlReplacer);
const elements = parse5Utils.findElementsByTagNames(root, ['base', 'meta', 'head', 'body', 'frameset']);
const base = elements.base ? elements.base[0] : null;
const baseUrl = base ? domAdapter.getAttr(base, 'href') : '';
const metas = elements.meta;
const head = elements.head[0];
const body = elements.body ? elements.body[0] : elements.frameset[0];
if (!isSrcdoc && metas && charset.fromMeta(PageProcessor._getPageMetas(metas, domAdapter)))
return this.RESTART_PROCESSING;
const domProcessor = new dom_1.default(domAdapter);
const replacer = (resourceUrl, resourceType, charsetAttrValue, isCrossDomain = false, isUrlsSet = false) => urlReplacer(resourceUrl, resourceType, charsetAttrValue, baseUrl, isCrossDomain, isUrlsSet);
domProcessor.forceProxySrcForImage = ctx.session.requestHookEventProvider.hasRequestEventListeners();
domProcessor.allowMultipleWindows = ctx.session.options.allowMultipleWindows;
parse5Utils.walkElements(root, el => domProcessor.processElement(el, replacer));
if (isSrcdoc)
parse5Utils.unshiftElement(PARSED_INIT_SCRIPT_FOR_IFRAME_TEMPLATE, head);
else if (!ctx.isHtmlImport) {
PageProcessor._addPageResources(head, processingOpts);
PageProcessor._addPageOriginFirstTitleParsedScript(head, ctx);
PageProcessor._addBodyCreatedEventScript(body);
if (ctx.restoringStorages && !processingOpts.isIframe)
this._addRestoreStoragesScript(ctx, head);
}
PageProcessor._changeMetas(metas, domAdapter);
PageProcessor._addCharsetInfo(head, charset.get());
return (bom || '') + parse5_1.default.serialize(root);
}
// NOTE: API for new implementation without request pipeline
injectResources(html, resources, options) {
const root = parse5_1.default.parse(html);
const elements = parse5Utils.findElementsByTagNames(root, ['head', 'body']);
const head = elements.head[0];
const body = elements.body[0];
PageProcessor._addPageResources(head, resources, options);
PageProcessor._addBodyCreatedEventScript(body);
return parse5_1.default.serialize(root);
}
}
exports.default = new PageProcessor();module.exports = exports.default;