mirror of
https://github.com/puppeteer/puppeteer
synced 2024-06-14 14:02:48 +00:00
response.text() should wait for request to finish
This patch makes sure that request.text() doesn't try to fetch response body from the backend until the request is actually finished (finished or failed).
This commit is contained in:
parent
67f4264162
commit
445dce46f6
@ -86,12 +86,12 @@ class NetworkManager extends EventEmitter {
|
|||||||
_onRequestWillBeSent(event) {
|
_onRequestWillBeSent(event) {
|
||||||
if (event.redirectResponse) {
|
if (event.redirectResponse) {
|
||||||
let request = this._idToRequest.get(event.requestId);
|
let request = this._idToRequest.get(event.requestId);
|
||||||
let response = new Response(request, event.redirectResponse, this._getResponseBody.bind(this, event.requestId));
|
let response = new Response(this._client, request, event.redirectResponse);
|
||||||
request._response = response;
|
request._response = response;
|
||||||
this.emit(NetworkManager.Events.Response, response);
|
this.emit(NetworkManager.Events.Response, response);
|
||||||
this.emit(NetworkManager.Events.RequestFinished, request);
|
this.emit(NetworkManager.Events.RequestFinished, request);
|
||||||
}
|
}
|
||||||
let request = new Request(event.request);
|
let request = new Request(event.requestId, event.request);
|
||||||
this._idToRequest.set(event.requestId, request);
|
this._idToRequest.set(event.requestId, request);
|
||||||
this.emit(NetworkManager.Events.Request, request);
|
this.emit(NetworkManager.Events.Request, request);
|
||||||
}
|
}
|
||||||
@ -104,7 +104,7 @@ class NetworkManager extends EventEmitter {
|
|||||||
// FileUpload sends a response without a matching request.
|
// FileUpload sends a response without a matching request.
|
||||||
if (!request)
|
if (!request)
|
||||||
return;
|
return;
|
||||||
let response = new Response(request, event.response, this._getResponseBody.bind(this, event.requestId));
|
let response = new Response(this._client, request, event.response);
|
||||||
request._response = response;
|
request._response = response;
|
||||||
this.emit(NetworkManager.Events.Response, response);
|
this.emit(NetworkManager.Events.Response, response);
|
||||||
}
|
}
|
||||||
@ -118,6 +118,7 @@ class NetworkManager extends EventEmitter {
|
|||||||
// @see https://github.com/GoogleChrome/puppeteer/issues/168
|
// @see https://github.com/GoogleChrome/puppeteer/issues/168
|
||||||
if (!request)
|
if (!request)
|
||||||
return;
|
return;
|
||||||
|
request._completePromiseFulfill.call(null);
|
||||||
this._idToRequest.delete(event.requestId);
|
this._idToRequest.delete(event.requestId);
|
||||||
this.emit(NetworkManager.Events.RequestFinished, request);
|
this.emit(NetworkManager.Events.RequestFinished, request);
|
||||||
}
|
}
|
||||||
@ -131,26 +132,22 @@ class NetworkManager extends EventEmitter {
|
|||||||
// @see https://github.com/GoogleChrome/puppeteer/issues/168
|
// @see https://github.com/GoogleChrome/puppeteer/issues/168
|
||||||
if (!request)
|
if (!request)
|
||||||
return;
|
return;
|
||||||
|
request._completePromiseFulfill.call(null);
|
||||||
this._idToRequest.delete(event.requestId);
|
this._idToRequest.delete(event.requestId);
|
||||||
this.emit(NetworkManager.Events.RequestFailed, request);
|
this.emit(NetworkManager.Events.RequestFailed, request);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} requestId
|
|
||||||
* @return {!Promise<!Buffer>}
|
|
||||||
*/
|
|
||||||
async _getResponseBody(requestId) {
|
|
||||||
let response = await this._client.send('Network.getResponseBody', {requestId});
|
|
||||||
return Buffer.from(response.body, response.base64Encoded ? 'base64' : 'utf8');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Request {
|
class Request {
|
||||||
/**
|
/**
|
||||||
* @param {!Object} payload
|
* @param {!Object} payload
|
||||||
*/
|
*/
|
||||||
constructor(payload) {
|
constructor(requestId, payload) {
|
||||||
|
this._requestId = requestId;
|
||||||
this._response = null;
|
this._response = null;
|
||||||
|
this._completePromise = new Promise(fulfill => {
|
||||||
|
this._completePromiseFulfill = fulfill;
|
||||||
|
});
|
||||||
this.url = payload.url;
|
this.url = payload.url;
|
||||||
this.method = payload.method;
|
this.method = payload.method;
|
||||||
this.postData = payload.postData;
|
this.postData = payload.postData;
|
||||||
@ -168,14 +165,15 @@ helper.tracePublicAPI(Request);
|
|||||||
|
|
||||||
class Response {
|
class Response {
|
||||||
/**
|
/**
|
||||||
|
* @param {!Connection} client
|
||||||
* @param {?Request} request
|
* @param {?Request} request
|
||||||
* @param {!Object} payload
|
* @param {!Object} payload
|
||||||
* @param {function():!Promise<!Buffer>} contentCallback
|
|
||||||
*/
|
*/
|
||||||
constructor(request, payload, contentCallback) {
|
constructor(client, request, payload) {
|
||||||
|
this._client = client;
|
||||||
this._request = request;
|
this._request = request;
|
||||||
this._contentCallback = contentCallback;
|
|
||||||
this._contentPromise = null;
|
this._contentPromise = null;
|
||||||
|
|
||||||
this.headers = new Map(Object.entries(payload.headers));
|
this.headers = new Map(Object.entries(payload.headers));
|
||||||
this.ok = payload.status >= 200 && payload.status <= 299;
|
this.ok = payload.status >= 200 && payload.status <= 299;
|
||||||
this.status = payload.status;
|
this.status = payload.status;
|
||||||
@ -187,8 +185,14 @@ class Response {
|
|||||||
* @return {!Promise<!Buffer>}
|
* @return {!Promise<!Buffer>}
|
||||||
*/
|
*/
|
||||||
buffer() {
|
buffer() {
|
||||||
if (!this._contentPromise)
|
if (!this._contentPromise) {
|
||||||
this._contentPromise = this._contentCallback();
|
this._contentPromise = this._request._completePromise.then(async() => {
|
||||||
|
let response = await this._client.send('Network.getResponseBody', {
|
||||||
|
requestId: this._request._requestId
|
||||||
|
});
|
||||||
|
return Buffer.from(response.body, response.base64Encoded ? 'base64' : 'utf8');
|
||||||
|
});
|
||||||
|
}
|
||||||
return this._contentPromise;
|
return this._contentPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
29
test/test.js
29
test/test.js
@ -1178,6 +1178,35 @@ describe('Puppeteer', function() {
|
|||||||
expect(await response.text()).toBe('{"foo": "bar"}\n');
|
expect(await response.text()).toBe('{"foo": "bar"}\n');
|
||||||
expect(await response.json()).toEqual({foo: 'bar'});
|
expect(await response.json()).toEqual({foo: 'bar'});
|
||||||
}));
|
}));
|
||||||
|
it('Page.Events.Response should not report body unless request is finished', SX(async() => {
|
||||||
|
await page.navigate(EMPTY_PAGE);
|
||||||
|
// Setup server to trap request.
|
||||||
|
let serverResponse = null;
|
||||||
|
server.setRoute('/get', (req, res) => {
|
||||||
|
serverResponse = res;
|
||||||
|
res.write('hello ');
|
||||||
|
});
|
||||||
|
// Setup page to trap response.
|
||||||
|
let pageResponse = null;
|
||||||
|
let requestFinished = false;
|
||||||
|
page.on('response', r => pageResponse = r);
|
||||||
|
page.on('requestfinished', () => requestFinished = true);
|
||||||
|
// send request and wait for server response
|
||||||
|
page.evaluate(() => fetch('./get', { method: 'GET'}));
|
||||||
|
await waitForEvents(page, 'response');
|
||||||
|
|
||||||
|
expect(serverResponse).toBeTruthy();
|
||||||
|
expect(pageResponse).toBeTruthy();
|
||||||
|
expect(pageResponse.status).toBe(200);
|
||||||
|
expect(requestFinished).toBe(false);
|
||||||
|
|
||||||
|
let responseText = pageResponse.text();
|
||||||
|
// Write part of the response and wait for it to be flushed.
|
||||||
|
await new Promise(x => serverResponse.write('wor', x));
|
||||||
|
// Finish response.
|
||||||
|
await new Promise(x => serverResponse.end('ld!', x));
|
||||||
|
expect(await responseText).toBe('hello world!');
|
||||||
|
}));
|
||||||
it('Page.Events.RequestFailed', SX(async function() {
|
it('Page.Events.RequestFailed', SX(async function() {
|
||||||
page.setRequestInterceptor(request => {
|
page.setRequestInterceptor(request => {
|
||||||
if (request.url.endsWith('css'))
|
if (request.url.endsWith('css'))
|
||||||
|
Loading…
Reference in New Issue
Block a user