Skip to content
Open
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
71 changes: 57 additions & 14 deletions src/rewriters/custom/head.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,27 +100,66 @@ window.history.replaceState = new Proxy(window.history.replaceState, {
},
});
(function () {
const replacedUrl = function (url) {
// Notion fires fire-and-forget telemetry and analytics to these hosts. Nooxy
// previously bounced them off the proxy via a same-origin pseudo endpoint,
// which produced a noisy 200 log line for every request. We now drop them
// entirely in the browser so no network request is made and nothing reaches
// the proxy. These responses were already discarded, so the page is unaffected.
const pathOf = function (url) {
const noScheme = url.replace(/^https?:\/\/[^\\/]*/, '');
return noScheme.split('?')[0].split('#')[0];
};

const isSuppressedUrl = function (url) {
// Same-origin Notion keepalive ping is non-essential and only adds proxy log noise.
if (pathOf(url) === '/api/v3/ping') {
return true;
}
const match = /^https?:\/\/([^\\/]*)/.exec(url);
const domain = match ? match[1] : '';
if (
// file.notion.so and file.notion.com serve signed PDF and attachment downloads.
// They are real content, not telemetry, so they must not be dropped. The blanket
// notion.so rule below would otherwise leave react-pdf with an empty body. Keep
// this comment slash-free: the converter mis-parses a bare slash as a regex.
if (domain === 'file.notion.so' || domain === 'file.notion.com') {
return false;
}
return (
(domain.endsWith('notion.so') && !domain.endsWith('msgstore.www.notion.so')) ||
domain.endsWith('splunkcloud.com') ||
domain.endsWith('statsigapi.net')
) {
// console.info('[NOOXY]', 'Suppress request:', url);
return url.replace(/^.*:(.*)\/\//, '/200/$1');
);
};

const urlOf = function (input) {
if (typeof input === 'string') {
return input;
}
// Request object
if (input && typeof input.url === 'string') {
return input.url;
}
try {
return String(input);
} catch (_e) {
return '';
}
return url;
};

window.fetch = new Proxy(window.fetch, {
apply: function (target, that, args) {
let url = args[0];
const rest = Array.prototype.slice.call(args, 1);
url = replacedUrl(url);
// console.info('[NOOXY]', 'Fetch Request:', url);
return Reflect.apply(target, that, [url].concat(rest));
if (isSuppressedUrl(urlOf(args[0]))) {
// Silently drop: resolve with a synthetic success, make no network call.
// console.info('[NOOXY]', 'Dropped request:', urlOf(args[0]));
return Promise.resolve(
new Response('{}', {
status: 200,
statusText: 'OK',
headers: { 'content-type': 'application/json' },
}),
);
}
return Reflect.apply(target, that, args);
},
});

Expand All @@ -130,10 +169,14 @@ window.history.replaceState = new Proxy(window.history.replaceState, {
xhr.open = new Proxy(xhr.open, {
apply: function (target, that, args) {
const method = args[0];
let url = args[1];
const url = args[1];
const rest = Array.prototype.slice.call(args, 2);
url = replacedUrl(url);
// console.info('[NOOXY]', 'XML Request:', url);
if (isSuppressedUrl(urlOf(url))) {
// Resolve locally via a data: URL (allowed by connect-src 'data:') so
// the request never leaves the browser and never hits the proxy.
// console.info('[NOOXY]', 'Dropped request:', urlOf(url));
return Reflect.apply(target, that, ['GET', 'data:application/json,%7B%7D'].concat(rest));
}
return Reflect.apply(target, that, [method, url].concat(rest));
},
});
Expand Down