Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

core(network-recorder): handle QUIC requests #5256

Merged
merged 3 commits into from
May 19, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions lighthouse-core/lib/network-recorder.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,19 @@ class NetworkRecorder extends EventEmitter {
}
}

/**
* QUIC network requests don't always "finish" even when they're done loading data, use recievedHeaders
* @see https://github.com/GoogleChrome/lighthouse/issues/5254
* @param {LH.WebInspector.NetworkRequest} record
* @return {boolean}
*/
static _isQUICAndFinished(record) {
const isQUIC = record._responseHeaders && record._responseHeaders
.some(header => header.name.toLowerCase() === 'alt-svc' && /quic/.test(header.value));
const receivedHeaders = record._timing && record._timing.receiveHeadersEnd > 0;
return !!(isQUIC && receivedHeaders && record.endTime);
}

/**
* Finds all time periods where the number of inflight requests is less than or equal to the
* number of allowed concurrent requests.
Expand All @@ -109,7 +122,7 @@ class NetworkRecorder extends EventEmitter {

// convert the network record timestamp to ms
timeBoundaries.push({time: record.startTime * 1000, isStart: true});
if (record.finished) {
if (record.finished || NetworkRecorder._isQUICAndFinished(record)) {
timeBoundaries.push({time: record.endTime * 1000, isStart: false});
}
});
Expand Down Expand Up @@ -143,7 +156,7 @@ class NetworkRecorder extends EventEmitter {
quietPeriods.push({start: quietPeriodStart, end: endTime});
}

return quietPeriods;
return quietPeriods.filter(period => period.start !== period.end);
}

/**
Expand Down
92 changes: 92 additions & 0 deletions lighthouse-core/test/gather/network-recorder-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,96 @@ describe('network recorder', function() {
const records = NetworkRecorder.recordsFromLogs(devtoolsLogItems);
assert.equal(records.length, 76);
});

describe('#findNetworkQuietPeriods', () => {
function record(data) {
const url = data.url || 'https://example.com';
const scheme = url.split(':')[0];
return Object.assign({
url,
finished: !!data.endTime,
parsedURL: {scheme},
}, data);
}

it('should find the 0-quiet periods', () => {
const records = [
record({startTime: 0, endTime: 1}),
record({startTime: 2, endTime: 3}),
record({startTime: 4, endTime: 5}),
];

const periods = NetworkRecorder.findNetworkQuietPeriods(records, 0);
assert.deepStrictEqual(periods, [
{start: 1000, end: 2000},
{start: 3000, end: 4000},
{start: 5000, end: Infinity},
]);
});

it('should find the 2-quiet periods', () => {
const records = [
record({startTime: 0, endTime: 1.5}),
record({startTime: 0, endTime: 2}),
record({startTime: 0, endTime: 2.5}),
record({startTime: 2, endTime: 3}),
record({startTime: 4, endTime: 5}),
];

const periods = NetworkRecorder.findNetworkQuietPeriods(records, 2);
assert.deepStrictEqual(periods, [
{start: 1500, end: Infinity},
]);
});

it('should handle unfinished requests', () => {
const records = [
record({startTime: 0, endTime: 1.5}),
record({startTime: 0, endTime: 2}),
record({startTime: 0, endTime: 2.5}),
record({startTime: 2, endTime: 3}),
record({startTime: 2}),
record({startTime: 2}),
record({startTime: 4, endTime: 5}),
record({startTime: 5.5}),
];

const periods = NetworkRecorder.findNetworkQuietPeriods(records, 2);
assert.deepStrictEqual(periods, [
{start: 1500, end: 2000},
{start: 3000, end: 4000},
{start: 5000, end: 5500},
]);
});

it('should ignore data URIs', () => {
const records = [
record({startTime: 0, endTime: 1}),
record({startTime: 0, endTime: 2, url: 'data:image/png;base64,'}),
];

const periods = NetworkRecorder.findNetworkQuietPeriods(records, 0);
assert.deepStrictEqual(periods, [
{start: 1000, end: Infinity},
]);
});

it('should handle QUIC requests', () => {
const quicRequest = {
finished: false,
_responseHeaders: [{name: 'ALT-SVC', value: 'hq=":49288";quic="1,1abadaba,51303334,0"'}],
_timing: {receiveHeadersEnd: 1.28},
};

const records = [
record({startTime: 0, endTime: 1}),
record({startTime: 0, endTime: 2, ...quicRequest}),
];

const periods = NetworkRecorder.findNetworkQuietPeriods(records, 0);
assert.deepStrictEqual(periods, [
{start: 2000, end: Infinity},
]);
});
});
});