Skip to content

Commit

Permalink
Add ability to log original and modified XML content in xml-prune scr…
Browse files Browse the repository at this point in the history
…iptlet
  • Loading branch information
AdamWr committed Jun 14, 2024
1 parent ee3c9c9 commit 59d1348
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 1 deletion.
21 changes: 20 additions & 1 deletion src/scriptlets/xml-prune.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import {
* - `propsToMatch` — optional, XPath or selector of elements which will be removed from XML
* - `optionalProp` — optional, selector of elements that must occur in XML document
* - `urlToMatch` — optional, string or regular expression for matching the request's URL
* - `logContent` — optional, string to log original and modified XML content.
*
* > Usage with no arguments will log response payload and URL to browser console;
* > it may be useful for debugging but it is not allowed for prod versions of filter lists.
Expand All @@ -59,6 +60,12 @@ import {
* example.org#%#//scriptlet('xml-prune', 'Period[id*="-ad-"]', '', '.mpd')
* ```
*
* 1. Remove `Period` tag whose `id` contains `-ad-`, only if request's URL contains `.mpd` and log content
*
* ```adblock
* example.org#%#//scriptlet('xml-prune', 'Period[id*="-ad-"]', '', '.mpd', 'logContent')
* ```
*
* 1. Remove `Period` tag whose `id` contains `pre-roll` and remove `duration` attribute from the `Period` tag
* by using XPath expression
*
Expand Down Expand Up @@ -86,7 +93,7 @@ import {
*/
/* eslint-enable max-len */

export function xmlPrune(source, propsToRemove, optionalProp = '', urlToMatch = '') {
export function xmlPrune(source, propsToRemove, optionalProp = '', urlToMatch = '', logContent) {
// do nothing if browser does not support Reflect, fetch or Proxy (e.g. Internet Explorer)
// https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy
Expand All @@ -100,6 +107,8 @@ export function xmlPrune(source, propsToRemove, optionalProp = '', urlToMatch =

let shouldPruneResponse = false;

const shouldLogContent = logContent === 'logContent';

const urlMatchRegexp = toRegExp(urlToMatch);

const XPATH_MARKER = 'xpath(';
Expand Down Expand Up @@ -193,13 +202,23 @@ export function xmlPrune(source, propsToRemove, optionalProp = '', urlToMatch =
shouldPruneResponse = false;
return text;
}
if (shouldLogContent) {
// It's necessary to clone the XML document because xmlDoc is logged with removed elements
const cloneXmlDoc = xmlDoc.cloneNode(true);
logMessage(source, 'Original xml:');
logMessage(source, cloneXmlDoc, true, false);
}
if (isXpath) {
xPathPruning(elements);
} else {
elements.forEach((elem) => {
elem.remove();
});
}
if (shouldLogContent) {
logMessage(source, 'Modified xml:');
logMessage(source, xmlDoc, true, false);
}
const serializer = new XMLSerializer();
text = serializer.serializeToString(xmlDoc);
return text;
Expand Down
36 changes: 36 additions & 0 deletions tests/scriptlets/xml-prune.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,42 @@ if (!isSupported) {
done();
});

test('fetch match URL - remove ads and log', async (assert) => {
assert.expect(4);

console.log = (...args) => {
if (args.length === 2 && args[1] instanceof XMLDocument) {
const xmlDocument = args[1];
const serializer = new XMLSerializer();
const text = serializer.serializeToString(xmlDocument);
if (text.includes('MPD') && text.includes('pre-roll-')) {
assert.ok(text.includes('Period id="pre-roll-1-ad-1"'), 'should log original text in console');
}
if (text.includes('MPD') && !text.includes('pre-roll-')) {
assert.notOk(text.includes('Period id="pre-roll-1-ad-1"'), 'should log modififed text in console');
}
}
nativeConsole(...args);
};

const MATCH_DATA = "Period[id*='-ad-']";
const OPTIONAL_MATCH = '';
const MATCH_URL = '.mpd';
const LOG_CONTENT = 'logContent';
const scriptletArgs = [MATCH_DATA, OPTIONAL_MATCH, MATCH_URL, LOG_CONTENT];

runScriptlet(name, scriptletArgs);

const done = assert.async();

const response = await fetch(MPD_OBJECTS_PATH);
const responseMPD = await response.text();

assert.notOk(responseMPD.includes('pre-roll-1-ad-1'));
assert.strictEqual(window.hit, 'FIRED', 'hit function fired');
done();
});

test('fetch match URL, match optional argument - remove ads', async (assert) => {
const MATCH_DATA = "Period[id*='-ad-']";
const OPTIONAL_MATCH = 'AdaptationSet';
Expand Down

0 comments on commit 59d1348

Please sign in to comment.