openvibers/openvibe.live Commits
The shell's preloads survive a page's own Link header (#738)
Changes
@@@ -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; }}@@@ -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;
@@ -37,6 +37,20 @@ function earlyHints(res, links) {
@@ -37,6 +37,20 @@ function earlyHints(res, links) {
const list = (links || []).filter((l) => l && l.href);
const list = (links || []).filter((l) => l && l.href);
if (!list.length || !res || res.headersSent) return false;
if (!list.length || !res || res.headersSent) return false;
const header = list.map((l) => '<' + l.href + '>; rel=preload' + (l.as ? '; as=' + l.as : '')).join(', ');
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; }
try { res.setHeader('Link', header); return true; } catch { return false; }
}
}
@@ -9,12 +9,23 @@ try { assets.setSharedDir(require('openvibe-shared/files').dir); } catch { /* */
@@ -9,12 +9,23 @@ try { assets.setSharedDir(require('openvibe-shared/files').dir); } catch { /* */
const shell = require('../server/web/sw');
const shell = require('../server/web/sw');
function fakeRes() {
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.writeEarlyHints = (h) => { res.hints = h; return true; };
res.setHeader = (k, v) => { res.headers[k] = v; };
res.setHeader = (k, v) => { res.headers[k] = v; };
+ res.getHeader = (k) => res.headers[k];
+ res.writeHead = () => { res.wrote = true; return res; };
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).
{ // 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();
const res = fakeRes();
let nexted = false;
let nexted = false;