Skip to content

Commit

Permalink
A better header structure easier to work with (#98)
Browse files Browse the repository at this point in the history
  • Loading branch information
soulgalore authored Dec 12, 2020
1 parent ba3d118 commit 4d4d63e
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 37 deletions.
13 changes: 6 additions & 7 deletions lib/collect.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ module.exports = {
const response = entry.response;
const request = entry.request;
const contentType = util.getContentType(response.content.mimeType);
const responseHeadersFlatten = headers.flatten(response.headers);
const content =
response.content && response.content.text ? response.content.text : '';
const timings = {
Expand All @@ -64,27 +63,27 @@ module.exports = {
timings.wait +
timings.receive;

const responseHeaders = headers.flatten(response.headers);
const requestHeaders = headers.flatten(request.headers);
return {
type: contentType,
url: request.url,
transferSize: response.bodySize,
contentSize:
response.content.size < 0 ? response.bodySize : response.content.size,
headerSize: response.headersSize,
expires: headers.getExpires(responseHeadersFlatten),
expires: headers.getExpires(responseHeaders),
status: response.status,
timeSinceLastModified: headers.getTimeSinceLastModified(
responseHeadersFlatten
),
timeSinceLastModified: headers.getTimeSinceLastModified(responseHeaders),
cookieNames: headers.getCookieNames(response.headers),
cookieNamesThirdParties: headers.getThirdPartyCookieNames(
response.headers,
firstParty
),
httpVersion: util.getHTTPVersion(response.httpVersion),
headers: {
request: request.headers,
response: response.headers
request: requestHeaders,
response: responseHeaders
},
totalTime,
timings,
Expand Down
38 changes: 25 additions & 13 deletions lib/headers.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,11 @@ module.exports = {
*/
flatten: headers => {
const theHeaders = headers.reduce((result, header) => {
result[header.name.toLowerCase()] = header.value;
if (!result[header.name.toLowerCase()]) {
result[header.name.toLowerCase()] = [header.value];
} else {
result[header.name.toLowerCase()].push(header.value);
}
return result;
}, {});
return theHeaders;
Expand All @@ -45,17 +49,17 @@ module.exports = {

if (responseHeaders['cache-control']) {
if (
responseHeaders['cache-control'].indexOf('no-cache') !== -1 ||
responseHeaders['cache-control'].indexOf('no-store') !== -1
responseHeaders['cache-control'][0].indexOf('no-cache') !== -1 ||
responseHeaders['cache-control'][0].indexOf('no-store') !== -1
) {
return 0;
}
const matches = responseHeaders['cache-control'].match(maxAgeRegExp);
const matches = responseHeaders['cache-control'][0].match(maxAgeRegExp);
if (matches) {
return parseInt(matches[1], 10);
}
} else if (responseHeaders.expires) {
const expiresMillis = parseHttpDate(responseHeaders.expires);
const expiresMillis = parseHttpDate(responseHeaders.expires[0]);

if (isFinite(expiresMillis))
expireSeconds = (expiresMillis - Date.now()) / 1000;
Expand All @@ -69,17 +73,25 @@ module.exports = {
* @returns {int} the time since the asset was last modified in seconds.
*/
getTimeSinceLastModified: headers => {
const lastModifiedMillis = parseHttpDate(headers['last-modified']);
if (headers['last-modified']) {
const lastModifiedMillis = parseHttpDate(headers['last-modified'][0]);

if (!isFinite(lastModifiedMillis)) {
return -1;
}
if (headers.date) {
let dateMillis = parseHttpDate(headers.date[0]);
if (!isFinite(dateMillis)) {
dateMillis = Date.now();
}

if (!isFinite(lastModifiedMillis)) {
return (dateMillis - lastModifiedMillis) / 1000;
} else {
return (Date.now() - lastModifiedMillis) / 1000;
}
} else {
return -1;
}
let dateMillis = parseHttpDate(headers.date);
if (!isFinite(dateMillis)) {
dateMillis = Date.now();
}

return (dateMillis - lastModifiedMillis) / 1000;
},
getCookieNames: headers => {
const cookies = headers.filter(h => h.name.match(/^set-cookie$/i));
Expand Down
38 changes: 21 additions & 17 deletions test/headersTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,15 @@ describe('headers', function() {
}, {
name: 'HEADER3',
value: 'value3'
},
{
name: 'HEADER3',
value: 'value4'
}];
var expected = {
'header1': 'value1',
'header2': 'value2',
'header3': 'value3'
'header1': ['value1'],
'header2': ['value2'],
'header3': ['value3','value4']
};

var flattenedHeaders = headers.flatten(harHeaders);
Expand All @@ -36,32 +40,32 @@ describe('headers', function() {
});

it('should return -1 for invalid last-modified header', () => {
const requestHeaders = {'last-modified': 'xyz'};
const requestHeaders = {'last-modified': ['xyz']};
const timeSinceLastModified = headers.getTimeSinceLastModified(requestHeaders);
assert.equal(timeSinceLastModified, -1);
});

it('should return positive time with only last-modified header', () => {
const requestHeaders = {
'last-modified': 'Wed, 26 Aug 2015 12:37:50 GMT'
'last-modified': ['Wed, 26 Aug 2015 12:37:50 GMT']
};
const timeSinceLastModified = headers.getTimeSinceLastModified(requestHeaders);
assert.isTrue(timeSinceLastModified > 0);
});

it('should handle invalid date header', () => {
const requestHeaders = {
'last-modified': 'Wed, 26 Aug 2025 12:37:50 GMT',
'date': 'Wedding'
'last-modified': ['Wed, 26 Aug 2025 12:37:50 GMT'],
'date': ['Wedding']
};
const timeSinceLastModified = headers.getTimeSinceLastModified(requestHeaders);
assert.isTrue(timeSinceLastModified < 0);
});

it('should calculate diff between last-modified and date headers', () => {
const requestHeaders = {
'last-modified': 'Wed, 26 Aug 2015 12:37:50 GMT',
'date': 'Wed, 26 Aug 2015 12:37:51 GMT'
'last-modified': ['Wed, 26 Aug 2015 12:37:50 GMT'],
'date': ['Wed, 26 Aug 2015 12:37:51 GMT']
};
const timeSinceLastModified = headers.getTimeSinceLastModified(requestHeaders);
assert.equal(timeSinceLastModified, 1);
Expand All @@ -75,44 +79,44 @@ describe('headers', function() {
assert.equal(expires, 0);
});
it('should return 0 for when cache-control is no-cache', () => {
const responseHeaders = {'cache-control': 'no-cache'};
const responseHeaders = {'cache-control': ['no-cache']};
const expires = headers.getExpires(responseHeaders);
assert.equal(expires, 0);
});
it('should return 0 for when cache-control is no-store', () => {
const responseHeaders = {'cache-control': 'no-store'};
const responseHeaders = {'cache-control': ['no-store']};
const expires = headers.getExpires(responseHeaders);
assert.equal(expires, 0);
});
it('should parse max-age from cache-control', () => {
const responseHeaders = {'cache-control': 'max-age=42'};
const responseHeaders = {'cache-control': ['max-age=42']};
const expires = headers.getExpires(responseHeaders);
assert.equal(expires, 42);
});
it('should handle invalid max-age from cache-control', () => {
const responseHeaders = {'cache-control': 'max-age=xyz42'};
const responseHeaders = {'cache-control': ['max-age=xyz42']};
const expires = headers.getExpires(responseHeaders);
assert.equal(expires, 0);
});
it('should handle invalid expires header', () => {
const responseHeaders = {'expires': 'xyz'};
const responseHeaders = {'expires': ['xyz']};
const expires = headers.getExpires(responseHeaders);
assert.equal(expires, 0);
});
it('should handle invalid expires header', () => {
// this example is from nytimes.com
const responseHeaders = {'expires': 'Wed Sep 15 09:14:42 MDT 2010\nThu Sep 16 15:24:47 MDT 2010'};
const responseHeaders = {'expires': ['Wed Sep 15 09:14:42 MDT 2010\nThu Sep 16 15:24:47 MDT 2010']};
const expires = headers.getExpires(responseHeaders);
assert.equal(expires, 0);
});
it('should handle numeric expires header', () => {
// this example is from nytimes.com
const responseHeaders = {'expires': '0'};
const responseHeaders = {'expires': ['0']};
const expires = headers.getExpires(responseHeaders);
assert.equal(expires, 0);
});
it('should parse valid expires header', () => {
const responseHeaders = {'expires': 'Wed, 26 Aug 2015 12:37:50 GMT'};
const responseHeaders = {'expires': ['Wed, 26 Aug 2015 12:37:50 GMT']};
const expires = headers.getExpires(responseHeaders);
assert.isTrue(expires < 0);
});
Expand Down

0 comments on commit 4d4d63e

Please sign in to comment.