openvibers/openvibe.live Commits

The shell's preloads survive a page's own Link header (#738)

OP OpenVibers committed 4 days ago · 4b07eb7bbf · 2 files, +26 −1

Changes

ddiff --git a/server/web/sw.js b/server/web/sw.js
iindex f8bfd37a..ff9d2cf6 100644
---- a/server/web/sw.js
++++ b/server/web/sw.js
@@@ -37,6 +37,20 @@ function earlyHints(res, links) {
const list = (links || []).filter((l) => l && l.href);
if (!list.length || !res || res.headersSent) return false;
const header = list.map((l) => '<' + l.href + '>; rel=preload' + (l.as ? '; as=' + l.as : '')).join(', ');
++ // A page sets its own Link later (the Markdown twin, llms.txt) and replaces the header: the preloads are merged back
++ // in when the head goes out (11-09: production's pages carried only the page's own links).
++ if (typeof res.writeHead === 'function' && typeof res.getHeader === 'function' && !res.ovHintsMerged) {
++ res.ovHintsMerged = true;
++ const writeHead = res.writeHead;
++ res.writeHead = function (...args) {
++ try {
++ const cur = res.getHeader('Link');
++ const now = Array.isArray(cur) ? cur.join(', ') : String(cur || '');
++ if (now.indexOf('rel=preload') < 0) res.setHeader('Link', now ? now + ', ' + header : header);
++ } catch { /* a hint is never worth a page */ }
++ return writeHead.apply(this, args);
++ };
++ }
try { res.setHeader('Link', header); return true; } catch { return false; }
}
ddiff --git a/test/shell.test.js b/test/shell.test.js
iindex 8f626255..70c467b1 100644
---- a/test/shell.test.js
++++ b/test/shell.test.js
@@@ -9,12 +9,23 @@ try { assets.setSharedDir(require('openvibe-shared/files').dir); } catch { /* */
const shell = require('../server/web/sw');
function fakeRes() {
-- const res = { headersSent: false, headers: {}, hints: null };
++ const res = { headersSent: false, headers: {}, hints: null, wrote: false };
res.writeEarlyHints = (h) => { res.hints = h; return true; };
res.setHeader = (k, v) => { res.headers[k] = v; };
++ res.getHeader = (k) => res.headers[k];
++ res.writeHead = () => { res.wrote = true; return res; };
return res;
}
++{ // A page that sets its own Link later (the Markdown twin, llms.txt) keeps the preloads too.
++ const res = fakeRes();
++ shell.hints()({ method: 'GET', path: '/', headers: { accept: 'text/html' } }, res, () => { });
++ res.setHeader('Link', '</index.md>; rel="alternate"; type="text/markdown"');
++ res.writeHead(200);
++ assert.ok(res.wrote);
++ assert.ok(/rel="alternate"/.test(res.headers.Link) && /rel=preload; as=script/.test(res.headers.Link), res.headers.Link);
++}
++
{ // A page is hinted in its Link header; no 103 goes out (nginx 1.28 would send the page as the 103's body).
const res = fakeRes();
let nexted = false;