From 5271c26af12a8bd69894dde3e9ddf5cb396be9e4 Mon Sep 17 00:00:00 2001 From: Dmitry Gozman Date: Mon, 19 Aug 2024 10:29:51 -0700 Subject: [PATCH] fix(trace viewer): do not serve resources with x-unknown content type (#32219) `x-unknown` is used as a placeholder for "no content-type" in the har. We should not send it to the browser, because it is meaningfully different from not sending `Content-Type` header. For example, Chromium refuses to interpret stylesheets served with `x-unknown` content type. Fixes https://github.com/microsoft/playwright-java/issues/1651. --- packages/trace-viewer/src/snapshotServer.ts | 4 +++- packages/trace-viewer/src/traceModel.ts | 8 +++++--- tests/library/trace-viewer.spec.ts | 12 ++++++++++++ 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/packages/trace-viewer/src/snapshotServer.ts b/packages/trace-viewer/src/snapshotServer.ts index c3c2f5a6247d7..b1dd371cb373f 100644 --- a/packages/trace-viewer/src/snapshotServer.ts +++ b/packages/trace-viewer/src/snapshotServer.ts @@ -85,7 +85,9 @@ export class SnapshotServer { contentType = `${contentType}; charset=utf-8`; const headers = new Headers(); - headers.set('Content-Type', contentType); + // "x-unknown" in the har means "no content type". + if (contentType !== 'x-unknown') + headers.set('Content-Type', contentType); for (const { name, value } of resource.response.headers) headers.set(name, value); headers.delete('Content-Encoding'); diff --git a/packages/trace-viewer/src/traceModel.ts b/packages/trace-viewer/src/traceModel.ts index 0fc1a73efa76c..1248dde967a07 100644 --- a/packages/trace-viewer/src/traceModel.ts +++ b/packages/trace-viewer/src/traceModel.ts @@ -114,9 +114,11 @@ export class TraceModel { async resourceForSha1(sha1: string): Promise { const blob = await this._backend.readBlob('resources/' + sha1); - if (!blob) - return; - return new Blob([blob], { type: this._resourceToContentType.get(sha1) || 'application/octet-stream' }); + const contentType = this._resourceToContentType.get(sha1); + // "x-unknown" in the har means "no content type". + if (!blob || contentType === undefined || contentType === 'x-unknown') + return blob; + return new Blob([blob], { type: contentType }); } storage(): SnapshotStorage { diff --git a/tests/library/trace-viewer.spec.ts b/tests/library/trace-viewer.spec.ts index e8471c16d6c78..3af586d67fe5e 100644 --- a/tests/library/trace-viewer.spec.ts +++ b/tests/library/trace-viewer.spec.ts @@ -1439,3 +1439,15 @@ test('should show baseURL in metadata pane', { await traceViewer.showMetadataTab(); await expect(traceViewer.metadataTab).toContainText('baseURL:https://example.com'); }); + +test('should serve css without content-type', async ({ page, runAndTrace, server }) => { + server.setRoute('/one-style.css', (req, res) => { + res.writeHead(200); + res.end(`body { background: red }`); + }); + const traceViewer = await runAndTrace(async () => { + await page.goto(server.PREFIX + '/one-style.html'); + }); + const snapshotFrame = await traceViewer.snapshotFrame('page.goto'); + await expect(snapshotFrame.locator('body')).toHaveCSS('background-color', 'rgb(255, 0, 0)', { timeout: 0 }); +});