This commit is contained in:
parent
03501cfdb2
commit
d8bc6dbeea
|
|
@ -18,7 +18,7 @@ import * as http from 'http';
|
|||
import * as https from 'https';
|
||||
import { HttpsProxyAgent } from 'https-proxy-agent';
|
||||
import { SocksProxyAgent } from 'socks-proxy-agent';
|
||||
import { pipeline, Readable, Transform } from 'stream';
|
||||
import { pipeline, Readable, Transform, TransformCallback } from 'stream';
|
||||
import url from 'url';
|
||||
import zlib from 'zlib';
|
||||
import { HTTPCredentials } from '../../types/types';
|
||||
|
|
@ -341,13 +341,6 @@ export abstract class APIRequestContext extends SdkObject {
|
|||
});
|
||||
};
|
||||
|
||||
// These requests don't have response body.
|
||||
if (['HEAD', 'PUT', 'TRACE'].includes(options.method!)) {
|
||||
notifyBodyFinished();
|
||||
request.destroy();
|
||||
return;
|
||||
}
|
||||
|
||||
let body: Readable = response;
|
||||
let transform: Transform | undefined;
|
||||
const encoding = response.headers['content-encoding'];
|
||||
|
|
@ -362,7 +355,9 @@ export abstract class APIRequestContext extends SdkObject {
|
|||
transform = zlib.createInflate();
|
||||
}
|
||||
if (transform) {
|
||||
body = pipeline(response, transform, e => {
|
||||
// Brotli and deflate decompressors throw if the input stream is empty.
|
||||
const emptyStreamTransform = new SafeEmptyStreamTransform(notifyBodyFinished);
|
||||
body = pipeline(response, emptyStreamTransform, transform, e => {
|
||||
if (e)
|
||||
reject(new Error(`failed to decompress '${encoding}' encoding: ${e}`));
|
||||
});
|
||||
|
|
@ -407,6 +402,26 @@ export abstract class APIRequestContext extends SdkObject {
|
|||
}
|
||||
}
|
||||
|
||||
class SafeEmptyStreamTransform extends Transform {
|
||||
private _receivedSomeData: boolean = false;
|
||||
private _onEmptyStreamCallback: () => void;
|
||||
|
||||
constructor(onEmptyStreamCallback: () => void) {
|
||||
super();
|
||||
this._onEmptyStreamCallback = onEmptyStreamCallback;
|
||||
}
|
||||
override _transform(chunk: any, encoding: BufferEncoding, callback: TransformCallback): void {
|
||||
this._receivedSomeData = true;
|
||||
callback(null, chunk);
|
||||
}
|
||||
override _flush(callback: TransformCallback): void {
|
||||
if (this._receivedSomeData)
|
||||
callback(null);
|
||||
else
|
||||
this._onEmptyStreamCallback();
|
||||
}
|
||||
}
|
||||
|
||||
export class BrowserContextAPIRequestContext extends APIRequestContext {
|
||||
private readonly _context: BrowserContext;
|
||||
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ for (const method of ['fetch', 'delete', 'get', 'head', 'patch', 'post', 'put']
|
|||
expect(response.ok()).toBeTruthy();
|
||||
expect(response.headers()['content-type']).toBe('application/json; charset=utf-8');
|
||||
expect(response.headersArray()).toContainEqual({ name: 'Content-Type', value: 'application/json; charset=utf-8' });
|
||||
expect(await response.text()).toBe(['head', 'put'].includes(method) ? '' : '{"foo": "bar"}\n');
|
||||
expect(await response.text()).toBe('head' === method ? '' : '{"foo": "bar"}\n');
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -363,3 +363,18 @@ it('should not fail on empty body with encoding', async ({ playwright, server })
|
|||
}
|
||||
await request.dispose();
|
||||
});
|
||||
|
||||
it('should return body for failing requests', async ({ playwright, server }) => {
|
||||
const request = await playwright.request.newContext();
|
||||
for (const method of ['head', 'put', 'trace']) {
|
||||
server.setRoute('/empty.html', (req, res) => {
|
||||
res.writeHead(404, { 'Content-Length': 10, 'Content-Type': 'text/plain' });
|
||||
res.end('Not found.');
|
||||
});
|
||||
const response = await request.fetch(server.EMPTY_PAGE, { method });
|
||||
expect(response.status()).toBe(404);
|
||||
// HEAD response returns empty body in node http module.
|
||||
expect(await response.text()).toBe(method === 'head' ? '' : 'Not found.');
|
||||
}
|
||||
await request.dispose();
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue