feat(har): store textual content without base64 encoding (#14772)

This commit is contained in:
Dmitry Gozman 2022-06-10 14:10:52 -07:00 committed by GitHub
parent 7a568a2952
commit 868e00253f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 28 additions and 13 deletions

View File

@ -191,7 +191,7 @@ export class HarTracer {
const contentType = event.headers['content-type'];
if (contentType)
content.mimeType = contentType;
this._storeResponseContent(event.body, content);
this._storeResponseContent(event.body, content, 'other');
if (this._started)
this._delegate.onEntryFinished(harEntry);
@ -261,7 +261,7 @@ export class HarTracer {
const content = harEntry.response.content;
compressionCalculationBarrier.setDecodedBodySize(buffer.length);
this._storeResponseContent(buffer, content);
this._storeResponseContent(buffer, content, request.resourceType());
}).catch(() => {
compressionCalculationBarrier.setDecodedBodySize(0);
}).then(() => {
@ -296,15 +296,21 @@ export class HarTracer {
this._delegate.onEntryFinished(harEntry);
}
private _storeResponseContent(buffer: Buffer | undefined, content: har.Content) {
private _storeResponseContent(buffer: Buffer | undefined, content: har.Content, resourceType: string) {
if (!buffer) {
content.size = 0;
return;
}
content.size = buffer.length;
if (this._options.content === 'embedded') {
content.text = buffer.toString('base64');
content.encoding = 'base64';
// Sometimes, we can receive a font/media file with textual mime type. Browser
// still interprets them correctly, but the 'content-type' header is obviously wrong.
if (isTextualMimeType(content.mimeType) && resourceType !== 'font') {
content.text = buffer.toString();
} else {
content.text = buffer.toString('base64');
content.encoding = 'base64';
}
} else if (this._options.content === 'sha1') {
content._sha1 = calculateSha1(buffer) + '.' + (mime.getExtension(content.mimeType) || 'dat');
if (this._started)
@ -529,3 +535,7 @@ function parseCookie(c: string): har.Cookie {
}
return cookie;
}
function isTextualMimeType(mimeType: string) {
return !!mimeType.match(/^(text\/.*?|application\/(json|(x-)?javascript|xml.*?|ecmascript)|image\/svg(\+xml)?|application\/.*?(\+json|\+xml))(;\s*charset=.*)?$/);
}

View File

@ -248,21 +248,26 @@ it('should include secure set-cookies', async ({ contextFactory, httpsServer },
it('should include content @smoke', async ({ contextFactory, server }, testInfo) => {
const { page, getLog } = await pageWithHar(contextFactory, testInfo);
await page.goto(server.PREFIX + '/har.html');
await page.evaluate(() => fetch('/pptr.png').then(r => r.arrayBuffer()));
const log = await getLog();
expect(log.entries[0].response.httpVersion).toBe('HTTP/1.1');
expect(log.entries[0].response.content.encoding).toBe('base64');
expect(log.entries[0].response.content.encoding).toBe(undefined);
expect(log.entries[0].response.content.mimeType).toBe('text/html; charset=utf-8');
expect(Buffer.from(log.entries[0].response.content.text, 'base64').toString()).toContain('HAR Page');
expect(log.entries[0].response.content.text).toContain('HAR Page');
expect(log.entries[0].response.content.size).toBeGreaterThanOrEqual(96);
expect(log.entries[0].response.content.compression).toBe(0);
expect(log.entries[1].response.httpVersion).toBe('HTTP/1.1');
expect(log.entries[1].response.content.encoding).toBe('base64');
expect(log.entries[1].response.content.encoding).toBe(undefined);
expect(log.entries[1].response.content.mimeType).toBe('text/css; charset=utf-8');
expect(Buffer.from(log.entries[1].response.content.text, 'base64').toString()).toContain('pink');
expect(log.entries[1].response.content.text).toContain('pink');
expect(log.entries[1].response.content.size).toBeGreaterThanOrEqual(37);
expect(log.entries[1].response.content.compression).toBe(0);
expect(log.entries[2].response.content.encoding).toBe('base64');
expect(log.entries[2].response.content.mimeType).toBe('image/png');
expect(Buffer.from(log.entries[2].response.content.text, 'base64').byteLength).toBeGreaterThan(0);
expect(log.entries[2].response.content.size).toBeGreaterThanOrEqual(6000);
expect(log.entries[2].response.content.compression).toBe(0);
});
it('should filter by glob', async ({ contextFactory, server }, testInfo) => {
@ -580,7 +585,7 @@ it('should contain http2 for http2 requests', async ({ contextFactory, browserNa
const log = await getLog();
expect(log.entries[0].request.httpVersion).toBe('HTTP/2.0');
expect(log.entries[0].response.httpVersion).toBe('HTTP/2.0');
expect(Buffer.from(log.entries[0].response.content.text, 'base64').toString()).toBe('<h1>Hello World</h1>');
expect(log.entries[0].response.content.text).toBe('<h1>Hello World</h1>');
server.close();
});
@ -734,7 +739,7 @@ it('should include API request', async ({ contextFactory, server }, testInfo) =>
expect(entry.response.status).toBe(200);
expect(entry.response.headers.find(h => h.name.toLowerCase() === 'content-type')?.value).toContain('application/json');
expect(entry.response.content.size).toBe(15);
expect(entry.response.content.text).toBe(responseBody.toString('base64'));
expect(entry.response.content.text).toBe(responseBody.toString());
});
it('should not hang on resources served from cache', async ({ contextFactory, server, browserName }, testInfo) => {