I'm trying to define a new filetype for the web, which is rendered to HTML via a browser extension. What I would like to do is have the server return files in my filetype with the HTTP header "Content-Type: text/mytype". The extension will inspect the response headers, and if the content-type matches text/mytype, it will intercept the response body and replace it with the rendered HTML. This gives us a filetype that interacts nicely with the web if you have the plugin installed.
As a proof of concept, I created a plugin working which intercepts the headers and renders them into the response, but it only works if the content-type is text/html. If I change the response content type to text/mytype on the server, Firefox downloads the file, seemingly without running my extension code at all.
Is there a different event I should be listening to, in order to intercept/change headers before and run extension code instead of just downloading the file?
Here's my code:
manifest.json:
{
"description": "Altering HTTP responses",
"manifest_version": 2,
"name": "http-response-filter",
"version": "1.0",
"homepage_url": "https://github.com/mdn/webextensions-examples/tree/master/http-response",
"icons": {
"48": "pen.svg"
},
"permissions": [
"webRequest", "webRequestBlocking", "<all_urls>"
],
"background": {
"scripts": ["background.js"]
},
"browser_specific_settings": {
"gecko": {
"strict_min_version": "57.0a1"
}
}
}
background.js:
var contentType;
function contentListener(details) {
//if(contentType === 'text/mytype') {
let filter = browser.webRequest.filterResponseData(details.requestId);
let decoder = new TextDecoder("utf-8");
let encoder = new TextEncoder();
filter.ondata = event => {
let str = decoder.decode(event.data, {stream: true});
// Later I want to replace this line with code that parses the
// document and renders it to HTML
str = str.replace(/Example/g, 'Content-Type: ' + contentType);
filter.write(encoder.encode(str));
filter.disconnect();
}
//}
return {};
}
browser.webRequest.onBeforeRequest.addListener(
contentListener,
{urls: ["<all_urls>"], types: ["main_frame"]},
["blocking"]
);
function headersListener(details) {
let headers = details.responseHeaders;
for(var i = 0; i < headers.length; i++) {
if(headers[i].name.toLowerCase() === 'content-type') {
contentType = headers[i].value;
// Try setting the content type to HTML to prevent downloading--
// doesn't work
headers[i].value = 'text/html; charset=utf-8';
}
}
browser.webRequest.onBeforeRequest.addListener(
contentListener,
{urls: ["<all_urls>"], types: ["main_frame"]},
["blocking"]
);
}
browser.webRequest.onHeadersReceived.addListener(
headersListener, {
urls: ["<all_urls>"],
types: ["main_frame"]
}, ["blocking", "responseHeaders"]
);