????
Current Path : C:/inetpub/vhost/sdoc.nextform.vn/api/bin/.playwright/package/lib/server/chromium/ |
Current File : C:/inetpub/vhost/sdoc.nextform.vn/api/bin/.playwright/package/lib/server/chromium/crBrowser.js |
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.CRBrowserContext = exports.CRBrowser = void 0; var _browser = require("../browser"); var _browserContext = require("../browserContext"); var _utils = require("../../utils"); var network = _interopRequireWildcard(require("../network")); var _page = require("../page"); var _frames = require("../frames"); var _crConnection = require("./crConnection"); var _crPage = require("./crPage"); var _crProtocolHelper = require("./crProtocolHelper"); var _crServiceWorker = require("./crServiceWorker"); function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } /** * Copyright 2017 Google Inc. All rights reserved. * Modifications copyright (c) Microsoft Corporation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ class CRBrowser extends _browser.Browser { static async connect(transport, options, devtools) { // Make a copy in case we need to update `headful` property below. options = { ...options }; const connection = new _crConnection.CRConnection(transport, options.protocolLogger, options.browserLogsCollector); const browser = new CRBrowser(connection, options); browser._devtools = devtools; const session = connection.rootSession; if (options.__testHookOnConnectToBrowser) await options.__testHookOnConnectToBrowser(); const version = await session.send('Browser.getVersion'); browser._version = version.product.substring(version.product.indexOf('/') + 1); browser._userAgent = version.userAgent; // We don't trust the option as it may lie in case of connectOverCDP where remote browser // may have been launched with different options. browser.options.headful = !version.userAgent.includes('Headless'); if (!options.persistent) { await session.send('Target.setAutoAttach', { autoAttach: true, waitForDebuggerOnStart: true, flatten: true }); return browser; } browser._defaultContext = new CRBrowserContext(browser, undefined, options.persistent); await Promise.all([session.send('Target.setAutoAttach', { autoAttach: true, waitForDebuggerOnStart: true, flatten: true }).then(async () => { // Target.setAutoAttach has a bug where it does not wait for new Targets being attached. // However making a dummy call afterwards fixes this. // This can be removed after https://chromium-review.googlesource.com/c/chromium/src/+/2885888 lands in stable. await session.send('Target.getTargetInfo'); }), browser._defaultContext._initialize()]); await browser._waitForAllPagesToBeInitialized(); return browser; } constructor(connection, options) { super(options); this._connection = void 0; this._session = void 0; this._clientRootSessionPromise = null; this._contexts = new Map(); this._crPages = new Map(); this._backgroundPages = new Map(); this._serviceWorkers = new Map(); this._devtools = void 0; this._version = ''; this._tracingRecording = false; this._tracingPath = ''; this._tracingClient = void 0; this._userAgent = ''; this._connection = connection; this._session = this._connection.rootSession; this._connection.on(_crConnection.ConnectionEvents.Disconnected, () => this._didClose()); this._session.on('Target.attachedToTarget', this._onAttachedToTarget.bind(this)); this._session.on('Target.detachedFromTarget', this._onDetachedFromTarget.bind(this)); this._session.on('Browser.downloadWillBegin', this._onDownloadWillBegin.bind(this)); this._session.on('Browser.downloadProgress', this._onDownloadProgress.bind(this)); } async doCreateNewContext(options) { let proxyBypassList = undefined; if (options.proxy) { if (process.env.PLAYWRIGHT_DISABLE_FORCED_CHROMIUM_PROXIED_LOOPBACK) proxyBypassList = options.proxy.bypass;else proxyBypassList = '<-loopback>' + (options.proxy.bypass ? `,${options.proxy.bypass}` : ''); } const { browserContextId } = await this._session.send('Target.createBrowserContext', { disposeOnDetach: true, proxyServer: options.proxy ? options.proxy.server : undefined, proxyBypassList }); const context = new CRBrowserContext(this, browserContextId, options); await context._initialize(); this._contexts.set(browserContextId, context); return context; } contexts() { return Array.from(this._contexts.values()); } version() { return this._version; } userAgent() { return this._userAgent; } _platform() { if (this._userAgent.includes('Windows')) return 'win'; if (this._userAgent.includes('Macintosh')) return 'mac'; return 'linux'; } isClank() { return this.options.name === 'clank'; } async _waitForAllPagesToBeInitialized() { await Promise.all([...this._crPages.values()].map(page => page.pageOrError())); } _onAttachedToTarget({ targetInfo, sessionId, waitingForDebugger }) { if (targetInfo.type === 'browser') return; const session = this._connection.session(sessionId); (0, _utils.assert)(targetInfo.browserContextId, 'targetInfo: ' + JSON.stringify(targetInfo, null, 2)); let context = this._contexts.get(targetInfo.browserContextId) || null; if (!context) { // TODO: auto attach only to pages from our contexts. // assert(this._defaultContext); context = this._defaultContext; } if (targetInfo.type === 'other' && targetInfo.url.startsWith('devtools://devtools') && this._devtools) { this._devtools.install(session); return; } const treatOtherAsPage = targetInfo.type === 'other' && process.env.PW_CHROMIUM_ATTACH_TO_OTHER; if (!context || targetInfo.type === 'other' && !treatOtherAsPage) { if (waitingForDebugger) { // Ideally, detaching should resume any target, but there is a bug in the backend. session._sendMayFail('Runtime.runIfWaitingForDebugger').then(() => { this._session._sendMayFail('Target.detachFromTarget', { sessionId }); }); } return; } (0, _utils.assert)(!this._crPages.has(targetInfo.targetId), 'Duplicate target ' + targetInfo.targetId); (0, _utils.assert)(!this._backgroundPages.has(targetInfo.targetId), 'Duplicate target ' + targetInfo.targetId); (0, _utils.assert)(!this._serviceWorkers.has(targetInfo.targetId), 'Duplicate target ' + targetInfo.targetId); if (targetInfo.type === 'background_page') { const backgroundPage = new _crPage.CRPage(session, targetInfo.targetId, context, null, { hasUIWindow: false, isBackgroundPage: true }); this._backgroundPages.set(targetInfo.targetId, backgroundPage); return; } if (targetInfo.type === 'page' || treatOtherAsPage) { const opener = targetInfo.openerId ? this._crPages.get(targetInfo.openerId) || null : null; const crPage = new _crPage.CRPage(session, targetInfo.targetId, context, opener, { hasUIWindow: targetInfo.type === 'page', isBackgroundPage: false }); this._crPages.set(targetInfo.targetId, crPage); return; } if (targetInfo.type === 'service_worker') { const serviceWorker = new _crServiceWorker.CRServiceWorker(context, session, targetInfo.url); this._serviceWorkers.set(targetInfo.targetId, serviceWorker); context.emit(CRBrowserContext.CREvents.ServiceWorker, serviceWorker); return; } // Detach from any targets we are not interested in, to avoid side-effects. // // One example of a side effect: upon shared worker restart, we receive // Inspector.targetReloadedAfterCrash and backend waits for Runtime.runIfWaitingForDebugger // from any attached client. If we do not resume, shared worker will stall. // // Ideally, detaching should resume any target, but there is a bug in the backend, // so we must Runtime.runIfWaitingForDebugger first. session._sendMayFail('Runtime.runIfWaitingForDebugger').then(() => { this._session._sendMayFail('Target.detachFromTarget', { sessionId }); }); } _onDetachedFromTarget(payload) { const targetId = payload.targetId; const crPage = this._crPages.get(targetId); if (crPage) { this._crPages.delete(targetId); crPage.didClose(); return; } const backgroundPage = this._backgroundPages.get(targetId); if (backgroundPage) { this._backgroundPages.delete(targetId); backgroundPage.didClose(); return; } const serviceWorker = this._serviceWorkers.get(targetId); if (serviceWorker) { this._serviceWorkers.delete(targetId); serviceWorker.didClose(); return; } } _findOwningPage(frameId) { for (const crPage of this._crPages.values()) { const frame = crPage._page._frameManager.frame(frameId); if (frame) return crPage; } return null; } _onDownloadWillBegin(payload) { const page = this._findOwningPage(payload.frameId); (0, _utils.assert)(page, 'Download started in unknown page: ' + JSON.stringify(payload)); page.willBeginDownload(); let originPage = page._initializedPage; // If it's a new window download, report it on the opener page. if (!originPage && page._opener) originPage = page._opener._initializedPage; if (!originPage) return; this._downloadCreated(originPage, payload.guid, payload.url, payload.suggestedFilename); } _onDownloadProgress(payload) { if (payload.state === 'completed') this._downloadFinished(payload.guid, ''); if (payload.state === 'canceled') this._downloadFinished(payload.guid, 'canceled'); } async _closePage(crPage) { await this._session.send('Target.closeTarget', { targetId: crPage._targetId }); } async newBrowserCDPSession() { return await this._connection.createBrowserSession(); } async startTracing(page, options = {}) { (0, _utils.assert)(!this._tracingRecording, 'Cannot start recording trace while already recording trace.'); this._tracingClient = page ? page._delegate._mainFrameSession._client : this._session; const defaultCategories = ['-*', 'devtools.timeline', 'v8.execute', 'disabled-by-default-devtools.timeline', 'disabled-by-default-devtools.timeline.frame', 'toplevel', 'blink.console', 'blink.user_timing', 'latencyInfo', 'disabled-by-default-devtools.timeline.stack', 'disabled-by-default-v8.cpu_profiler', 'disabled-by-default-v8.cpu_profiler.hires']; const { path = null, screenshots = false, categories = defaultCategories } = options; if (screenshots) categories.push('disabled-by-default-devtools.screenshot'); this._tracingPath = path; this._tracingRecording = true; await this._tracingClient.send('Tracing.start', { transferMode: 'ReturnAsStream', categories: categories.join(',') }); } async stopTracing() { (0, _utils.assert)(this._tracingClient, 'Tracing was not started.'); const [event] = await Promise.all([new Promise(f => this._tracingClient.once('Tracing.tracingComplete', f)), this._tracingClient.send('Tracing.end')]); const result = await (0, _crProtocolHelper.readProtocolStream)(this._tracingClient, event.stream, this._tracingPath); this._tracingRecording = false; return result; } isConnected() { return !this._connection._closed; } async _clientRootSession() { if (!this._clientRootSessionPromise) this._clientRootSessionPromise = this._connection.createBrowserSession(); return this._clientRootSessionPromise; } } exports.CRBrowser = CRBrowser; class CRBrowserContext extends _browserContext.BrowserContext { constructor(browser, browserContextId, options) { super(browser, options, browserContextId); this._authenticateProxyViaCredentials(); } async _initialize() { (0, _utils.assert)(!Array.from(this._browser._crPages.values()).some(page => page._browserContext === this)); const promises = [super._initialize()]; if (this._browser.options.name !== 'electron' && this._browser.options.name !== 'clank') { promises.push(this._browser._session.send('Browser.setDownloadBehavior', { behavior: this._options.acceptDownloads ? 'allowAndName' : 'deny', browserContextId: this._browserContextId, downloadPath: this._browser.options.downloadsPath, eventsEnabled: true })); } await Promise.all(promises); } _crPages() { return [...this._browser._crPages.values()].filter(crPage => crPage._browserContext === this); } pages() { return this._crPages().map(crPage => crPage._initializedPage).filter(Boolean); } async newPageDelegate() { (0, _browserContext.assertBrowserContextIsNotOwned)(this); const oldKeys = this._browser.isClank() ? new Set(this._browser._crPages.keys()) : undefined; let { targetId } = await this._browser._session.send('Target.createTarget', { url: 'about:blank', browserContextId: this._browserContextId }); if (oldKeys) { // Chrome for Android returns tab ids (1, 2, 3, 4, 5) instead of content target ids here, work around it via the // heuristic assuming that there is only one page created at a time. const newKeys = new Set(this._browser._crPages.keys()); // Remove old keys. for (const key of oldKeys) newKeys.delete(key); // Remove potential concurrent popups. for (const key of newKeys) { const page = this._browser._crPages.get(key); if (page._opener) newKeys.delete(key); } (0, _utils.assert)(newKeys.size === 1); [targetId] = [...newKeys]; } return this._browser._crPages.get(targetId); } async doGetCookies(urls) { const { cookies } = await this._browser._session.send('Storage.getCookies', { browserContextId: this._browserContextId }); return network.filterCookies(cookies.map(c => { const copy = { sameSite: 'Lax', ...c }; delete copy.size; delete copy.priority; delete copy.session; delete copy.sameParty; delete copy.sourceScheme; delete copy.sourcePort; return copy; }), urls); } async addCookies(cookies) { await this._browser._session.send('Storage.setCookies', { cookies: network.rewriteCookies(cookies), browserContextId: this._browserContextId }); } async clearCookies() { await this._browser._session.send('Storage.clearCookies', { browserContextId: this._browserContextId }); } async doGrantPermissions(origin, permissions) { const webPermissionToProtocol = new Map([['geolocation', 'geolocation'], ['midi', 'midi'], ['notifications', 'notifications'], ['camera', 'videoCapture'], ['microphone', 'audioCapture'], ['background-sync', 'backgroundSync'], ['ambient-light-sensor', 'sensors'], ['accelerometer', 'sensors'], ['gyroscope', 'sensors'], ['magnetometer', 'sensors'], ['accessibility-events', 'accessibilityEvents'], ['clipboard-read', 'clipboardReadWrite'], ['clipboard-write', 'clipboardSanitizedWrite'], ['payment-handler', 'paymentHandler'], // chrome-specific permissions we have. ['midi-sysex', 'midiSysex']]); const filtered = permissions.map(permission => { const protocolPermission = webPermissionToProtocol.get(permission); if (!protocolPermission) throw new Error('Unknown permission: ' + permission); return protocolPermission; }); await this._browser._session.send('Browser.grantPermissions', { origin: origin === '*' ? undefined : origin, browserContextId: this._browserContextId, permissions: filtered }); } async doClearPermissions() { await this._browser._session.send('Browser.resetPermissions', { browserContextId: this._browserContextId }); } async setGeolocation(geolocation) { (0, _browserContext.verifyGeolocation)(geolocation); this._options.geolocation = geolocation; for (const page of this.pages()) await page._delegate.updateGeolocation(); } async setExtraHTTPHeaders(headers) { this._options.extraHTTPHeaders = headers; for (const page of this.pages()) await page._delegate.updateExtraHTTPHeaders(); for (const sw of this.serviceWorkers()) await sw.updateExtraHTTPHeaders(false); } async setUserAgent(userAgent) { this._options.userAgent = userAgent; for (const page of this.pages()) await page._delegate.updateUserAgent(); // TODO: service workers don't have Emulation domain? } async setOffline(offline) { this._options.offline = offline; for (const page of this.pages()) await page._delegate.updateOffline(); for (const sw of this.serviceWorkers()) await sw.updateOffline(false); } async doSetHTTPCredentials(httpCredentials) { this._options.httpCredentials = httpCredentials; for (const page of this.pages()) await page._delegate.updateHttpCredentials(); for (const sw of this.serviceWorkers()) await sw.updateHttpCredentials(false); } async doAddInitScript(source) { for (const page of this.pages()) await page._delegate.addInitScript(source); } async doRemoveInitScripts() { for (const page of this.pages()) await page._delegate.removeInitScripts(); } async doExposeBinding(binding) { for (const page of this.pages()) await page._delegate.exposeBinding(binding); } async doRemoveExposedBindings() { for (const page of this.pages()) await page._delegate.removeExposedBindings(); } async doUpdateRequestInterception() { for (const page of this.pages()) await page._delegate.updateRequestInterception(); for (const sw of this.serviceWorkers()) await sw.updateRequestInterception(); } async doClose() { // Headful chrome cannot dispose browser context with opened 'beforeunload' // dialogs, so we should close all that are currently opened. // We also won't get new ones since `Target.disposeBrowserContext` does not trigger // beforeunload. const openedBeforeUnloadDialogs = []; for (const crPage of this._crPages()) { const dialogs = [...crPage._page._frameManager._openedDialogs].filter(dialog => dialog.type() === 'beforeunload'); openedBeforeUnloadDialogs.push(...dialogs); } await Promise.all(openedBeforeUnloadDialogs.map(dialog => dialog.dismiss())); if (!this._browserContextId) { await Promise.all(this._crPages().map(crPage => crPage._mainFrameSession._stopVideoRecording())); // Closing persistent context should close the browser. await this._browser.close(); return; } await this._browser._session.send('Target.disposeBrowserContext', { browserContextId: this._browserContextId }); this._browser._contexts.delete(this._browserContextId); for (const [targetId, serviceWorker] of this._browser._serviceWorkers) { if (serviceWorker._browserContext !== this) continue; // When closing a browser context, service workers are shutdown // asynchronously and we get detached from them later. // To avoid the wrong order of notifications, we manually fire // "close" event here and forget about the serivce worker. serviceWorker.didClose(); this._browser._serviceWorkers.delete(targetId); } } onClosePersistent() { // When persistent context is closed, we do not necessary get Target.detachedFromTarget // for all the background pages. for (const [targetId, backgroundPage] of this._browser._backgroundPages.entries()) { if (backgroundPage._browserContext === this && backgroundPage._initializedPage) { backgroundPage.didClose(); this._browser._backgroundPages.delete(targetId); } } } async clearCache() { for (const page of this._crPages()) await page._mainFrameSession._networkManager.clearCache(); } async cancelDownload(guid) { // The upstream CDP method is implemented in a way that no explicit error would be given // regarding the requested `guid`, even if the download is in a state not suitable for // cancellation (finished, cancelled, etc.) or the guid is invalid at all. await this._browser._session.send('Browser.cancelDownload', { guid: guid, browserContextId: this._browserContextId }); } backgroundPages() { const result = []; for (const backgroundPage of this._browser._backgroundPages.values()) { if (backgroundPage._browserContext === this && backgroundPage._initializedPage) result.push(backgroundPage._initializedPage); } return result; } serviceWorkers() { return Array.from(this._browser._serviceWorkers.values()).filter(serviceWorker => serviceWorker._browserContext === this); } async newCDPSession(page) { let targetId = null; if (page instanceof _page.Page) { targetId = page._delegate._targetId; } else if (page instanceof _frames.Frame) { const session = page._page._delegate._sessions.get(page._id); if (!session) throw new Error(`This frame does not have a separate CDP session, it is a part of the parent frame's session`); targetId = session._targetId; } else { throw new Error('page: expected Page or Frame'); } const rootSession = await this._browser._clientRootSession(); const { sessionId } = await rootSession.send('Target.attachToTarget', { targetId, flatten: true }); return this._browser._connection.session(sessionId); } } exports.CRBrowserContext = CRBrowserContext; CRBrowserContext.CREvents = { BackgroundPage: 'backgroundpage', ServiceWorker: 'serviceworker' };