feat(har): store textual content without base64 encoding (#14772)
This commit is contained in:
parent
7a568a2952
commit
868e00253f
|
|
@ -191,7 +191,7 @@ export class HarTracer {
|
||||||
const contentType = event.headers['content-type'];
|
const contentType = event.headers['content-type'];
|
||||||
if (contentType)
|
if (contentType)
|
||||||
content.mimeType = contentType;
|
content.mimeType = contentType;
|
||||||
this._storeResponseContent(event.body, content);
|
this._storeResponseContent(event.body, content, 'other');
|
||||||
|
|
||||||
if (this._started)
|
if (this._started)
|
||||||
this._delegate.onEntryFinished(harEntry);
|
this._delegate.onEntryFinished(harEntry);
|
||||||
|
|
@ -261,7 +261,7 @@ export class HarTracer {
|
||||||
|
|
||||||
const content = harEntry.response.content;
|
const content = harEntry.response.content;
|
||||||
compressionCalculationBarrier.setDecodedBodySize(buffer.length);
|
compressionCalculationBarrier.setDecodedBodySize(buffer.length);
|
||||||
this._storeResponseContent(buffer, content);
|
this._storeResponseContent(buffer, content, request.resourceType());
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
compressionCalculationBarrier.setDecodedBodySize(0);
|
compressionCalculationBarrier.setDecodedBodySize(0);
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
|
|
@ -296,15 +296,21 @@ export class HarTracer {
|
||||||
this._delegate.onEntryFinished(harEntry);
|
this._delegate.onEntryFinished(harEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _storeResponseContent(buffer: Buffer | undefined, content: har.Content) {
|
private _storeResponseContent(buffer: Buffer | undefined, content: har.Content, resourceType: string) {
|
||||||
if (!buffer) {
|
if (!buffer) {
|
||||||
content.size = 0;
|
content.size = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
content.size = buffer.length;
|
content.size = buffer.length;
|
||||||
if (this._options.content === 'embedded') {
|
if (this._options.content === 'embedded') {
|
||||||
|
// 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.text = buffer.toString('base64');
|
||||||
content.encoding = 'base64';
|
content.encoding = 'base64';
|
||||||
|
}
|
||||||
} else if (this._options.content === 'sha1') {
|
} else if (this._options.content === 'sha1') {
|
||||||
content._sha1 = calculateSha1(buffer) + '.' + (mime.getExtension(content.mimeType) || 'dat');
|
content._sha1 = calculateSha1(buffer) + '.' + (mime.getExtension(content.mimeType) || 'dat');
|
||||||
if (this._started)
|
if (this._started)
|
||||||
|
|
@ -529,3 +535,7 @@ function parseCookie(c: string): har.Cookie {
|
||||||
}
|
}
|
||||||
return 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=.*)?$/);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -248,21 +248,26 @@ it('should include secure set-cookies', async ({ contextFactory, httpsServer },
|
||||||
it('should include content @smoke', async ({ contextFactory, server }, testInfo) => {
|
it('should include content @smoke', async ({ contextFactory, server }, testInfo) => {
|
||||||
const { page, getLog } = await pageWithHar(contextFactory, testInfo);
|
const { page, getLog } = await pageWithHar(contextFactory, testInfo);
|
||||||
await page.goto(server.PREFIX + '/har.html');
|
await page.goto(server.PREFIX + '/har.html');
|
||||||
|
await page.evaluate(() => fetch('/pptr.png').then(r => r.arrayBuffer()));
|
||||||
const log = await getLog();
|
const log = await getLog();
|
||||||
|
|
||||||
expect(log.entries[0].response.httpVersion).toBe('HTTP/1.1');
|
expect(log.entries[0].response.content.encoding).toBe(undefined);
|
||||||
expect(log.entries[0].response.content.encoding).toBe('base64');
|
|
||||||
expect(log.entries[0].response.content.mimeType).toBe('text/html; charset=utf-8');
|
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.size).toBeGreaterThanOrEqual(96);
|
||||||
expect(log.entries[0].response.content.compression).toBe(0);
|
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(undefined);
|
||||||
expect(log.entries[1].response.content.encoding).toBe('base64');
|
|
||||||
expect(log.entries[1].response.content.mimeType).toBe('text/css; charset=utf-8');
|
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.size).toBeGreaterThanOrEqual(37);
|
||||||
expect(log.entries[1].response.content.compression).toBe(0);
|
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) => {
|
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();
|
const log = await getLog();
|
||||||
expect(log.entries[0].request.httpVersion).toBe('HTTP/2.0');
|
expect(log.entries[0].request.httpVersion).toBe('HTTP/2.0');
|
||||||
expect(log.entries[0].response.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();
|
server.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -734,7 +739,7 @@ it('should include API request', async ({ contextFactory, server }, testInfo) =>
|
||||||
expect(entry.response.status).toBe(200);
|
expect(entry.response.status).toBe(200);
|
||||||
expect(entry.response.headers.find(h => h.name.toLowerCase() === 'content-type')?.value).toContain('application/json');
|
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.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) => {
|
it('should not hang on resources served from cache', async ({ contextFactory, server, browserName }, testInfo) => {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue