Skip to content
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
9 changes: 6 additions & 3 deletions lib/headers.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,12 @@ module.exports = {
},
getCookieNames: headers => {
const cookies = headers.filter(h => h.name.match(/^set-cookie$/i));
const cookieNames = cookies.map(h => {
return h.value.split('=')[0];
});
// Some HARs concatenate multiple Set-Cookie response headers into
// one value joined by '\n'. Split on the newline so every cookie's
// name is captured, not just the first one.
const cookieNames = cookies.flatMap(h =>
h.value.split('\n').map(c => c.split('=')[0])
);
return cookieNames;
},
getThirdPartyCookieNames: (headers, regex) => {
Expand Down
2 changes: 1 addition & 1 deletion lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ module.exports = {
const mainDomain = util.getMainDomain(baseDomain);
// Hack for ... Wikipedia!
if (mainDomain === 'wikipedia') {
firstParty = '(.*wikipedia.*||.*wikimedia.*)';
firstParty = '(.*wikipedia.*|.*wikimedia.*)';
} else {
firstParty = '.*' + mainDomain + '.*';
}
Expand Down
56 changes: 56 additions & 0 deletions test/firstPartyTest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
'use strict';

const test = require('ava');
const pagexray = require('../lib/index');

function entry(url, mimeType) {
return {
pageref: 'page_0',
startedDateTime: '2024-01-01T00:00:00.000Z',
time: 10,
request: { method: 'GET', url, headers: [] },
response: {
status: 200,
httpVersion: 'http/1.1',
headersSize: 0,
bodySize: 0,
content: { mimeType, size: 0 },
headers: [],
redirectURL: ''
},
timings: {}
};
}

test('First party (wikipedia): non-wikipedia hosts must be classified as third party', t => {
// The auto-derived firstParty regex for wikipedia used to be
// '(.*wikipedia.*||.*wikimedia.*)' — the empty alternative made it
// match every URL, so a Google Analytics request on a Wikipedia page
// was wrongly counted as first-party.
const har = {
log: {
creator: { name: 'Browsertime' },
browser: { name: 'chrome', version: '1' },
pages: [
{
id: 'page_0',
startedDateTime: '2024-01-01T00:00:00.000Z',
title: 'wikipedia',
pageTimings: { onLoad: 1000, onContentLoad: 800 }
}
],
entries: [
entry('https://en.wikipedia.org/', 'text/html'),
entry('https://upload.wikimedia.org/logo.png', 'image/png'),
entry(
'https://www.google-analytics.com/analytics.js',
'application/javascript'
)
]
}
};

const page = pagexray.convert(har)[0];
t.is(page.firstParty.requests, 2, 'wikipedia + wikimedia are first-party');
t.is(page.thirdParty.requests, 1, 'google-analytics is third-party');
});
11 changes: 11 additions & 0 deletions test/headersTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,17 @@ test('getThirdPartyCookieNames: skip cookies whose domain matches first-party',
);
});

test('getCookieNames: capture every cookie when Set-Cookie values are newline-joined', t => {
// Mirrors the getThirdPartyCookieNames newline fix: some HARs
// concatenate multiple Set-Cookie response headers into one value
// joined by '\n'. Splitting on '=' alone would only return the first
// cookie's name and under-count page.cookies.
const harHeaders = [
{name: 'Set-Cookie', value: 'UID=abc; Domain=.example.com\nUIDR=1453756870'}
];
t.deepEqual(headers.getCookieNames(harHeaders), ['UID', 'UIDR']);
});

test('getThirdPartyCookieNames: do not let a newline-joined cookie leak into the domain', t => {
// Some HARs concatenate two Set-Cookie headers into a single value
// joined by '\n'. The captured Domain= attribute must stop at the
Expand Down