1
0
mirror of https://github.com/webrecorder/pywb.git synced 2025-03-20 18:59:11 +01:00
pywb/wombat/test/helpers/initChrome.js

169 lines
4.5 KiB
JavaScript
Raw Normal View History

wombat overhaul! fixes #449 (#451) wombat: - I: function overrides applied by wombat now better appear to be the original new function name same as originals when possible - I: WombatLocation now looks and behaves more like the original Location interface - I: The custom storage class now looks and behaves more like the original Storage - I: SVG image rewriting has been improved: both the href and xlink:href deprecated since SVG2 now rewritten always - I: document.open now handles the case of creation of a new window - I: Request object rewriting of the readonly href property is now correctly handled - I: EventTarget.addEventListener, removeEventListener overrides now preserve the original this argument of the wrapped listener - A: document.close override to ensure wombat is initialized after write or writeln usage - A: reconstruction of <doctype...> in rewriteHTMLComplete IFF it was included in the original string of HTML - A: document.body setter override to ensure rewriting of the new body or frameset - A: Attr.[value, nodeValue, textContent] added setter override to perform URL rewrites - A: SVGElements rewriting of the filter, style, xlink:href, href, and src attributes - A: HTMLTrackElement rewriting of the src attribute of the - A: HTMLQuoteElement and HTMLModElement rewriting of the cite attribute - A: Worklet.addModule: Loads JS module specified by a URL. - A: HTMLHyperlinkElementUtils overrides to the areaelement - A: ShadowRootoverrides to: innerHTML even though inherites from DocumentFragement and Node it still has innerHTML getter setter. - A: ShadowRoot, Element, DocumentFragment append, prepend: adds strings of HTML or a new Node inherited from ParentNode - A: StylePropertyMap override: New way to access and set CSS properties. - A: Response.redirecthttps rewriting of the URL argument. - A: UIEvent, MouseEvent, TouchEvent, KeyboardEvent, WheelEvent, InputEvent, and CompositionEven constructor and init{even-name} overrides in order to ensure that wombats JS Proxy usage does not affect their defined behaviors - A: XSLTProcessor override to ensure its usage is not affected by wombats JS Proxy usage. - A: navigator.unregisterProtocolHandler: Same override as existing navigator.registerProtocolHandler but from the inverse operation - A: PresentationRequest: Constructor takes a URL or an array of URLs. - A: EventSource and WebSocket override in order to ensure that they do not cause live leaks - A: overrides for the child node interface - Fix: autofetch worker creatation of the backing worker when it is operating within an execution context with a null origin tests: - A: 559 tests specific to wombat and client side rewritting pywb: - Fix: a few broken tests due to iana.org requiring a user agent in its requests rewrite: - introduced a new JSWorkerRewriter class in order to support rewriting via wombat workers in the context of all supported worker variants via - ensured rewriter app correctly sets the static prefix ci: - Modified travis.yml to specifically enumerate jobs documentation: - Documented new wombat, wombat proxy moded, wombat workers auto-fetch: - switched to mutation observer when in proxy mode so that the behaviors can operate in tandem with the autofetcher
2019-05-15 14:42:51 -04:00
const cp = require('child_process');
const path = require('path');
const os = require('os');
const fs = require('fs-extra');
const readline = require('readline');
const chromeFinder = require('chrome-launcher/dist/chrome-finder');
const criHelper = require('chrome-remote-interface-extra/lib/helper');
const CHROME_PROFILE_PATH = path.join(os.tmpdir(), 'temp_chrome_profile-');
const winPos = !process.env.NO_MOVE_WINDOW ? '--window-position=2000,0' : '';
const chromeArgs = userDataDir => [
'--enable-automation',
'--force-color-profile=srgb',
'--remote-debugging-port=9222',
'--disable-background-networking',
'--disable-background-timer-throttling',
'--disable-renderer-backgrounding',
'--disable-backgrounding-occluded-windows',
'--disable-ipc-flooding-protection',
'--enable-features=NetworkService,NetworkServiceInProcess',
'--disable-client-side-phishing-detection',
'--disable-default-apps',
'--disable-extensions',
'--disable-popup-blocking',
'--disable-hang-monitor',
'--disable-prompt-on-repost',
'--disable-sync',
'--disable-domain-reliability',
'--disable-infobars',
'--disable-features=site-per-process,TranslateUI',
'--disable-breakpad',
'--disable-backing-store-limit',
'--metrics-recording-only',
'--no-first-run',
'--safebrowsing-disable-auto-update',
'--password-store=basic',
'--use-mock-keychain',
'--mute-audio',
'--autoplay-policy=no-user-gesture-required',
`--user-data-dir=${userDataDir}`,
winPos,
'about:blank'
];
const preferredExes = {
linux: [
'google-chrome-unstable',
'google-chrome-beta',
'google-chrome-stable'
],
darwin: ['Chrome Canary', 'Chrome'],
win32: []
};
function findChrome() {
const findingFn = chromeFinder[process.platform];
if (findingFn == null) {
throw new Error(
`Can not find chrome exe, unsupported platform - ${process.platform}`
);
}
const exes = findingFn();
const preferred = preferredExes[process.platform] || [];
let exe;
for (let i = 0; i < preferred.length; i++) {
exe = exes.find(anExe => anExe.includes(preferred[i]));
if (exe) return exe;
}
return exes[0];
}
/**
*
* @return {Promise<{chromeProcess: ChildProcess, killChrome: function(): void}>}
*/
async function initChrome() {
const executable = findChrome();
const userDataDir = await fs.mkdtemp(CHROME_PROFILE_PATH);
const chromeArguments = chromeArgs(userDataDir);
const chromeProcess = cp.spawn(executable, chromeArguments, {
stdio: ['ignore', 'ignore', 'pipe'],
env: process.env,
detached: process.platform !== 'win32'
});
const maybeRemoveUDataDir = () => {
try {
fs.removeSync(userDataDir);
} catch (e) {}
};
let killed = false;
const killChrome = () => {
if (killed) {
return;
}
killed = true;
chromeProcess.kill('SIGKILL');
// process.kill(-chromeProcess.pid, 'SIGKILL')
maybeRemoveUDataDir();
};
process.on('exit', killChrome);
chromeProcess.once('exit', maybeRemoveUDataDir);
process.on('SIGINT', () => {
killChrome();
process.exit(130);
});
process.once('SIGTERM', killChrome);
process.once('SIGHUP', killChrome);
await waitForWSEndpoint(chromeProcess, 15 * 1000);
return { chromeProcess, killChrome };
}
module.exports = initChrome;
// module.exports = initChrome
function waitForWSEndpoint(chromeProcess, timeout) {
return new Promise((resolve, reject) => {
const rl = readline.createInterface({ input: chromeProcess.stderr });
let stderr = '';
const listeners = [
criHelper.helper.addEventListener(rl, 'line', onLine),
criHelper.helper.addEventListener(rl, 'close', onClose),
criHelper.helper.addEventListener(chromeProcess, 'exit', onClose),
criHelper.helper.addEventListener(chromeProcess, 'error', onClose)
];
const timeoutId = timeout ? setTimeout(onTimeout, timeout) : 0;
function onClose() {
cleanup();
reject(new Error(['Failed to launch chrome!', stderr].join('\n')));
}
function onTimeout() {
cleanup();
reject(
new Error(
`Timed out after ${timeout} ms while trying to connect to Chrome!`
)
);
}
/**
* @param {string} line
*/
function onLine(line) {
stderr += line + '\n';
const match = line.match(/^DevTools listening on (ws:\/\/.*)$/);
if (!match) {
return;
}
cleanup();
resolve(match[1]);
}
function cleanup() {
if (timeoutId) {
clearTimeout(timeoutId);
}
criHelper.helper.removeEventListeners(listeners);
rl.close();
}
});
}