fix firefox bug

This commit is contained in:
Simon Knott 2025-02-05 17:03:33 +01:00
parent a1f4cb8b43
commit bb2220e5ed
No known key found for this signature in database
GPG key ID: 8CEDC00028084AEC
2 changed files with 21 additions and 4 deletions

View file

@ -515,13 +515,15 @@ export abstract class BrowserContext extends SdkObject {
}; };
const originsToSave = new Set(this._origins); const originsToSave = new Set(this._origins);
const collectScript = `(${storageScript.collect})((${utilityScriptSerializers.source})(), ${this._browser.options.name === 'firefox'})`;
// First try collecting storage stage from existing pages. // First try collecting storage stage from existing pages.
for (const page of this.pages()) { for (const page of this.pages()) {
const origin = page.mainFrame().origin(); const origin = page.mainFrame().origin();
if (!origin || !originsToSave.has(origin)) if (!origin || !originsToSave.has(origin))
continue; continue;
try { try {
const storage: storageScript.Storage = await page.mainFrame().nonStallingEvaluateInExistingContext(`(${storageScript.collect})((${utilityScriptSerializers.source})())`, 'utility'); const storage: storageScript.Storage = await page.mainFrame().nonStallingEvaluateInExistingContext(collectScript, 'utility');
if (storage.localStorage.length || storage.indexedDB.length) if (storage.localStorage.length || storage.indexedDB.length)
result.origins.push({ origin, localStorage: storage.localStorage, indexedDB: storage.indexedDB }); result.origins.push({ origin, localStorage: storage.localStorage, indexedDB: storage.indexedDB });
originsToSave.delete(origin); originsToSave.delete(origin);
@ -541,7 +543,7 @@ export abstract class BrowserContext extends SdkObject {
for (const origin of originsToSave) { for (const origin of originsToSave) {
const frame = page.mainFrame(); const frame = page.mainFrame();
await frame.goto(internalMetadata, origin); await frame.goto(internalMetadata, origin);
const storage: Awaited<ReturnType<typeof storageScript.collect>> = await frame.evaluateExpression(`(${storageScript.collect})((${utilityScriptSerializers.source})())`, { world: 'utility' }); const storage: storageScript.Storage = await frame.evaluateExpression(collectScript, { world: 'utility' });
if (storage.localStorage.length || storage.indexedDB.length) if (storage.localStorage.length || storage.indexedDB.length)
result.origins.push({ origin, localStorage: storage.localStorage, indexedDB: storage.indexedDB }); result.origins.push({ origin, localStorage: storage.localStorage, indexedDB: storage.indexedDB });
} }

View file

@ -19,7 +19,7 @@ import type { source } from './isomorphic/utilityScriptSerializers';
export type Storage = Omit<channels.OriginStorage, 'origin'>; export type Storage = Omit<channels.OriginStorage, 'origin'>;
export async function collect(serializers: ReturnType<typeof source>): Promise<Storage> { export async function collect(serializers: ReturnType<typeof source>, isFirefox: boolean): Promise<Storage> {
const idbResult = await Promise.all((await indexedDB.databases()).map(async dbInfo => { const idbResult = await Promise.all((await indexedDB.databases()).map(async dbInfo => {
if (!dbInfo.name) if (!dbInfo.name)
throw new Error('Database name is empty'); throw new Error('Database name is empty');
@ -33,11 +33,26 @@ export async function collect(serializers: ReturnType<typeof source>): Promise<S
}); });
} }
function isPlainObject(v: any) {
const ctor = v?.constructor;
if (ctor === Object)
return true;
// firefox bug. the above check doesn't work in the utility world.
if (isFirefox) {
const constructorImpl = ctor?.toString();
if (constructorImpl.startsWith('function Object() {') && constructorImpl.includes(' [native code]'))
return true;
}
return false;
}
function trySerialize(value: any): { trivial?: any, encoded?: any } { function trySerialize(value: any): { trivial?: any, encoded?: any } {
let trivial = true; let trivial = true;
const encoded = serializers.serializeAsCallArgument(value, v => { const encoded = serializers.serializeAsCallArgument(value, v => {
const isTrivial = ( const isTrivial = (
v?.constructor === Object isPlainObject(v)
|| Array.isArray(v) || Array.isArray(v)
|| typeof v === 'string' || typeof v === 'string'
|| typeof v === 'number' || typeof v === 'number'