diff --git a/src/server/trace/viewer/frameSnapshot.ts b/src/server/trace/viewer/frameSnapshot.ts
index 876a7b56ea..7885ab26da 100644
--- a/src/server/trace/viewer/frameSnapshot.ts
+++ b/src/server/trace/viewer/frameSnapshot.ts
@@ -15,23 +15,25 @@
*/
import * as trace from '../common/traceEvents';
-import { ContextEntry } from './traceModel';
+import { ContextEntry, ContextResources } from './traceModel';
export * as trace from '../common/traceEvents';
export type SerializedFrameSnapshot = {
html: string;
- resourcesByUrl: { [key: string]: { resourceId: string, frameId: string }[] };
- overriddenUrls: { [key: string]: boolean };
- resourceOverrides: { [key: string]: string };
+ resources: { [key: string]: { resourceId: string, sha1?: string } };
};
export class FrameSnapshot {
private _snapshots: trace.FrameSnapshotTraceEvent[];
private _index: number;
- contextEntry: ContextEntry;
+ private _contextEntry: ContextEntry;
+ private _contextResources: ContextResources;
+ private _frameId: string;
- constructor(contextEntry: ContextEntry, events: trace.FrameSnapshotTraceEvent[], index: number) {
- this.contextEntry = contextEntry;
+ constructor(frameId: string, contextEntry: ContextEntry, contextResources: ContextResources, events: trace.FrameSnapshotTraceEvent[], index: number) {
+ this._frameId = frameId;
+ this._contextEntry = contextEntry;
+ this._contextResources = contextResources;
this._snapshots = events;
this._index = index;
}
@@ -80,14 +82,19 @@ export class FrameSnapshot {
let html = visit(snapshot.html, this._index);
if (snapshot.doctype)
html = `` + html;
- html += ``;
+ html += ``;
- const resourcesByUrl = this.contextEntry.resourcesByUrl;
- const overriddenUrls = this.contextEntry.overriddenUrls;
- const resourceOverrides: any = {};
- for (const o of this._snapshots[this._index].snapshot.resourceOverrides)
- resourceOverrides[o.url] = o.sha1;
- return { html, resourcesByUrl, overriddenUrls: overriddenUrls, resourceOverrides };
+ const resources: { [key: string]: { resourceId: string, sha1?: string } } = {};
+ for (const [url, contextResources] of this._contextResources) {
+ const contextResource = contextResources.find(r => r.frameId === this._frameId) || contextResources[0];
+ if (contextResource)
+ resources[url] = { resourceId: contextResource.resourceId };
+ }
+ for (const o of this.traceEvent().snapshot.resourceOverrides) {
+ const resource = resources[o.url];
+ resource.sha1 = o.sha1;
+ }
+ return { html, resources };
}
}
diff --git a/src/server/trace/viewer/snapshotServer.ts b/src/server/trace/viewer/snapshotServer.ts
index cf0ae41d69..979d971c1c 100644
--- a/src/server/trace/viewer/snapshotServer.ts
+++ b/src/server/trace/viewer/snapshotServer.ts
@@ -20,6 +20,7 @@ import path from 'path';
import querystring from 'querystring';
import type { TraceModel } from './traceModel';
import { TraceServer } from './traceServer';
+import type { SerializedFrameSnapshot } from './frameSnapshot';
export class SnapshotServer {
private _resourcesDir: string | undefined;
@@ -104,9 +105,7 @@ export class SnapshotServer {
private _serveServiceWorker(request: http.IncomingMessage, response: http.ServerResponse): boolean {
function serviceWorkerMain(self: any /* ServiceWorkerGlobalScope */) {
- const pageToResourcesByUrl = new Map();
- const pageToOverriddenUrls = new Map();
- const snapshotToResourceOverrides = new Map();
+ const snapshotResources = new Map();
self.addEventListener('install', function(event: any) {
});
@@ -171,28 +170,22 @@ export class SnapshotServer {
if (request.mode === 'navigate') {
const htmlResponse = await fetch(`/snapshot-data?pageId=${parsed.pageId}&snapshotId=${parsed.snapshotId || ''}×tamp=${parsed.timestamp || ''}&frameId=${parsed.frameId || ''}`);
- const { html, resourcesByUrl, overriddenUrls, resourceOverrides } = await htmlResponse.json();
+ const { html, resources }: SerializedFrameSnapshot = await htmlResponse.json();
if (!html)
return respondNotAvailable();
- pageToResourcesByUrl.set(parsed.pageId, resourcesByUrl);
- pageToOverriddenUrls.set(parsed.pageId, overriddenUrls);
- snapshotToResourceOverrides.set(parsed.snapshotId + '@' + parsed.timestamp, resourceOverrides);
+ snapshotResources.set(parsed.snapshotId + '@' + parsed.timestamp, resources);
const response = new Response(html, { status: 200, headers: { 'Content-Type': 'text/html' } });
return response;
}
- const resourcesByUrl = pageToResourcesByUrl.get(parsed.pageId);
- const overriddenUrls = pageToOverriddenUrls.get(parsed.pageId);
- const resourceOverrides = snapshotToResourceOverrides.get(parsed.snapshotId + '@' + parsed.timestamp);
+ const resources = snapshotResources.get(parsed.snapshotId + '@' + parsed.timestamp)!;
const urlWithoutHash = removeHash(request.url);
- const resourcesWithUrl = resourcesByUrl?.[urlWithoutHash] || [];
- const resource = resourcesWithUrl.find(r => r.frameId === parsed.frameId) || resourcesWithUrl[0];
+ const resource = resources[urlWithoutHash];
if (!resource)
return respond404();
- const overrideSha1 = resourceOverrides?.[urlWithoutHash];
- const fetchUrl = overrideSha1 ?
- `/resources/${resource.resourceId}/override/${overrideSha1}` :
+ const fetchUrl = resource.sha1 ?
+ `/resources/${resource.resourceId}/override/${resource.sha1}` :
`/resources/${resource.resourceId}`;
const fetchedResponse = await fetch(fetchUrl);
const headers = new Headers(fetchedResponse.headers);
@@ -201,7 +194,7 @@ export class SnapshotServer {
// as the original request url.
// Response url turns into resource base uri that is used to resolve
// relative links, e.g. url(/foo/bar) in style sheets.
- if (overriddenUrls?.[urlWithoutHash]) {
+ if (resource.sha1) {
// No cache, so that we refetch overridden resources.
headers.set('Cache-Control', 'no-cache');
}
diff --git a/src/server/trace/viewer/traceModel.ts b/src/server/trace/viewer/traceModel.ts
index 1de711ce1d..8a65a29a50 100644
--- a/src/server/trace/viewer/traceModel.ts
+++ b/src/server/trace/viewer/traceModel.ts
@@ -23,6 +23,7 @@ export class TraceModel {
contextEntries = new Map();
pageEntries = new Map();
resourceById = new Map();
+ contextResources = new Map();
appendEvents(events: trace.TraceEvent[]) {
for (const event of events)
@@ -39,9 +40,8 @@ export class TraceModel {
created: event,
destroyed: undefined as any,
pages: [],
- resourcesByUrl: {},
- overriddenUrls: {}
});
+ this.contextResources.set(event.contextId, new Map());
break;
}
case 'context-destroyed': {
@@ -104,14 +104,12 @@ export class TraceModel {
pageEntry.snapshotsByFrameId[event.frameId] = snapshots;
}
snapshots.push(event);
- const contextEntry = this.contextEntries.get(event.contextId)!;
for (const override of event.snapshot.resourceOverrides) {
if (override.ref) {
const refOverride = snapshots[snapshots.length - 1 - override.ref]?.snapshot.resourceOverrides.find(o => o.url === override.url);
override.sha1 = refOverride?.sha1;
delete override.ref;
}
- contextEntry.overriddenUrls[override.url] = true;
}
break;
}
@@ -122,11 +120,11 @@ export class TraceModel {
}
appendResource(event: trace.NetworkResourceTraceEvent) {
- const contextEntry = this.contextEntries.get(event.contextId)!;
- let responseEvents = contextEntry.resourcesByUrl[event.url];
+ const contextResources = this.contextResources.get(event.contextId)!;
+ let responseEvents = contextResources.get(event.url);
if (!responseEvents) {
responseEvents = [];
- contextEntry.resourcesByUrl[event.url] = responseEvents;
+ contextResources.set(event.url, responseEvents);
}
responseEvents.push({ frameId: event.frameId, resourceId: event.resourceId });
this.resourceById.set(event.resourceId, event);
@@ -159,7 +157,7 @@ export class TraceModel {
const frameSnapshots = pageEntry.snapshotsByFrameId[frameId];
for (let index = 0; index < frameSnapshots.length; index++) {
if (frameSnapshots[index].snapshotId === snapshotId)
- return new FrameSnapshot(contextEntry, frameSnapshots, index);
+ return new FrameSnapshot(frameId, contextEntry, this.contextResources.get(contextEntry.created.contextId)!, frameSnapshots, index);
}
}
@@ -172,7 +170,7 @@ export class TraceModel {
if (timestamp && snapshot.timestamp <= timestamp)
snapshotIndex = index;
}
- return snapshotIndex >= 0 ? new FrameSnapshot(contextEntry, frameSnapshots, snapshotIndex) : undefined;
+ return snapshotIndex >= 0 ? new FrameSnapshot(frameId, contextEntry, this.contextResources.get(contextEntry.created.contextId)!, frameSnapshots, snapshotIndex) : undefined;
}
}
@@ -183,10 +181,10 @@ export type ContextEntry = {
created: trace.ContextCreatedTraceEvent;
destroyed: trace.ContextDestroyedTraceEvent;
pages: PageEntry[];
- resourcesByUrl: { [key: string]: { resourceId: string, frameId: string }[] };
- overriddenUrls: { [key: string]: boolean };
}
+export type ContextResources = Map;
+
export type InterestingPageEvent = trace.DialogOpenedEvent | trace.DialogClosedEvent | trace.NavigationEvent | trace.LoadEvent;
export type PageEntry = {