diff --git a/core/manipulate-dom.js b/core/manipulate-dom.js index b8b475be..ec44e1a6 100644 --- a/core/manipulate-dom.js +++ b/core/manipulate-dom.js @@ -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(/"'\/]+)["'].*[>\/]/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(/"'\/]+)["'].*[>\/]/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}; + + } } }; diff --git a/pages/updates/updates.html b/pages/updates/updates.html index 71ef6186..9fba07a7 100644 --- a/pages/updates/updates.html +++ b/pages/updates/updates.html @@ -25,7 +25,7 @@ New in LocalCDN: