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

Delta Between Two Patch Sets: chrome/ext/background.js

Issue 29374674: Issue 4864 - Start using ESLint for adblockpluschrome (Closed)
Left Patch Set: Created Feb. 7, 2017, 4:49 p.m.
Right Patch Set: Use .includes again Created March 31, 2017, 8:37 a.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « chrome/devtools.js ('k') | chrome/ext/common.js » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
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-2016 Eyeo GmbH 3 * Copyright (C) 2006-2017 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
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details. 12 * GNU General Public License for more details.
13 * 13 *
14 * You should have received a copy of the GNU General Public License 14 * You should have received a copy of the GNU General Public License
15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
16 */ 16 */
17 17
18 "use strict"; 18 "use strict";
19 19
20 (function()
20 { 21 {
21 /* Pages */ 22 /* Pages */
22 23
23 let Page = ext.Page = function(tab) 24 let Page = ext.Page = function(tab)
24 { 25 {
25 this.id = tab.id; 26 this.id = tab.id;
26 this._url = tab.url && new URL(tab.url); 27 this._url = tab.url && new URL(tab.url);
27 28
28 this.browserAction = new BrowserAction(tab.id); 29 this.browserAction = new BrowserAction(tab.id);
29 this.contextMenus = new ContextMenus(this); 30 this.contextMenus = new ContextMenus(this);
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
111 if (!frames) 112 if (!frames)
112 frames = framesOfTabs[tabId] = Object.create(null); 113 frames = framesOfTabs[tabId] = Object.create(null);
113 114
114 let frame = frames[frameId]; 115 let frame = frames[frameId];
115 if (!frame) 116 if (!frame)
116 frame = frames[frameId] = {}; 117 frame = frames[frameId] = {};
117 118
118 return frame; 119 return frame;
119 } 120 }
120 121
121 chrome.webNavigation.onBeforeNavigate.addListener(details => 122 function updatePageFrameStructure(frameId, tabId, url, parentFrameId)
122 {
123 // Capture parent frame here because onCommitted doesn't get this info.
124 let frame = createFrame(details.tabId, details.frameId);
125 frame.parent = framesOfTabs[details.tabId][details.parentFrameId] || null;
126 });
127
128 let eagerlyUpdatedPages = new ext.PageMap();
129
130 ext._updatePageFrameStructure = (frameId, tabId, url, eager) =>
131 { 123 {
132 if (frameId == 0) 124 if (frameId == 0)
133 { 125 {
134 let page = new Page({id: tabId, url}); 126 let page = new Page({id: tabId, url});
135 127
136 if (eagerlyUpdatedPages.get(page) != url) 128 ext._removeFromAllPageMaps(tabId);
137 { 129
138 ext._removeFromAllPageMaps(tabId); 130 chrome.tabs.get(tabId, () =>
139 131 {
140 // When a sitekey header is received we must immediately update the page 132 // If the tab is prerendered, chrome.tabs.get() sets
141 // structure in order to record and use the key. We want to avoid 133 // chrome.runtime.lastError and we have to dispatch the onLoading event,
142 // trashing the page structure if the onCommitted event is then fired 134 // since the onUpdated event isn't dispatched for prerendered tabs.
143 // for the page. 135 // However, we have to keep relying on the unUpdated event for tabs that
144 if (eager) 136 // are already visible. Otherwise browser action changes get overridden
145 eagerlyUpdatedPages.set(page, url); 137 // when Chrome automatically resets them on navigation.
146 138 if (chrome.runtime.lastError)
147 chrome.tabs.get(tabId, () => 139 ext.pages.onLoading._dispatch(page);
148 { 140 });
149 // If the tab is prerendered, chrome.tabs.get() sets 141 }
150 // chrome.runtime.lastError and we have to dispatch the 142
151 // onLoading event, since the onUpdated event isn't 143 // Update frame parent and URL in frame structure
152 // dispatched for prerendered tabs. However, we have to
153 // keep relying on the unUpdated event for tabs that are
154 // already visible. Otherwise browser action changes get
155 // overridden when Chrome automatically resets them on
156 // navigation.
157 if (chrome.runtime.lastError)
158 ext.pages.onLoading._dispatch(page);
159 });
160 }
161 }
162
163 // Update frame URL in frame structure
164 let frame = createFrame(tabId, frameId); 144 let frame = createFrame(tabId, frameId);
165 frame.url = new URL(url); 145 frame.url = new URL(url);
166 }; 146 frame.parent = framesOfTabs[tabId][parentFrameId] || null;
167 147 }
168 chrome.webNavigation.onCommitted.addListener(details => 148
169 { 149 chrome.webRequest.onHeadersReceived.addListener(details =>
170 ext._updatePageFrameStructure(details.frameId, details.tabId, details.url); 150 {
151 // We have to update the frame structure when switching to a new
152 // document, so that we process any further requests made by that
153 // document in the right context. Unfortunately, we cannot rely
154 // on webNavigation.onCommitted since it isn't guaranteed to fire
155 // before any subresources start downloading[1]. As an
156 // alternative we use webRequest.onHeadersReceived for HTTP(S)
157 // URLs, being careful to ignore any responses that won't cause
158 // the document to be replaced.
159 // [1] - https://bugs.chromium.org/p/chromium/issues/detail?id=665843
160
161 // The request has been processed without replacing the document.
162 // https://chromium.googlesource.com/chromium/src/+/02d3f50b/content/browser /frame_host/navigation_request.cc#473
163 if (details.statusCode == 204 || details.statusCode == 205)
164 return;
165
166 for (let header of details.responseHeaders)
167 {
168 let headerName = header.name.toLowerCase();
169
170 // For redirects we must wait for the next response in order
171 // to know if the document will be replaced. Note: Chrome
172 // performs a redirect only if there is a "Location" header with
173 // a non-empty value and a known redirect status code.
174 // https://chromium.googlesource.com/chromium/src/+/39a7d96/net/http/http_ response_headers.cc#929
175 if (headerName == "location" && header.value &&
176 (details.statusCode == 301 || details.statusCode == 302 ||
177 details.statusCode == 303 || details.statusCode == 307 ||
178 details.statusCode == 308))
179 return;
180
181 // If the response initiates a download the document won't be
182 // replaced. Chrome initiates a download if there is a
183 // "Content-Disposition" with a valid and non-empty value other
184 // than "inline".
185 // https://chromium.googlesource.com/chromium/src/+/02d3f50b/content/brows er/loader/mime_sniffing_resource_handler.cc#534
186 // https://chromium.googlesource.com/chromium/src/+/02d3f50b/net/http/http _content_disposition.cc#374
187 // https://chromium.googlesource.com/chromium/src/+/16e2688e/net/http/http _util.cc#431
188 if (headerName == "content-disposition")
189 {
190 let disposition = header.value.split(";")[0].replace(/[ \t]+$/, "");
191 if (disposition.toLowerCase() != "inline" &&
192 /^[\x21-\x7E]+$/.test(disposition) &&
193 !/[()<>@,;:\\"/[\]?={}]/.test(disposition))
194 return;
195 }
196
197 // The value of the "Content-Type" header also determines if Chrome will
198 // initiate a download, or otherwise how the response will be rendered.
199 // We only need to consider responses which will result in a navigation
200 // and be rendered as HTML or similar.
201 // Note: Chrome might render the response as HTML if the "Content-Type"
202 // header is missing, invalid or unknown.
203 // https://chromium.googlesource.com/chromium/src/+/99f41af9/net/http/http _util.cc#66
204 // https://chromium.googlesource.com/chromium/src/+/3130418a/net/base/mime _sniffer.cc#667
205 if (headerName == "content-type")
206 {
207 let mediaType = header.value.split(/[ \t;(]/)[0].toLowerCase();
208 if (mediaType.includes("/") &&
209 mediaType != "*/*" &&
210 mediaType != "application/unknown" &&
211 mediaType != "unknown/unknown" &&
212 mediaType != "text/html" &&
213 mediaType != "text/xml" &&
214 mediaType != "application/xml" &&
215 mediaType != "application/xhtml+xml" &&
216 mediaType != "image/svg+xml")
217 return;
218 }
219 }
220
221 updatePageFrameStructure(details.frameId, details.tabId, details.url,
222 details.parentFrameId);
223 },
224 {types: ["main_frame", "sub_frame"], urls: ["http://*/*", "https://*/*"]},
225 ["responseHeaders"]);
226
227 chrome.webNavigation.onBeforeNavigate.addListener(details =>
228 {
229 // Since we can only listen for HTTP(S) responses using
230 // webRequest.onHeadersReceived we must update the page structure here for
231 // other navigations.
232 let url = new URL(details.url);
233 if (url.protocol != "http:" && url.protocol != "https:")
234 {
235 updatePageFrameStructure(details.frameId, details.tabId, details.url,
236 details.parentFrameId);
237 }
171 }); 238 });
172 239
173 function forgetTab(tabId) 240 function forgetTab(tabId)
174 { 241 {
175 ext.pages.onRemoved._dispatch(tabId); 242 ext.pages.onRemoved._dispatch(tabId);
176 243
177 ext._removeFromAllPageMaps(tabId); 244 ext._removeFromAllPageMaps(tabId);
178 delete framesOfTabs[tabId]; 245 delete framesOfTabs[tabId];
179 } 246 }
180 247
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after
373 440
374 /* Web requests */ 441 /* Web requests */
375 442
376 let framesOfTabs = Object.create(null); 443 let framesOfTabs = Object.create(null);
377 444
378 ext.getFrame = (tabId, frameId) => 445 ext.getFrame = (tabId, frameId) =>
379 { 446 {
380 return (framesOfTabs[tabId] || {})[frameId]; 447 return (framesOfTabs[tabId] || {})[frameId];
381 }; 448 };
382 449
383 let handlerBehaviorChangedQuota = ( 450 let handlerBehaviorChangedQuota =
384 chrome.webRequest.MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES 451 chrome.webRequest.MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES;
385 );
386 452
387 function propagateHandlerBehaviorChange() 453 function propagateHandlerBehaviorChange()
388 { 454 {
389 // Make sure to not call handlerBehaviorChanged() more often than allowed 455 // Make sure to not call handlerBehaviorChanged() more often than allowed
390 // by chrome.webRequest.MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES. 456 // by chrome.webRequest.MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES.
391 // Otherwise Chrome notifies the user that this extension is causing issues. 457 // Otherwise Chrome notifies the user that this extension is causing issues.
392 if (handlerBehaviorChangedQuota > 0) 458 if (handlerBehaviorChangedQuota > 0)
393 { 459 {
394 chrome.webNavigation.onBeforeNavigate.removeListener( 460 chrome.webNavigation.onBeforeNavigate.removeListener(
395 propagateHandlerBehaviorChange 461 propagateHandlerBehaviorChange
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
470 let results = ext.webRequest.onBeforeRequest._dispatch( 536 let results = ext.webRequest.onBeforeRequest._dispatch(
471 new URL(details.url), 537 new URL(details.url),
472 type.toUpperCase(), 538 type.toUpperCase(),
473 new Page({id: details.tabId}), 539 new Page({id: details.tabId}),
474 frame 540 frame
475 ); 541 );
476 542
477 if (results.indexOf(false) != -1) 543 if (results.indexOf(false) != -1)
478 return {cancel: true}; 544 return {cancel: true};
479 } 545 }
480 }, {urls: ["http://*/*", "https://*/*"]}, ["blocking"]); 546 }, {urls: ["<all_urls>"]}, ["blocking"]);
481 547
482 548
483 /* Message passing */ 549 /* Message passing */
484 550
485 chrome.runtime.onMessage.addListener((message, rawSender, sendResponse) => 551 chrome.runtime.onMessage.addListener((message, rawSender, sendResponse) =>
486 { 552 {
487 let sender = {}; 553 let sender = {};
488 554
489 // Add "page" and "frame" if the message was sent by a content script. 555 // Add "page" and "frame" if the message was sent by a content script.
490 // If sent by popup or the background page itself, there is no "tab". 556 // If sent by popup or the background page itself, there is no "tab".
(...skipping 11 matching lines...) Expand all
502 568
503 let frame = frames[rawSender.frameId]; 569 let frame = frames[rawSender.frameId];
504 if (frame) 570 if (frame)
505 return frame.parent; 571 return frame.parent;
506 572
507 return frames[0]; 573 return frames[0];
508 } 574 }
509 }; 575 };
510 } 576 }
511 577
512 let results = ext.onMessage._dispatch(message, sender, sendResponse); 578 return ext.onMessage._dispatch(
513 return results.indexOf(true) != -1; 579 message, sender, sendResponse
580 ).indexOf(true) != -1;
514 }); 581 });
515 582
516 583
517 /* Storage */ 584 /* Storage */
518 585
519 ext.storage = { 586 ext.storage = {
520 get(keys, callback) 587 get(keys, callback)
521 { 588 {
522 chrome.storage.local.get(keys, callback); 589 chrome.storage.local.get(keys, callback);
523 }, 590 },
(...skipping 24 matching lines...) Expand all
548 { 615 {
549 chrome.runtime.openOptionsPage(() => 616 chrome.runtime.openOptionsPage(() =>
550 { 617 {
551 if (chrome.runtime.lastError) 618 if (chrome.runtime.lastError)
552 return; 619 return;
553 620
554 chrome.tabs.query({active: true, lastFocusedWindow: true}, tabs => 621 chrome.tabs.query({active: true, lastFocusedWindow: true}, tabs =>
555 { 622 {
556 if (tabs.length > 0) 623 if (tabs.length > 0)
557 { 624 {
558 window.setTimeout(() => 625 if (tabs[0].status == "complete")
559 {
560 callback(new Page(tabs[0])); 626 callback(new Page(tabs[0]));
561 }); 627 else
628 afterTabLoaded(callback)(tabs[0]);
562 } 629 }
563 }); 630 });
564 }); 631 });
565 } 632 }
566 }; 633 };
567 } 634 }
568 else 635 else
569 { 636 {
570 // Edge does not yet support runtime.openOptionsPage (tested version 38) 637 // Edge does not yet support runtime.openOptionsPage (tested version 38)
571 // and so this workaround needs to stay for now. 638 // and so this workaround needs to stay for now.
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
606 /* Windows */ 673 /* Windows */
607 ext.windows = { 674 ext.windows = {
608 create(createData, callback) 675 create(createData, callback)
609 { 676 {
610 chrome.windows.create(createData, createdWindow => 677 chrome.windows.create(createData, createdWindow =>
611 { 678 {
612 afterTabLoaded(callback)(createdWindow.tabs[0]); 679 afterTabLoaded(callback)(createdWindow.tabs[0]);
613 }); 680 });
614 } 681 }
615 }; 682 };
616 } 683 }());
LEFTRIGHT

Powered by Google App Engine
This is Rietveld