Skip to content

Commit

Permalink
core(driver): add timeout to getRequestContent (#4718)
Browse files Browse the repository at this point in the history
  • Loading branch information
paulirish committed Mar 15, 2018
1 parent fd35606 commit bd1dd3d
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 5 deletions.
23 changes: 18 additions & 5 deletions lighthouse-core/gather/driver.js
Expand Up @@ -9,6 +9,7 @@
const NetworkRecorder = require('../lib/network-recorder');
const emulation = require('../lib/emulation');
const Element = require('../lib/element');
const LHError = require('../lib/errors');
const EventEmitter = require('events').EventEmitter;
const URL = require('../lib/url-shim');
const TraceParser = require('../lib/traces/trace-parser');
Expand Down Expand Up @@ -714,13 +715,25 @@ class Driver {
/**
* Return the body of the response with the given ID.
* @param {string} requestId
* @param {number|undefined} timeout
* @return {string}
*/
getRequestContent(requestId) {
return this.sendCommand('Network.getResponseBody', {
requestId,
// Ignoring result.base64Encoded, which indicates if body is already encoded
}).then(result => result.body);
getRequestContent(requestId, timeout = 1000) {
return new Promise((resolve, reject) => {
// If this takes more than 1s, reject the Promise.
// Why? Encoding issues can lead to hanging getResponseBody calls: https://github.com/GoogleChrome/lighthouse/pull/4718
const err = new LHError(LHError.errors.REQUEST_CONTENT_TIMEOUT);
const asyncTimeout = setTimeout((_ => reject(err)), timeout);

this.sendCommand('Network.getResponseBody', {requestId}).then(result => {
clearTimeout(asyncTimeout);
// Ignoring result.base64Encoded, which indicates if body is already encoded
resolve(result.body);
}).catch(e => {
clearTimeout(asyncTimeout);
reject(e);
});
});
}

/**
Expand Down
3 changes: 3 additions & 0 deletions lighthouse-core/lib/errors.js
Expand Up @@ -88,6 +88,9 @@ const ERRORS = {
TRACING_ALREADY_STARTED: {message: strings.internalChromeError, pattern: /Tracing.*started/},
PARSING_PROBLEM: {message: strings.internalChromeError, pattern: /Parsing problem/},
READ_FAILED: {message: strings.internalChromeError, pattern: /Read failed/},

// Protocol timeout failures
REQUEST_CONTENT_TIMEOUT: {message: strings.requestContentTimeout},
};

Object.keys(ERRORS).forEach(code => ERRORS[code].code = code);
Expand Down
1 change: 1 addition & 0 deletions lighthouse-core/lib/strings.js
Expand Up @@ -12,4 +12,5 @@ module.exports = {
pageLoadTookTooLong: `Your page took too long to load. Please follow the opportunities in the report to reduce your page load time, and then try re-running Lighthouse.`,
pageLoadFailed: `Your page failed to load. Verify that the URL is valid and re-run Lighthouse.`,
internalChromeError: `An internal Chrome error occurred. Please restart Chrome and try re-running Lighthouse.`,
requestContentTimeout: 'Fetching resource content has exceeded the allotted time',
};
11 changes: 11 additions & 0 deletions lighthouse-core/test/gather/driver-test.js
Expand Up @@ -17,6 +17,7 @@ const connection = new Connection();
const driverStub = new Driver(connection);

const redirectDevtoolsLog = require('../fixtures/wikipedia-redirect.devtoolslog.json');
const MAX_WAIT_FOR_PROTOCOL = 20;

function createOnceStub(events) {
return (eventName, cb) => {
Expand Down Expand Up @@ -75,6 +76,8 @@ connection.sendCommand = function(command, params) {
return Promise.resolve({frameTree: {frame: {id: 1}}});
case 'Page.createIsolatedWorld':
return Promise.resolve({executionContextId: 1});
case 'Network.getResponseBody':
return new Promise(res => setTimeout(res, MAX_WAIT_FOR_PROTOCOL + 20));
case 'Page.enable':
case 'Tracing.start':
case 'ServiceWorker.enable':
Expand Down Expand Up @@ -138,6 +141,14 @@ describe('Browser Driver', () => {
});
});

it('throws if getRequestContent takes too long', () => {
return driverStub.getRequestContent(0, MAX_WAIT_FOR_PROTOCOL).then(_ => {
assert.ok(false, 'long-running getRequestContent supposed to reject');
}, e => {
assert.equal(e.code, 'REQUEST_CONTENT_TIMEOUT');
});
});

it('evaluates an expression', () => {
return driverStub.evaluateAsync('120 + 3').then(value => {
assert.deepEqual(value, 123);
Expand Down

0 comments on commit bd1dd3d

Please sign in to comment.