Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Side by Side Diff: lib/requestBlocker.js

Issue 29739594: Issue 6543 - Match requests without tabId/frameId in their originating context (Closed)
Patch Set: Created April 2, 2018, 2:55 a.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * This file is part of Adblock Plus <https://adblockplus.org/>, 2 * This file is part of Adblock Plus <https://adblockplus.org/>,
3 * Copyright (C) 2006-present eyeo GmbH 3 * Copyright (C) 2006-present eyeo GmbH
4 * 4 *
5 * Adblock Plus is free software: you can redistribute it and/or modify 5 * Adblock Plus is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 3 as 6 * it under the terms of the GNU General Public License version 3 as
7 * published by the Free Software Foundation. 7 * published by the Free Software Foundation.
8 * 8 *
9 * Adblock Plus is distributed in the hope that it will be useful, 9 * Adblock Plus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
66 // WEBRTC gets addressed through a workaround, even if the webRequest API is 66 // WEBRTC gets addressed through a workaround, even if the webRequest API is
67 // lacking support to block this kind of a request. 67 // lacking support to block this kind of a request.
68 yield "WEBRTC"; 68 yield "WEBRTC";
69 69
70 // POPUP, CSP and ELEMHIDE filters aren't mapped to resource types. 70 // POPUP, CSP and ELEMHIDE filters aren't mapped to resource types.
71 yield "POPUP"; 71 yield "POPUP";
72 yield "ELEMHIDE"; 72 yield "ELEMHIDE";
73 yield "CSP"; 73 yield "CSP";
74 }()); 74 }());
75 75
76 function onBeforeRequestAsync(tabId, url, type, docDomain, 76 function getRelatedTabIds(details)
77 thirdParty, sitekey,
78 specificOnly, filter)
79 { 77 {
80 let tabIds = tabId != -1 ? [tabId] : []; 78 // This is the common case, the request is associated with a single tab.
79 // If tabId is -1, its not (e.g. the request was sent by
80 // a Service/Shared Worker) and we have to identify the related tabs.
81 if (details.tabId != -1)
82 return Promise.resolve([details.tabId]);
81 83
82 if (filter) 84 // Firefox >=48 provides "originUrl" indicating the URL of the tab
83 FilterNotifier.emit("filter.hitCount", filter, 0, 0, tabIds); 85 // that caused this request. In case of Service/Shared Worker,
86 // this is URL of the tab that caused the worker to be spawned.
87 if (details.originUrl)
kzar 2018/04/03 12:49:30 Nit: Please use braces since the body spans multip
Sebastian Noack 2018/04/04 01:04:45 No longer relevant (the block has only one line no
88 return browser.tabs.query({url: details.originUrl}).then(
89 tabs => tabs.map(tab => tab.id)
90 );
84 91
85 devtools.logRequest( 92 // Chromium >=63 provides "intiator" which is equivalent to "originUrl" on
86 tabIds, url, type, docDomain, 93 // Firefox except that its not a full URL but just an origin (proto + host).
87 thirdParty, sitekey, 94 // So we have to find each tab with an URL of the same origin.
88 specificOnly, filter 95 if (details.initiator)
89 ); 96 return browser.tabs.query({}).then(tabs =>
kzar 2018/04/03 12:49:30 Couldn't we pass something like `details.initiator
Sebastian Noack 2018/04/04 01:04:45 In fact we can. I wasn't aware that tab.query() ac
kzar 2018/04/05 10:31:51 Cool, I assumed I was wrong somehow :p. This looks
97 {
98 let tabIds = [];
99 for (let tab of tabs)
100 {
101 if (new URL(tab.url).origin == details.initiator)
102 tabIds.push(tab.id);
kzar 2018/04/03 12:49:30 Wouldn't this mean we sometimes log a request for
Sebastian Noack 2018/04/04 01:04:45 This usually means that the request was sent by a
kzar 2018/04/05 10:31:51 Acknowledged.
103 }
104 return tabIds;
105 });
106
107 return Promise.resolve([]);
108 }
109
110 function logRequest(details, url, type, docDomain, thirdParty,
111 sitekey, specificOnly, filter)
112 {
113 getRelatedTabIds(details).then(tabIds =>
114 {
115 if (filter)
116 FilterNotifier.emit("filter.hitCount", filter, 0, 0, tabIds);
117
118 devtools.logRequest(
119 tabIds, url, type, docDomain,
120 thirdParty, sitekey,
121 specificOnly, filter
122 );
123 });
90 } 124 }
91 125
92 browser.webRequest.onBeforeRequest.addListener(details => 126 browser.webRequest.onBeforeRequest.addListener(details =>
93 { 127 {
94 // Never block top-level documents. 128 // Never block top-level documents.
95 if (details.type == "main_frame") 129 if (details.type == "main_frame")
96 return; 130 return;
97 131
98 // Filter out requests from non web protocols. Ideally, we'd explicitly 132 // Filter out requests from non web protocols. Ideally, we'd explicitly
99 // specify the protocols we are interested in (i.e. http://, https://, 133 // specify the protocols we are interested in (i.e. http://, https://,
100 // ws:// and wss://) with the url patterns, given below, when adding this 134 // ws:// and wss://) with the url patterns, given below, when adding this
101 // listener. But unfortunately, Chrome <=57 doesn't support the WebSocket 135 // listener. But unfortunately, Chrome <=57 doesn't support the WebSocket
102 // protocol and is causing an error if it is given. 136 // protocol and is causing an error if it is given.
103 let url = new URL(details.url); 137 let url = new URL(details.url);
104 if (url.protocol != "http:" && url.protocol != "https:" && 138 if (url.protocol != "http:" && url.protocol != "https:" &&
105 url.protocol != "ws:" && url.protocol != "wss:") 139 url.protocol != "ws:" && url.protocol != "wss:")
106 return; 140 return;
107 141
108 // Firefox (only) allows to intercept requests sent by the browser 142 let originUrl = null;
109 // and other extensions. We don't want to block these.
110 if (details.originUrl) 143 if (details.originUrl)
111 { 144 {
112 let originUrl = new URL(details.originUrl); 145 originUrl = new URL(details.originUrl);
146
147 // Firefox (only) allows to intercept requests sent by the browser
148 // and other extensions. We don't want to block these.
113 if (originUrl.protocol == "chrome:" || 149 if (originUrl.protocol == "chrome:" ||
114 originUrl.protocol == "moz-extension:") 150 originUrl.protocol == "moz-extension:")
115 return; 151 return;
116 } 152 }
153 // Fallback to "initiator" on Chrome >=63. It doesn't include the
154 // path (unlike "originUrl" on Firefox), but is still good enough
155 // (in case the tab/frame is unknown) for the $domain filter option
156 // and most document exception rules which only match the domain part.
157 else if (details.initiator)
158 originUrl = new URL(details.initiator);
117 159
118 let frame = ext.getFrame( 160 let page = null;
119 details.tabId, 161 let frame = null;
120 // We are looking for the frame that contains the element which 162 if (details.tabId != -1)
121 // has triggered this request. For most requests (e.g. images) we 163 {
122 // can just use the request's frame ID, but for subdocument requests 164 page = new ext.Page({id: details.tabId});
123 // (e.g. iframes) we must instead use the request's parent frame ID. 165 frame = ext.getFrame(
124 details.type == "sub_frame" ? details.parentFrameId : details.frameId 166 details.tabId,
125 ); 167 // We are looking for the frame that contains the element which
168 // has triggered this request. For most requests (e.g. images) we
169 // can just use the request's frame ID, but for subdocument requests
170 // (e.g. iframes) we must instead use the request's parent frame ID.
171 details.type == "sub_frame" ? details.parentFrameId : details.frameId
172 );
173 }
126 174
127 let docDomain = null; 175 if (checkWhitelisted(page, frame, originUrl))
128 let sitekey = null; 176 return;
129 let thirdParty = false;
130 let specificOnly = false;
131
132 if (frame)
133 {
134 let page = new ext.Page({id: details.tabId});
135
136 if (checkWhitelisted(page, frame))
137 return;
138
139 docDomain = extractHostFromFrame(frame);
140 sitekey = getKey(page, frame);
141 thirdParty = isThirdParty(url, docDomain);
142 specificOnly = !!checkWhitelisted(page, frame,
143 RegExpFilter.typeMap.GENERICBLOCK);
144 }
145 177
146 let urlString = stringifyURL(url); 178 let urlString = stringifyURL(url);
147 let type = resourceTypes.get(details.type) || "OTHER"; 179 let type = resourceTypes.get(details.type) || "OTHER";
180 let docDomain = extractHostFromFrame(frame, originUrl);
181 let thirdParty = isThirdParty(url, docDomain);
182 let sitekey = getKey(page, frame, originUrl);
183 let specificOnly = !!checkWhitelisted(page, frame, originUrl,
184 RegExpFilter.typeMap.GENERICBLOCK);
185
148 let filter = defaultMatcher.matchesAny( 186 let filter = defaultMatcher.matchesAny(
149 urlString, RegExpFilter.typeMap[type], 187 urlString, RegExpFilter.typeMap[type],
150 docDomain, thirdParty, sitekey, specificOnly 188 docDomain, thirdParty, sitekey, specificOnly
151 ); 189 );
152 190
153 setTimeout(onBeforeRequestAsync, 0, details.tabId, urlString, 191 logRequest(details, urlString, type, docDomain,
154 type, docDomain, 192 thirdParty, sitekey, specificOnly, filter);
155 thirdParty, sitekey,
156 specificOnly, filter);
157 193
158 if (filter instanceof BlockingFilter) 194 if (filter instanceof BlockingFilter)
159 return {cancel: true}; 195 return {cancel: true};
160 }, {urls: ["<all_urls>"]}, ["blocking"]); 196 }, {urls: ["<all_urls>"]}, ["blocking"]);
161 197
162 port.on("filters.collapse", (message, sender) => 198 port.on("filters.collapse", (message, sender) =>
163 { 199 {
164 if (checkWhitelisted(sender.page, sender.frame)) 200 if (checkWhitelisted(sender.page, sender.frame))
165 return false; 201 return false;
166 202
167 let typeMask = RegExpFilter.typeMap[message.mediatype]; 203 let typeMask = RegExpFilter.typeMap[message.mediatype];
168 let documentHost = extractHostFromFrame(sender.frame); 204 let documentHost = extractHostFromFrame(sender.frame);
169 let sitekey = getKey(sender.page, sender.frame); 205 let sitekey = getKey(sender.page, sender.frame);
170 let blocked = false; 206 let blocked = false;
171 207
172 let specificOnly = checkWhitelisted( 208 let specificOnly = checkWhitelisted(
173 sender.page, sender.frame, 209 sender.page, sender.frame, null,
174 RegExpFilter.typeMap.GENERICBLOCK 210 RegExpFilter.typeMap.GENERICBLOCK
175 ); 211 );
176 212
177 for (let url of message.urls) 213 for (let url of message.urls)
178 { 214 {
179 let urlObj = new URL(url, message.baseURL); 215 let urlObj = new URL(url, message.baseURL);
180 let filter = defaultMatcher.matchesAny( 216 let filter = defaultMatcher.matchesAny(
181 stringifyURL(urlObj), 217 stringifyURL(urlObj),
182 typeMask, documentHost, 218 typeMask, documentHost,
183 isThirdParty(urlObj, documentHost), 219 isThirdParty(urlObj, documentHost),
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
239 275
240 port.on("request.blockedByRTCWrapper", (msg, sender) => 276 port.on("request.blockedByRTCWrapper", (msg, sender) =>
241 { 277 {
242 return ext.webRequest.onBeforeRequest._dispatch( 278 return ext.webRequest.onBeforeRequest._dispatch(
243 new URL(msg.url), 279 new URL(msg.url),
244 "webrtc", 280 "webrtc",
245 sender.page, 281 sender.page,
246 sender.frame 282 sender.frame
247 ).includes(false); 283 ).includes(false);
248 }); 284 });
OLDNEW
« no previous file with comments | « lib/popupBlocker.js ('k') | lib/url.js » ('j') | lib/whitelisting.js » ('J')

Powered by Google App Engine
This is Rietveld