Fixed: HTML filter (#277)

This commit is contained in:
nobody 2021-02-21 19:13:11 +01:00
parent 9bca268a98
commit ad00d4c3a8
No known key found for this signature in database
GPG Key ID: 8F6DE3D614FCFD7A
2 changed files with 82 additions and 81 deletions

View File

@ -34,90 +34,91 @@ manipulateDOM._removeCrossOriginAndIntegrityAttr = function (details) {
console.warn('[ LocalCDN ] browser.webRequest.filterResponseData not supported by your browser.');
return;
}
if (details.statusCode === 200) {
let initiatorDomain, listedToManipulateDOM, negateHtmlFilter, filtering, header;
let initiatorDomain, listedToManipulateDOM, negateHtmlFilter, filtering, header;
initiatorDomain = helpers.extractDomainFromUrl(details.url, true) || Address.EXAMPLE;
listedToManipulateDOM = stateManager._domainIsListed(initiatorDomain, 'manipulate-dom');
negateHtmlFilter = stateManager.getInvertOption;
initiatorDomain = helpers.extractDomainFromUrl(details.url, true) || Address.EXAMPLE;
listedToManipulateDOM = stateManager._domainIsListed(initiatorDomain, 'manipulate-dom');
negateHtmlFilter = stateManager.getInvertOption;
if ((negateHtmlFilter || listedToManipulateDOM) && !(negateHtmlFilter && listedToManipulateDOM)) {
filtering = true;
} else {
filtering = false;
}
// by Jaap (https://gitlab.com/Jaaap)
header = details.responseHeaders.find((h) => h.name.toLowerCase() === 'content-type');
if (header && filtering) {
let mimeType, isAllowlisted;
mimeType = header.value.replace(/;.*/, '').toLowerCase();
isAllowlisted = stateManager._domainIsListed(initiatorDomain);
if (!isAllowlisted && mimeType === 'text/html') {
let asciiDecoder, decoder, encoder, charset, isFirstData, filter, data;
charset = (/charset\s*=/).test(header.value) && header.value.replace(/^.*?charset\s*=\s*/, '').replace(/["']?/g, '');
// Check if charset is supported by TextDecoder()
if (/charset\s*=/.test(header.value) && !EncodingTypes[charset.toString().toLowerCase()]) {
console.error(`[ LocalCDN ] Unsupported charset: ${charset}`);
return;
}
asciiDecoder = new TextDecoder('ASCII');
encoder = new TextEncoder();
isFirstData = true;
filter = browser.webRequest.filterResponseData(details.requestId);
data = [];
header.value = 'text/html; charset=UTF-8';
// NOTE: should work if 'script' string is divided into two chunks
filter.ondata = (evt) => {
if (isFirstData) {
if (!charset) {
// content-type has no charset declared
let htmlHead, charsetMatch;
htmlHead = asciiDecoder.decode(evt.data, {'stream': false});
// eslint-disable-next-line no-useless-escape
charsetMatch = htmlHead.match(/<meta.*charset=["']?([^>"'\/]+)["'].*[>\/]/i);
charset = charsetMatch ? charsetMatch[1] : 'UTF-8';
}
decoder = new TextDecoder(charset);
}
isFirstData = false;
data.push(evt.data);
};
filter.onstop = () => {
let str = '';
for (let buffer of data) {
str += decoder.decode(buffer, {'stream': true});
}
str += decoder.decode(); // end-of-stream
// remove crossorigin and integrity attributes
str = str.replace(/<(link|script)[^>]+>/ig, (m) => {
// eslint-disable-next-line no-use-before-define
if (cdnDomainsRE.test(m)) {
return m.replace(/\s+(integrity|crossorigin)(="[^"]*"|='[^']*'|=[^"'`=>\s]+|)/ig, '');
}
return m;
});
filter.write(encoder.encode(str));
filter.close();
};
if ((negateHtmlFilter || listedToManipulateDOM) && !(negateHtmlFilter && listedToManipulateDOM)) {
filtering = true;
} else {
filtering = false;
}
return {'responseHeaders': details.responseHeaders};
// by Jaap (https://gitlab.com/Jaaap)
header = details.responseHeaders.find((h) => h.name.toLowerCase() === 'content-type');
if (header && filtering) {
let mimeType, isAllowlisted;
mimeType = header.value.replace(/;.*/, '').toLowerCase();
isAllowlisted = stateManager._domainIsListed(initiatorDomain);
if (!isAllowlisted && mimeType === 'text/html') {
let asciiDecoder, decoder, encoder, charset, isFirstData, filter, data;
charset = (/charset\s*=/).test(header.value) && header.value.replace(/^.*?charset\s*=\s*/, '').replace(/["']?/g, '');
// Check if charset is supported by TextDecoder()
if (/charset\s*=/.test(header.value) && !EncodingTypes[charset.toString().toLowerCase()]) {
console.error(`[ LocalCDN ] Unsupported charset: ${charset}`);
return;
}
asciiDecoder = new TextDecoder('ASCII');
encoder = new TextEncoder();
isFirstData = true;
filter = browser.webRequest.filterResponseData(details.requestId);
data = [];
header.value = 'text/html; charset=UTF-8';
// NOTE: should work if 'script' string is divided into two chunks
filter.ondata = (evt) => {
if (isFirstData) {
if (!charset) {
// content-type has no charset declared
let htmlHead, charsetMatch;
htmlHead = asciiDecoder.decode(evt.data, {'stream': false});
// eslint-disable-next-line no-useless-escape
charsetMatch = htmlHead.match(/<meta.*charset=["']?([^>"'\/]+)["'].*[>\/]/i);
charset = charsetMatch ? charsetMatch[1] : 'UTF-8';
}
decoder = new TextDecoder(charset);
}
isFirstData = false;
data.push(evt.data);
};
filter.onstop = () => {
let str = '';
for (let buffer of data) {
str += decoder.decode(buffer, {'stream': true});
}
str += decoder.decode(); // end-of-stream
// remove crossorigin and integrity attributes
str = str.replace(/<(link|script)[^>]+>/ig, (m) => {
// eslint-disable-next-line no-use-before-define
if (cdnDomainsRE.test(m)) {
return m.replace(/\s+(integrity|crossorigin)(="[^"]*"|='[^']*'|=[^"'`=>\s]+|)/ig, '');
}
return m;
});
filter.write(encoder.encode(str));
filter.close();
};
}
return {'responseHeaders': details.responseHeaders};
}
}
};

View File

@ -25,7 +25,7 @@
New in LocalCDN:
</div>
<ul>
<li></li>
<li>Fixed: Check status code in HTML filter (<a href="https://codeberg.org/nobody/LocalCDN/issues/277">#277</a>)</li>
</ul>
<div id="generator-section">
<div class="topic-label">