blob: 6a4573a1384dd7672a04be13931de753d67cf014 [file] [log] [blame]
Adrià Vilanova Martínezac2a5612022-12-27 21:51:40 +01001import MWOptionsWatcherClient from '../../common/mainWorldOptionsWatcher/Client.js';
2import {convertJSONToResponse, getResponseJSON} from '../utils.js';
3
4import demo from './demo.js';
5
6export const responseModifiers = [
7 demo,
8];
9
10// Content script target
11export const kCSTarget = 'TWPT-XHRInterceptorOptionsWatcher-CS';
12// Main world (AKA regular web page) target
13export const kMWTarget = 'TWPT-XHRInterceptorOptionsWatcher-MW';
14
15export default class ResponseModifier {
16 constructor() {
17 this.optionsWatcher = new MWOptionsWatcherClient(
18 Array.from(this.watchingFeatures()), kCSTarget, kMWTarget);
19 }
20
21 watchingFeatures(modifiers) {
22 if (!modifiers) modifiers = responseModifiers;
23
24 const union = new Set();
25 for (const m of modifiers) {
26 if (!m.featureGated) continue;
27 for (const feature of m.features) union.add(feature);
28 }
29 return union;
30 }
31
32 async #getMatchingModifiers(request) {
33 // First filter modifiers which match the request URL regex.
34 const urlModifiers = responseModifiers.filter(
35 modifier => request.$TWPTRequestURL.match(modifier.urlRegex));
36
37 // Now filter modifiers which require a certain feature to be enabled
38 // (feature-gated modifiers).
39 const featuresAreEnabled = await this.optionsWatcher.areEnabled(
40 Array.from(this.watchingFeatures(urlModifiers)));
41
42 // #!if !production
43 if (Object.keys(featuresAreEnabled).length > 0) {
44 console.info(
45 '[XHR Interceptor - Response Modifier] Requested features',
46 featuresAreEnabled, 'for request', request.$TWPTRequestURL);
47 }
48 // #!endif
49
50 return urlModifiers.filter(modifier => {
51 return !modifier.featureGated || modifier.isEnabled(featuresAreEnabled);
52 });
53 }
54
55 async intercept(request, response) {
56 const matchingModifiers = await this.#getMatchingModifiers(request);
57
58 // If we didn't find any matching modifiers, return the response right away.
59 if (matchingModifiers.length === 0) return response;
60
61 // Otherwise, apply the modifiers sequentially and set the new response.
62 let json = getResponseJSON({
63 responseType: request.xhr.responseType,
64 response: request.xhr.response,
65 $TWPTRequestURL: request.$TWPTRequestURL,
66 $isArrayProto: request.$isArrayProto,
67 });
68 for (const modifier of matchingModifiers) {
69 json = await modifier.interceptor(request, json);
70 }
71 response = convertJSONToResponse(request, json);
72 request.$newResponse = response;
73 request.$responseModified = true;
74 }
75}