참고소스 수정본
This commit is contained in:
235
참고/playwright-main/browser_patches/firefox/juggler/Helper.js
Normal file
235
참고/playwright-main/browser_patches/firefox/juggler/Helper.js
Normal file
@@ -0,0 +1,235 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const uuidGen = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator);
|
||||
|
||||
export class Helper {
|
||||
decorateAsEventEmitter(objectToDecorate) {
|
||||
const { EventEmitter } = ChromeUtils.importESModule('resource://gre/modules/EventEmitter.sys.mjs');
|
||||
const emitter = new EventEmitter();
|
||||
objectToDecorate.on = emitter.on.bind(emitter);
|
||||
objectToDecorate.addEventListener = emitter.on.bind(emitter);
|
||||
objectToDecorate.off = emitter.off.bind(emitter);
|
||||
objectToDecorate.removeEventListener = emitter.off.bind(emitter);
|
||||
objectToDecorate.once = emitter.once.bind(emitter);
|
||||
objectToDecorate.emit = emitter.emit.bind(emitter);
|
||||
}
|
||||
|
||||
collectAllBrowsingContexts(rootBrowsingContext, allBrowsingContexts = []) {
|
||||
allBrowsingContexts.push(rootBrowsingContext);
|
||||
for (const child of rootBrowsingContext.children)
|
||||
this.collectAllBrowsingContexts(child, allBrowsingContexts);
|
||||
return allBrowsingContexts;
|
||||
}
|
||||
|
||||
awaitTopic(topic) {
|
||||
return new Promise(resolve => {
|
||||
const listener = () => {
|
||||
Services.obs.removeObserver(listener, topic);
|
||||
resolve();
|
||||
}
|
||||
Services.obs.addObserver(listener, topic);
|
||||
});
|
||||
}
|
||||
|
||||
toProtocolNavigationId(loadIdentifier) {
|
||||
return `nav-${loadIdentifier}`;
|
||||
}
|
||||
|
||||
addObserver(handler, topic) {
|
||||
Services.obs.addObserver(handler, topic);
|
||||
return () => Services.obs.removeObserver(handler, topic);
|
||||
}
|
||||
|
||||
addMessageListener(receiver, eventName, handler) {
|
||||
receiver.addMessageListener(eventName, handler);
|
||||
return () => receiver.removeMessageListener(eventName, handler);
|
||||
}
|
||||
|
||||
addEventListener(receiver, eventName, handler, options) {
|
||||
receiver.addEventListener(eventName, handler, options);
|
||||
return () => {
|
||||
try {
|
||||
receiver.removeEventListener(eventName, handler, options);
|
||||
} catch (e) {
|
||||
// This could fail when window has navigated cross-process
|
||||
// and we remove the listener from WindowProxy.
|
||||
// Nothing we can do here - so ignore the error.
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
awaitEvent(receiver, eventName) {
|
||||
return new Promise(resolve => {
|
||||
receiver.addEventListener(eventName, function listener() {
|
||||
receiver.removeEventListener(eventName, listener);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
on(receiver, eventName, handler, options) {
|
||||
// The toolkit/modules/EventEmitter.jsm dispatches event name as a first argument.
|
||||
// Fire event listeners without it for convenience.
|
||||
const handlerWrapper = (_, ...args) => handler(...args);
|
||||
receiver.on(eventName, handlerWrapper, options);
|
||||
return () => receiver.off(eventName, handlerWrapper);
|
||||
}
|
||||
|
||||
addProgressListener(progress, listener, flags) {
|
||||
progress.addProgressListener(listener, flags);
|
||||
return () => progress.removeProgressListener(listener);
|
||||
}
|
||||
|
||||
removeListeners(listeners) {
|
||||
for (const tearDown of listeners)
|
||||
tearDown.call(null);
|
||||
listeners.splice(0, listeners.length);
|
||||
}
|
||||
|
||||
generateId() {
|
||||
const string = uuidGen.generateUUID().toString();
|
||||
return string.substring(1, string.length - 1);
|
||||
}
|
||||
|
||||
getLoadContext(channel) {
|
||||
let loadContext = null;
|
||||
try {
|
||||
if (channel.notificationCallbacks)
|
||||
loadContext = channel.notificationCallbacks.getInterface(Ci.nsILoadContext);
|
||||
} catch (e) {}
|
||||
try {
|
||||
if (!loadContext && channel.loadGroup)
|
||||
loadContext = channel.loadGroup.notificationCallbacks.getInterface(Ci.nsILoadContext);
|
||||
} catch (e) { }
|
||||
return loadContext;
|
||||
}
|
||||
|
||||
getNetworkErrorStatusText(status) {
|
||||
if (!status)
|
||||
return null;
|
||||
for (const key of Object.keys(Cr)) {
|
||||
if (Cr[key] === status)
|
||||
return key;
|
||||
}
|
||||
// Security module. The following is taken from
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/How_to_check_the_secruity_state_of_an_XMLHTTPRequest_over_SSL
|
||||
if ((status & 0xff0000) === 0x5a0000) {
|
||||
// NSS_SEC errors (happen below the base value because of negative vals)
|
||||
if ((status & 0xffff) < Math.abs(Ci.nsINSSErrorsService.NSS_SEC_ERROR_BASE)) {
|
||||
// The bases are actually negative, so in our positive numeric space, we
|
||||
// need to subtract the base off our value.
|
||||
const nssErr = Math.abs(Ci.nsINSSErrorsService.NSS_SEC_ERROR_BASE) - (status & 0xffff);
|
||||
switch (nssErr) {
|
||||
case 11:
|
||||
return 'SEC_ERROR_EXPIRED_CERTIFICATE';
|
||||
case 12:
|
||||
return 'SEC_ERROR_REVOKED_CERTIFICATE';
|
||||
case 13:
|
||||
return 'SEC_ERROR_UNKNOWN_ISSUER';
|
||||
case 20:
|
||||
return 'SEC_ERROR_UNTRUSTED_ISSUER';
|
||||
case 21:
|
||||
return 'SEC_ERROR_UNTRUSTED_CERT';
|
||||
case 36:
|
||||
return 'SEC_ERROR_CA_CERT_INVALID';
|
||||
case 90:
|
||||
return 'SEC_ERROR_INADEQUATE_KEY_USAGE';
|
||||
case 176:
|
||||
return 'SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED';
|
||||
default:
|
||||
return 'SEC_ERROR_UNKNOWN';
|
||||
}
|
||||
}
|
||||
const sslErr = Math.abs(Ci.nsINSSErrorsService.NSS_SSL_ERROR_BASE) - (status & 0xffff);
|
||||
switch (sslErr) {
|
||||
case 3:
|
||||
return 'SSL_ERROR_NO_CERTIFICATE';
|
||||
case 4:
|
||||
return 'SSL_ERROR_BAD_CERTIFICATE';
|
||||
case 8:
|
||||
return 'SSL_ERROR_UNSUPPORTED_CERTIFICATE_TYPE';
|
||||
case 9:
|
||||
return 'SSL_ERROR_UNSUPPORTED_VERSION';
|
||||
case 12:
|
||||
return 'SSL_ERROR_BAD_CERT_DOMAIN';
|
||||
default:
|
||||
return 'SSL_ERROR_UNKNOWN';
|
||||
}
|
||||
}
|
||||
return '<unknown error>';
|
||||
}
|
||||
|
||||
browsingContextToFrameId(browsingContext) {
|
||||
if (!browsingContext)
|
||||
return undefined;
|
||||
if (!browsingContext.parent)
|
||||
return 'mainframe-' + browsingContext.browserId;
|
||||
return 'subframe-' + browsingContext.id;
|
||||
}
|
||||
}
|
||||
|
||||
const helper = new Helper();
|
||||
|
||||
export class EventWatcher {
|
||||
constructor(receiver, eventNames, pendingEventWatchers = new Set()) {
|
||||
this._pendingEventWatchers = pendingEventWatchers;
|
||||
this._pendingEventWatchers.add(this);
|
||||
|
||||
this._events = [];
|
||||
this._pendingPromises = [];
|
||||
this._eventListeners = eventNames.map(eventName =>
|
||||
helper.on(receiver, eventName, this._onEvent.bind(this, eventName)),
|
||||
);
|
||||
}
|
||||
|
||||
_onEvent(eventName, eventObject) {
|
||||
this._events.push({eventName, eventObject});
|
||||
for (const promise of this._pendingPromises)
|
||||
promise.resolve();
|
||||
this._pendingPromises = [];
|
||||
}
|
||||
|
||||
async ensureEvent(aEventName, predicate) {
|
||||
if (typeof aEventName !== 'string')
|
||||
throw new Error('ERROR: ensureEvent expects a "string" as its first argument');
|
||||
while (true) {
|
||||
const result = this.getEvent(aEventName, predicate);
|
||||
if (result)
|
||||
return result;
|
||||
await new Promise((resolve, reject) => this._pendingPromises.push({resolve, reject}));
|
||||
}
|
||||
}
|
||||
|
||||
async ensureEvents(eventNames, predicate) {
|
||||
if (!Array.isArray(eventNames))
|
||||
throw new Error('ERROR: ensureEvents expects an array of event names as its first argument');
|
||||
return await Promise.all(eventNames.map(eventName => this.ensureEvent(eventName, predicate)));
|
||||
}
|
||||
|
||||
async ensureEventsAndDispose(eventNames, predicate) {
|
||||
if (!Array.isArray(eventNames))
|
||||
throw new Error('ERROR: ensureEventsAndDispose expects an array of event names as its first argument');
|
||||
const result = await this.ensureEvents(eventNames, predicate);
|
||||
this.dispose();
|
||||
return result;
|
||||
}
|
||||
|
||||
getEvent(aEventName, predicate = (eventObject) => true) {
|
||||
return this._events.find(({eventName, eventObject}) => eventName === aEventName && predicate(eventObject))?.eventObject;
|
||||
}
|
||||
|
||||
hasEvent(aEventName, predicate) {
|
||||
return !!this.getEvent(aEventName, predicate);
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this._pendingEventWatchers.delete(this);
|
||||
for (const promise of this._pendingPromises)
|
||||
promise.reject(new Error('EventWatcher is being disposed'));
|
||||
this._pendingPromises = [];
|
||||
helper.removeListeners(this._eventListeners);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user