83 lines
2.6 KiB
JavaScript
83 lines
2.6 KiB
JavaScript
// background.js
|
|
const blobs = new Set();
|
|
|
|
function isExtensionUrl(url) {
|
|
return url.startsWith(browser.runtime.getURL(''));
|
|
}
|
|
|
|
function viewerUrlFor(originalUrl) {
|
|
return browser.runtime.getURL('viewer.html') + '?src=' + encodeURIComponent(originalUrl);
|
|
}
|
|
|
|
// Redirect obvious .pdf URLs (but skip extension pages)
|
|
browser.webRequest.onBeforeRequest.addListener(
|
|
details => {
|
|
const url = details.url;
|
|
if (isExtensionUrl(url)) return {};
|
|
const path = url.split('?')[0].toLowerCase();
|
|
if (path.endsWith('.pdf')) {
|
|
return { redirectUrl: viewerUrlFor(details.url) };
|
|
}
|
|
return {};
|
|
},
|
|
{ urls: ["<all_urls>"], types: ["main_frame"] },
|
|
["blocking"]
|
|
);
|
|
|
|
// Redirect when response headers indicate PDF
|
|
browser.webRequest.onHeadersReceived.addListener(
|
|
details => {
|
|
const url = details.url;
|
|
if (isExtensionUrl(url)) return {};
|
|
const headers = details.responseHeaders || [];
|
|
for (let h of headers) {
|
|
if (!h.name || !h.value) continue;
|
|
const n = h.name.toLowerCase();
|
|
const v = h.value.toLowerCase();
|
|
if (n === "content-type" && v.includes("application/pdf")) {
|
|
return { redirectUrl: viewerUrlFor(details.url) };
|
|
}
|
|
// some servers force download with content-disposition
|
|
if (n === "content-disposition" && v.includes("attachment") && v.includes(".pdf")) {
|
|
return { redirectUrl: viewerUrlFor(details.url) };
|
|
}
|
|
}
|
|
return {};
|
|
},
|
|
{ urls: ["<all_urls>"], types: ["main_frame"] },
|
|
["blocking", "responseHeaders"]
|
|
);
|
|
|
|
// Message API: fetch PDF and return a blob: URL (no large binary through messaging)
|
|
browser.runtime.onMessage.addListener(async (msg) => {
|
|
if (!msg || !msg.type) return;
|
|
|
|
if (msg.type === "fetch-pdf" && msg.url) {
|
|
try {
|
|
// Ensure you have host permission for the target (manifest had "<all_urls>")
|
|
const res = await fetch(msg.url, { credentials: "include" });
|
|
if (!res.ok) {
|
|
return { error: `HTTP ${res.status} ${res.statusText}` };
|
|
}
|
|
const arrayBuffer = await res.arrayBuffer();
|
|
const contentType = res.headers.get("content-type") || "application/pdf";
|
|
const blob = new Blob([arrayBuffer], { type: contentType });
|
|
const blobUrl = URL.createObjectURL(blob);
|
|
blobs.add(blobUrl);
|
|
return { blobUrl, contentType };
|
|
} catch (err) {
|
|
return { error: String(err) };
|
|
}
|
|
}
|
|
|
|
// allow viewer to tell us to free the blob URL when it's done
|
|
if (msg.type === "revoke-blob" && msg.blobUrl) {
|
|
if (blobs.has(msg.blobUrl)) {
|
|
blobs.delete(msg.blobUrl);
|
|
try { URL.revokeObjectURL(msg.blobUrl); } catch(e) {}
|
|
return { revoked: true };
|
|
}
|
|
return { revoked: false };
|
|
}
|
|
});
|