fix: don't parse potentially invalid urls in event handlers (#5090)
This commit is contained in:
parent
01d6f83597
commit
fdde9493ea
|
|
@ -18,6 +18,7 @@ import * as fs from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as util from 'util';
|
import * as util from 'util';
|
||||||
import type { Route } from '../../..';
|
import type { Route } from '../../..';
|
||||||
|
import { parsedURL } from '../../client/clientHelper';
|
||||||
import type { FrameSnapshot, NetworkResourceTraceEvent, PageSnapshot } from '../../trace/traceTypes';
|
import type { FrameSnapshot, NetworkResourceTraceEvent, PageSnapshot } from '../../trace/traceTypes';
|
||||||
import { ContextEntry } from './traceModel';
|
import { ContextEntry } from './traceModel';
|
||||||
|
|
||||||
|
|
@ -112,11 +113,9 @@ export class SnapshotRouter {
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeHash(url: string) {
|
function removeHash(url: string) {
|
||||||
try {
|
const u = parsedURL(url);
|
||||||
const u = new URL(url);
|
if (!u)
|
||||||
u.hash = '';
|
|
||||||
return u.toString();
|
|
||||||
} catch (e) {
|
|
||||||
return url;
|
return url;
|
||||||
}
|
u.hash = '';
|
||||||
|
return u.toString();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -132,8 +132,8 @@ class TraceViewer {
|
||||||
this._document.snapshotRouter.route(route);
|
this._document.snapshotRouter.route(route);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const url = new URL(request.url());
|
|
||||||
try {
|
try {
|
||||||
|
const url = new URL(request.url());
|
||||||
if (this._document && request.url().includes('action-preview')) {
|
if (this._document && request.url().includes('action-preview')) {
|
||||||
const fullPath = url.pathname.substring('/action-preview/'.length);
|
const fullPath = url.pathname.substring('/action-preview/'.length);
|
||||||
const actionId = fullPath.substring(0, fullPath.indexOf('.png'));
|
const actionId = fullPath.substring(0, fullPath.indexOf('.png'));
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,14 @@ export async function evaluationScript(fun: Function | string | { path?: string,
|
||||||
throw new Error('Either path or content property must be present');
|
throw new Error('Either path or content property must be present');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function parsedURL(url: string): URL | null {
|
||||||
|
try {
|
||||||
|
return new URL(url);
|
||||||
|
} catch (e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function urlMatches(urlString: string, match: types.URLMatch | undefined): boolean {
|
export function urlMatches(urlString: string, match: types.URLMatch | undefined): boolean {
|
||||||
if (match === undefined || match === '')
|
if (match === undefined || match === '')
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -67,10 +75,11 @@ export function urlMatches(urlString: string, match: types.URLMatch | undefined)
|
||||||
return match.test(urlString);
|
return match.test(urlString);
|
||||||
if (typeof match === 'string' && match === urlString)
|
if (typeof match === 'string' && match === urlString)
|
||||||
return true;
|
return true;
|
||||||
const url = new URL(urlString);
|
const url = parsedURL(urlString);
|
||||||
|
if (!url)
|
||||||
|
return false;
|
||||||
if (typeof match === 'string')
|
if (typeof match === 'string')
|
||||||
return url.pathname === match;
|
return url.pathname === match;
|
||||||
|
|
||||||
if (typeof match !== 'function')
|
if (typeof match !== 'function')
|
||||||
throw new Error('url parameter should be string, RegExp or function');
|
throw new Error('url parameter should be string, RegExp or function');
|
||||||
return match(url);
|
return match(url);
|
||||||
|
|
|
||||||
|
|
@ -61,12 +61,18 @@ export function rewriteCookies(cookies: types.SetNetworkCookieParam[]): types.Se
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function stripFragmentFromUrl(url: string): string {
|
export function parsedURL(url: string): URL | null {
|
||||||
if (!url.indexOf('#'))
|
try {
|
||||||
|
return new URL(url);
|
||||||
|
} catch (e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function stripFragmentFromUrl(url: string): string {
|
||||||
|
if (!url.includes('#'))
|
||||||
return url;
|
return url;
|
||||||
const parsed = new URL(url);
|
return url.substring(0, url.indexOf('#'));
|
||||||
parsed.hash = '';
|
|
||||||
return parsed.href;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Request {
|
export class Request {
|
||||||
|
|
|
||||||
|
|
@ -481,7 +481,9 @@ export class Page extends EventEmitter {
|
||||||
const url = frame.url();
|
const url = frame.url();
|
||||||
if (!url.startsWith('http'))
|
if (!url.startsWith('http'))
|
||||||
return;
|
return;
|
||||||
this._browserContext.addVisitedOrigin(new URL(url).origin);
|
const purl = network.parsedURL(url);
|
||||||
|
if (purl)
|
||||||
|
this._browserContext.addVisitedOrigin(purl.origin);
|
||||||
}
|
}
|
||||||
|
|
||||||
allBindings() {
|
allBindings() {
|
||||||
|
|
|
||||||
|
|
@ -134,7 +134,9 @@ class HarContextTracer {
|
||||||
|
|
||||||
private _onRequest(page: Page, request: network.Request) {
|
private _onRequest(page: Page, request: network.Request) {
|
||||||
const pageEntry = this._pageEntries.get(page)!;
|
const pageEntry = this._pageEntries.get(page)!;
|
||||||
const url = new URL(request.url());
|
const url = network.parsedURL(request.url());
|
||||||
|
if (!url)
|
||||||
|
return;
|
||||||
|
|
||||||
const harEntry: har.Entry = {
|
const harEntry: har.Entry = {
|
||||||
pageref: pageEntry.id,
|
pageref: pageEntry.id,
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ import { BrowserContext } from '../server/browserContext';
|
||||||
import { Page } from '../server/page';
|
import { Page } from '../server/page';
|
||||||
import * as network from '../server/network';
|
import * as network from '../server/network';
|
||||||
import { helper, RegisteredListener } from '../server/helper';
|
import { helper, RegisteredListener } from '../server/helper';
|
||||||
|
import { stripFragmentFromUrl } from '../server/network';
|
||||||
import { Progress, runAbortableTask } from '../server/progress';
|
import { Progress, runAbortableTask } from '../server/progress';
|
||||||
import { debugLogger } from '../utils/debugLogger';
|
import { debugLogger } from '../utils/debugLogger';
|
||||||
import { Frame } from '../server/frames';
|
import { Frame } from '../server/frames';
|
||||||
|
|
@ -115,7 +116,7 @@ export class Snapshotter {
|
||||||
return frameResult;
|
return frameResult;
|
||||||
const frameSnapshot = {
|
const frameSnapshot = {
|
||||||
frameId: frame._id,
|
frameId: frame._id,
|
||||||
url: removeHash(frame.url()),
|
url: stripFragmentFromUrl(frame.url()),
|
||||||
html: '<body>Snapshot is not available</body>',
|
html: '<body>Snapshot is not available</body>',
|
||||||
resourceOverrides: [],
|
resourceOverrides: [],
|
||||||
};
|
};
|
||||||
|
|
@ -190,7 +191,7 @@ export class Snapshotter {
|
||||||
|
|
||||||
const snapshot: FrameSnapshot = {
|
const snapshot: FrameSnapshot = {
|
||||||
frameId: frame._id,
|
frameId: frame._id,
|
||||||
url: removeHash(frame.url()),
|
url: stripFragmentFromUrl(frame.url()),
|
||||||
html: data.html,
|
html: data.html,
|
||||||
resourceOverrides: [],
|
resourceOverrides: [],
|
||||||
};
|
};
|
||||||
|
|
@ -216,16 +217,6 @@ export class Snapshotter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeHash(url: string) {
|
|
||||||
try {
|
|
||||||
const u = new URL(url);
|
|
||||||
u.hash = '';
|
|
||||||
return u.toString();
|
|
||||||
} catch (e) {
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type FrameSnapshotAndMapping = {
|
type FrameSnapshotAndMapping = {
|
||||||
snapshot: FrameSnapshot,
|
snapshot: FrameSnapshot,
|
||||||
mapping: Map<Frame, string>,
|
mapping: Map<Frame, string>,
|
||||||
|
|
|
||||||
|
|
@ -494,3 +494,8 @@ it('should report raw buffer for main resource', (test, { browserName, platform
|
||||||
const body = await response.body();
|
const body = await response.body();
|
||||||
expect(body.toString()).toBe('Ü (lowercase ü)');
|
expect(body.toString()).toBe('Ü (lowercase ü)');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should not throw unhandled rejections on invalid url', async ({page, server}) => {
|
||||||
|
const e = await page.goto('https://www.youtube Panel Title.com/').catch(e => e);
|
||||||
|
expect(e.toString()).toContain('Panel Title');
|
||||||
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue