This example adds an ondata
listener which replaces "WebExtension Example" in the response with "WebExtension WebExtension Example" using the replace()
method.
Note: This example only works for occurrences of "WebExtension Example" that are entirely contained within a data chunk, and not ones that straddle two chunks (which might happen ~0.1% of the time for large documents). Additionally it only deals with UTF-8-coded documents. A real implementation of this would have to be more complex.
function listener(details) {
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});
str = str.replace(/WebExtension Example/g, 'WebExtension WebExtension Example');
filter.write(encoder.encode(str));
}
filter.onstop = event => {
filter.close();
}
}
browser.webRequest.onBeforeRequest.addListener(
listener,
{urls: ["https://example.com/*"], types: ["main_frame"]},
["blocking"]
);
Another example for handling large documents:
function listener(details) {
let filter = browser.webRequest.filterResponseData(details.requestId);
let decoder = new TextDecoder("utf-8");
let encoder = new TextEncoder();
let data = [];
filter.ondata = event => {
data.push(event.data);
};
filter.onstop = event => {
let str = "";
if (data.length == 1) {
str = decoder.decode(data[0]);
}
else {
for (let i = 0; i < data.length; i++) {
let stream = (i == data.length - 1) ? false : true;
str += decoder.decode(data[i], {stream});
}
}
str = str.replace(/WebExtension Example/g, 'WebExtension $&');
filter.write(encoder.encode(str));
filter.close();
};
}
browser.webRequest.onBeforeRequest.addListener(
listener,
{urls: ["https://example.com/"], types: ["main_frame"]},
["blocking"]
);
Here's another version:
function listener(details) {
let filter = browser.webRequest.filterResponseData(details.requestId);
let decoder = new TextDecoder("utf-8");
let encoder = new TextEncoder();
let data = [];
filter.ondata = event => {
data.push(event.data);
};
filter.onstop = event => {
let str = "";
for (let buffer of data) {
str += decoder.decode(buffer, {stream: true});
}
str += decoder.decode();
str = str.replace(/WebExtension Example/g, 'WebExtension $&');
filter.write(encoder.encode(str));
filter.close();
};
}
browser.webRequest.onBeforeRequest.addListener(
listener,
{urls: ["https://example.com/"], types: ["main_frame"]},
["blocking"]
);
The above example can also be written like so:
function listener(details) {
let filter = browser.webRequest.filterResponseData(details.requestId);
let decoder = new TextDecoder("utf-8");
let encoder = new TextEncoder();
let data = [];
filter.ondata = event => {
data.push(decoder.decode(event.data, {stream: true}));
};
filter.onstop = event => {
data.push(decoder.decode());
let str = data.join("");
str = str.replace(/WebExtension Example/g, 'WebExtension $&');
filter.write(encoder.encode(str));
filter.close();
};
}
browser.webRequest.onBeforeRequest.addListener(
listener,
{urls: ["https://example.com/"], types: ["main_frame"]},
["blocking"]
);
This example uses a Blob
:
function listener(details) {
let filter = browser.webRequest.filterResponseData(details.requestId);
let encoder = new TextEncoder();
let data = [];
filter.ondata = event => {
data.push(event.data);
};
filter.onstop = async event => {
let blob = new Blob(data, {type: 'text/html'});
let str = await blob.text();
str = str.replace(/WebExtension Example/g, 'WebExtension $&');
filter.write(encoder.encode(str));
filter.close();
};
}
browser.webRequest.onBeforeRequest.addListener(
listener,
{urls: ["https://example.com/"], types: ["main_frame"]},
["blocking"]
);
This example makes use of the DOMParser
interface:
function listener(details) {
let filter = browser.webRequest.filterResponseData(details.requestId);
let encoder = new TextEncoder();
let parser = new DOMParser();
let data = [];
filter.ondata = event => {
data.push(event.data);
};
filter.onstop = async event => {
let blob = new Blob(data, {type: 'text/html'});
let str = await blob.text();
let doc = parser.parseFromString(str, blob.type);
let nodes = doc.querySelectorAll("title, h1");
for (let node of nodes) {
node.innerText = node.innerText.replace('WebExtension Example', 'WebExtension $&');
}
filter.write(encoder.encode(doc.documentElement.outerHTML));
filter.close();
};
}
browser.webRequest.onBeforeRequest.addListener(
listener,
{urls: ["https://example.com/"], types: ["main_frame"]},
["blocking"]
);
This example combines all buffers into a single buffer:
function listener(details) {
let filter = browser.webRequest.filterResponseData(details.requestId);
let decoder = new TextDecoder("utf-8");
let encoder = new TextEncoder();
let data = [];
filter.ondata = event => {
data.push(new Uint8Array(event.data));
};
filter.onstop = event => {
let combinedLength = 0;
for (let buffer of data) {
combinedLength += buffer.length;
}
let combinedArray = new Uint8Array(combinedLength);
let writeOffset = 0;
for (let buffer of data) {
combinedArray.set(buffer, writeOffset);
writeOffset += buffer.length;
}
let str = decoder.decode(combinedArray);
str = str.replace(/WebExtension Example/g, 'WebExtension $&');
filter.write(encoder.encode(str));
filter.close();
};
}
browser.webRequest.onBeforeRequest.addListener(
listener,
{urls: ["https://example.com/"], types: ["main_frame"]},
["blocking"]
);
The above example can also be written like so:
function listener(details) {
let filter = browser.webRequest.filterResponseData(details.requestId);
let decoder = new TextDecoder('utf-8');
let encoder = new TextEncoder();
let data = [];
filter.ondata = event => {
data.push(event.data);
};
filter.onstop = async event => {
let blob = new Blob(data, {type: 'text/html'});
let buffer = await blob.arrayBuffer();
let str = decoder.decode(buffer);
str = str.replace(/WebExtension Example/g, 'WebExtension $&');
filter.write(encoder.encode(str));
filter.close();
};
}
browser.webRequest.onBeforeRequest.addListener(
listener,
{urls: ["https://example.com/"], types: ["main_frame"]},
["blocking"]
);
This example demonstrates, how one can detect, if it's the final chunk in the response:
function listener(details) {
let filter = browser.webRequest.filterResponseData(details.requestId);
let encoder = new TextEncoder();
let decoder = new TextDecoder("utf-8");
let str = "";
filter.ondata = event => {
let stream = true;
let data = new Uint8Array(event.data.slice(-8, -1));
if (String.fromCharCode(...data) == "</html>") {
stream = false;
}
str += decoder.decode(event.data, {stream});
};
filter.onstop = event => {
str = str.replace(/WebExtension Example/g, 'WebExtension $&');
filter.write(encoder.encode(str));
filter.close();
};
}
browser.webRequest.onBeforeRequest.addListener(
listener,
{urls: ["https://example.com/"], types: ["main_frame"]},
["blocking"]
);