Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 22x 22x 22x 22x 22x 19x 19x 19x 19x 19x 22x 22x 22x 22x 22x 22x 22x 22x 22x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 2x 6x 4x 4x 6x 22x 22x 22x | // Wraps globalThis.fetch with a simple cookie jar so HTTP-only cookies
// set by the server are replayed on subsequent requests — mirrors what
// browsers do automatically but Node.js does not.
const jar = new Map(); // origin → { name: value }
const _fetch = globalThis.fetch;
globalThis.fetch = async function (url, options = {}) {
const origin = new URL(url).origin;
// Inject stored cookies for this origin
const stored = jar.get(origin);
if (stored && Object.keys(stored).length > 0) {
const cookieStr = Object.entries(stored)
.map(([k, v]) => `${k}=${v}`)
.join('; ');
options = { ...options, headers: { ...options.headers, Cookie: cookieStr } };
}
const response = await _fetch(url, options);
// Capture Set-Cookie headers (getSetCookie() returns each header separately,
// avoiding the comma-in-Expires parsing problem)
const setCookies = response.headers.getSetCookie?.() ??
[response.headers.get('set-cookie')].filter(Boolean);
for (const raw of setCookies) {
const nameVal = raw.split(';')[0].trim();
const eq = nameVal.indexOf('=');
if (eq < 1) continue;
const name = nameVal.slice(0, eq).trim();
const value = nameVal.slice(eq + 1).trim();
const attrs = raw.toLowerCase();
const isDeleted = attrs.includes('max-age=0') ||
attrs.includes('expires=thu, 01 jan 1970');
if (!jar.has(origin)) jar.set(origin, {});
if (isDeleted) {
delete jar.get(origin)[name];
} else {
jar.get(origin)[name] = value;
}
}
return response;
};
|