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

Unified Diff: chrome/ext/background.js

Issue 29403564: Issue 5083 - Merges chrome subdirectory to top level directory (Closed) Base URL: https://hg.adblockplus.org/adblockpluschrome
Patch Set: rebase for dave and sebastians changes, update buildtools dependency Created April 10, 2017, 7:51 a.m.
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | chrome/ext/common.js » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/ext/background.js
===================================================================
deleted file mode 100644
--- a/chrome/ext/background.js
+++ /dev/null
@@ -1,683 +0,0 @@
-/*
- * This file is part of Adblock Plus <https://adblockplus.org/>,
- * Copyright (C) 2006-2017 eyeo GmbH
- *
- * Adblock Plus is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * Adblock Plus is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
- */
-
-"use strict";
-
-(function()
-{
- /* Pages */
-
- let Page = ext.Page = function(tab)
- {
- this.id = tab.id;
- this._url = tab.url && new URL(tab.url);
-
- this.browserAction = new BrowserAction(tab.id);
- this.contextMenus = new ContextMenus(this);
- };
- Page.prototype = {
- get url()
- {
- // usually our Page objects are created from Chrome's Tab objects, which
- // provide the url. So we can return the url given in the constructor.
- if (this._url)
- return this._url;
-
- // but sometimes we only have the tab id when we create a Page object.
- // In that case we get the url from top frame of the tab, recorded by
- // the onBeforeRequest handler.
- let frames = framesOfTabs[this.id];
- if (frames)
- {
- let frame = frames[0];
- if (frame)
- return frame.url;
- }
- },
- sendMessage(message, responseCallback)
- {
- chrome.tabs.sendMessage(this.id, message, responseCallback);
- }
- };
-
- ext.getPage = id => new Page({id: parseInt(id, 10)});
-
- function afterTabLoaded(callback)
- {
- return openedTab =>
- {
- let onUpdated = (tabId, changeInfo, tab) =>
- {
- if (tabId == openedTab.id && changeInfo.status == "complete")
- {
- chrome.tabs.onUpdated.removeListener(onUpdated);
- callback(new Page(openedTab));
- }
- };
- chrome.tabs.onUpdated.addListener(onUpdated);
- };
- }
-
- ext.pages = {
- open(url, callback)
- {
- chrome.tabs.create({url}, callback && afterTabLoaded(callback));
- },
- query(info, callback)
- {
- let rawInfo = {};
- for (let property in info)
- {
- switch (property)
- {
- case "active":
- case "lastFocusedWindow":
- rawInfo[property] = info[property];
- }
- }
-
- chrome.tabs.query(rawInfo, tabs =>
- {
- callback(tabs.map(tab => new Page(tab)));
- });
- },
- onLoading: new ext._EventTarget(),
- onActivated: new ext._EventTarget(),
- onRemoved: new ext._EventTarget()
- };
-
- chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) =>
- {
- if (changeInfo.status == "loading")
- ext.pages.onLoading._dispatch(new Page(tab));
- });
-
- function createFrame(tabId, frameId)
- {
- let frames = framesOfTabs[tabId];
- if (!frames)
- frames = framesOfTabs[tabId] = Object.create(null);
-
- let frame = frames[frameId];
- if (!frame)
- frame = frames[frameId] = {};
-
- return frame;
- }
-
- function updatePageFrameStructure(frameId, tabId, url, parentFrameId)
- {
- if (frameId == 0)
- {
- let page = new Page({id: tabId, url});
-
- ext._removeFromAllPageMaps(tabId);
-
- chrome.tabs.get(tabId, () =>
- {
- // If the tab is prerendered, chrome.tabs.get() sets
- // chrome.runtime.lastError and we have to dispatch the onLoading event,
- // since the onUpdated event isn't dispatched for prerendered tabs.
- // However, we have to keep relying on the unUpdated event for tabs that
- // are already visible. Otherwise browser action changes get overridden
- // when Chrome automatically resets them on navigation.
- if (chrome.runtime.lastError)
- ext.pages.onLoading._dispatch(page);
- });
- }
-
- // Update frame parent and URL in frame structure
- let frame = createFrame(tabId, frameId);
- frame.url = new URL(url);
- frame.parent = framesOfTabs[tabId][parentFrameId] || null;
- }
-
- chrome.webRequest.onHeadersReceived.addListener(details =>
- {
- // We have to update the frame structure when switching to a new
- // document, so that we process any further requests made by that
- // document in the right context. Unfortunately, we cannot rely
- // on webNavigation.onCommitted since it isn't guaranteed to fire
- // before any subresources start downloading[1]. As an
- // alternative we use webRequest.onHeadersReceived for HTTP(S)
- // URLs, being careful to ignore any responses that won't cause
- // the document to be replaced.
- // [1] - https://bugs.chromium.org/p/chromium/issues/detail?id=665843
-
- // The request has been processed without replacing the document.
- // https://chromium.googlesource.com/chromium/src/+/02d3f50b/content/browser/frame_host/navigation_request.cc#473
- if (details.statusCode == 204 || details.statusCode == 205)
- return;
-
- for (let header of details.responseHeaders)
- {
- let headerName = header.name.toLowerCase();
-
- // For redirects we must wait for the next response in order
- // to know if the document will be replaced. Note: Chrome
- // performs a redirect only if there is a "Location" header with
- // a non-empty value and a known redirect status code.
- // https://chromium.googlesource.com/chromium/src/+/39a7d96/net/http/http_response_headers.cc#929
- if (headerName == "location" && header.value &&
- (details.statusCode == 301 || details.statusCode == 302 ||
- details.statusCode == 303 || details.statusCode == 307 ||
- details.statusCode == 308))
- return;
-
- // If the response initiates a download the document won't be
- // replaced. Chrome initiates a download if there is a
- // "Content-Disposition" with a valid and non-empty value other
- // than "inline".
- // https://chromium.googlesource.com/chromium/src/+/02d3f50b/content/browser/loader/mime_sniffing_resource_handler.cc#534
- // https://chromium.googlesource.com/chromium/src/+/02d3f50b/net/http/http_content_disposition.cc#374
- // https://chromium.googlesource.com/chromium/src/+/16e2688e/net/http/http_util.cc#431
- if (headerName == "content-disposition")
- {
- let disposition = header.value.split(";")[0].replace(/[ \t]+$/, "");
- if (disposition.toLowerCase() != "inline" &&
- /^[\x21-\x7E]+$/.test(disposition) &&
- !/[()<>@,;:\\"/[\]?={}]/.test(disposition))
- return;
- }
-
- // The value of the "Content-Type" header also determines if Chrome will
- // initiate a download, or otherwise how the response will be rendered.
- // We only need to consider responses which will result in a navigation
- // and be rendered as HTML or similar.
- // Note: Chrome might render the response as HTML if the "Content-Type"
- // header is missing, invalid or unknown.
- // https://chromium.googlesource.com/chromium/src/+/99f41af9/net/http/http_util.cc#66
- // https://chromium.googlesource.com/chromium/src/+/3130418a/net/base/mime_sniffer.cc#667
- if (headerName == "content-type")
- {
- let mediaType = header.value.split(/[ \t;(]/)[0].toLowerCase();
- if (mediaType.includes("/") &&
- mediaType != "*/*" &&
- mediaType != "application/unknown" &&
- mediaType != "unknown/unknown" &&
- mediaType != "text/html" &&
- mediaType != "text/xml" &&
- mediaType != "application/xml" &&
- mediaType != "application/xhtml+xml" &&
- mediaType != "image/svg+xml")
- return;
- }
- }
-
- updatePageFrameStructure(details.frameId, details.tabId, details.url,
- details.parentFrameId);
- },
- {types: ["main_frame", "sub_frame"], urls: ["http://*/*", "https://*/*"]},
- ["responseHeaders"]);
-
- chrome.webNavigation.onBeforeNavigate.addListener(details =>
- {
- // Since we can only listen for HTTP(S) responses using
- // webRequest.onHeadersReceived we must update the page structure here for
- // other navigations.
- let url = new URL(details.url);
- if (url.protocol != "http:" && url.protocol != "https:")
- {
- updatePageFrameStructure(details.frameId, details.tabId, details.url,
- details.parentFrameId);
- }
- });
-
- function forgetTab(tabId)
- {
- ext.pages.onRemoved._dispatch(tabId);
-
- ext._removeFromAllPageMaps(tabId);
- delete framesOfTabs[tabId];
- }
-
- chrome.tabs.onReplaced.addListener((addedTabId, removedTabId) =>
- {
- forgetTab(removedTabId);
- });
-
- chrome.tabs.onRemoved.addListener(forgetTab);
-
- chrome.tabs.onActivated.addListener(details =>
- {
- ext.pages.onActivated._dispatch(new Page({id: details.tabId}));
- });
-
-
- /* Browser actions */
-
- let BrowserAction = function(tabId)
- {
- this._tabId = tabId;
- this._changes = null;
- };
- BrowserAction.prototype = {
- _applyChanges()
- {
- if ("iconPath" in this._changes)
- {
- chrome.browserAction.setIcon({
- tabId: this._tabId,
- path: {
- 16: this._changes.iconPath.replace("$size", "16"),
- 19: this._changes.iconPath.replace("$size", "19"),
- 20: this._changes.iconPath.replace("$size", "20"),
- 32: this._changes.iconPath.replace("$size", "32"),
- 38: this._changes.iconPath.replace("$size", "38"),
- 40: this._changes.iconPath.replace("$size", "40")
- }
- });
- }
-
- if ("badgeText" in this._changes)
- {
- chrome.browserAction.setBadgeText({
- tabId: this._tabId,
- text: this._changes.badgeText
- });
- }
-
- if ("badgeColor" in this._changes)
- {
- chrome.browserAction.setBadgeBackgroundColor({
- tabId: this._tabId,
- color: this._changes.badgeColor
- });
- }
-
- this._changes = null;
- },
- _queueChanges()
- {
- chrome.tabs.get(this._tabId, () =>
- {
- // If the tab is prerendered, chrome.tabs.get() sets
- // chrome.runtime.lastError and we have to delay our changes
- // until the currently visible tab is replaced with the
- // prerendered tab. Otherwise chrome.browserAction.set* fails.
- if (chrome.runtime.lastError)
- {
- let onReplaced = (addedTabId, removedTabId) =>
- {
- if (addedTabId == this._tabId)
- {
- chrome.tabs.onReplaced.removeListener(onReplaced);
- this._applyChanges();
- }
- };
- chrome.tabs.onReplaced.addListener(onReplaced);
- }
- else
- {
- this._applyChanges();
- }
- });
- },
- _addChange(name, value)
- {
- if (!this._changes)
- {
- this._changes = {};
- this._queueChanges();
- }
-
- this._changes[name] = value;
- },
- setIcon(path)
- {
- this._addChange("iconPath", path);
- },
- setBadge(badge)
- {
- if (!badge)
- {
- this._addChange("badgeText", "");
- }
- else
- {
- if ("number" in badge)
- this._addChange("badgeText", badge.number.toString());
-
- if ("color" in badge)
- this._addChange("badgeColor", badge.color);
- }
- }
- };
-
-
- /* Context menus */
-
- let contextMenuItems = new ext.PageMap();
- let contextMenuUpdating = false;
-
- let updateContextMenu = () =>
- {
- if (contextMenuUpdating)
- return;
-
- contextMenuUpdating = true;
-
- chrome.tabs.query({active: true, lastFocusedWindow: true}, tabs =>
- {
- chrome.contextMenus.removeAll(() =>
- {
- contextMenuUpdating = false;
-
- if (tabs.length == 0)
- return;
-
- let items = contextMenuItems.get({id: tabs[0].id});
-
- if (!items)
- return;
-
- items.forEach(item =>
- {
- chrome.contextMenus.create({
- title: item.title,
- contexts: item.contexts,
- onclick(info, tab)
- {
- item.onclick(new Page(tab));
- }
- });
- });
- });
- });
- };
-
- let ContextMenus = function(page)
- {
- this._page = page;
- };
- ContextMenus.prototype = {
- create(item)
- {
- let items = contextMenuItems.get(this._page);
- if (!items)
- contextMenuItems.set(this._page, items = []);
-
- items.push(item);
- updateContextMenu();
- },
- remove(item)
- {
- let items = contextMenuItems.get(this._page);
- if (items)
- {
- let index = items.indexOf(item);
- if (index != -1)
- {
- items.splice(index, 1);
- updateContextMenu();
- }
- }
- }
- };
-
- chrome.tabs.onActivated.addListener(updateContextMenu);
-
- chrome.windows.onFocusChanged.addListener(windowId =>
- {
- if (windowId != chrome.windows.WINDOW_ID_NONE)
- updateContextMenu();
- });
-
-
- /* Web requests */
-
- let framesOfTabs = Object.create(null);
-
- ext.getFrame = (tabId, frameId) =>
- {
- return (framesOfTabs[tabId] || {})[frameId];
- };
-
- let handlerBehaviorChangedQuota =
- chrome.webRequest.MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES;
-
- function propagateHandlerBehaviorChange()
- {
- // Make sure to not call handlerBehaviorChanged() more often than allowed
- // by chrome.webRequest.MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES.
- // Otherwise Chrome notifies the user that this extension is causing issues.
- if (handlerBehaviorChangedQuota > 0)
- {
- chrome.webNavigation.onBeforeNavigate.removeListener(
- propagateHandlerBehaviorChange
- );
- chrome.webRequest.handlerBehaviorChanged();
-
- handlerBehaviorChangedQuota--;
- setTimeout(() => { handlerBehaviorChangedQuota++; }, 600000);
- }
- }
-
- ext.webRequest = {
- onBeforeRequest: new ext._EventTarget(),
- handlerBehaviorChanged()
- {
- // Defer handlerBehaviorChanged() until navigation occurs.
- // There wouldn't be any visible effect when calling it earlier,
- // but it's an expensive operation and that way we avoid to call
- // it multiple times, if multiple filters are added/removed.
- let {onBeforeNavigate} = chrome.webNavigation;
- if (!onBeforeNavigate.hasListener(propagateHandlerBehaviorChange))
- onBeforeNavigate.addListener(propagateHandlerBehaviorChange);
- }
- };
-
- chrome.tabs.query({}, tabs =>
- {
- tabs.forEach(tab =>
- {
- chrome.webNavigation.getAllFrames({tabId: tab.id}, details =>
- {
- if (details && details.length > 0)
- {
- let frames = framesOfTabs[tab.id] = Object.create(null);
-
- for (let i = 0; i < details.length; i++)
- {
- frames[details[i].frameId] = {
- url: new URL(details[i].url),
- parent: null
- };
- }
-
- for (let i = 0; i < details.length; i++)
- {
- let {parentFrameId} = details[i];
-
- if (parentFrameId != -1)
- frames[details[i].frameId].parent = frames[parentFrameId];
- }
- }
- });
- });
- });
-
- chrome.webRequest.onBeforeRequest.addListener(details =>
- {
- // The high-level code isn't interested in requests that aren't
- // related to a tab or requests loading a top-level document,
- // those should never be blocked.
- if (details.tabId == -1 || details.type == "main_frame")
- return;
-
- // We are looking for the frame that contains the element which
- // has triggered this request. For most requests (e.g. images) we
- // can just use the request's frame ID, but for subdocument requests
- // (e.g. iframes) we must instead use the request's parent frame ID.
- let {frameId, type} = details;
- if (type == "sub_frame")
- {
- frameId = details.parentFrameId;
- type = "SUBDOCUMENT";
- }
-
- let frame = ext.getFrame(details.tabId, frameId);
- if (frame)
- {
- let results = ext.webRequest.onBeforeRequest._dispatch(
- new URL(details.url),
- type.toUpperCase(),
- new Page({id: details.tabId}),
- frame
- );
-
- if (results.indexOf(false) != -1)
- return {cancel: true};
- }
- }, {urls: ["<all_urls>"]}, ["blocking"]);
-
-
- /* Message passing */
-
- chrome.runtime.onMessage.addListener((message, rawSender, sendResponse) =>
- {
- let sender = {};
-
- // Add "page" and "frame" if the message was sent by a content script.
- // If sent by popup or the background page itself, there is no "tab".
- if ("tab" in rawSender)
- {
- sender.page = new Page(rawSender.tab);
- sender.frame = {
- url: new URL(rawSender.url),
- get parent()
- {
- let frames = framesOfTabs[rawSender.tab.id];
-
- if (!frames)
- return null;
-
- let frame = frames[rawSender.frameId];
- if (frame)
- return frame.parent;
-
- return frames[0];
- }
- };
- }
-
- return ext.onMessage._dispatch(
- message, sender, sendResponse
- ).indexOf(true) != -1;
- });
-
-
- /* Storage */
-
- ext.storage = {
- get(keys, callback)
- {
- chrome.storage.local.get(keys, callback);
- },
- set(key, value, callback)
- {
- let items = {};
- items[key] = value;
- chrome.storage.local.set(items, callback);
- },
- remove(key, callback)
- {
- chrome.storage.local.remove(key, callback);
- },
- onChanged: chrome.storage.onChanged
- };
-
- /* Options */
-
- if ("openOptionsPage" in chrome.runtime)
- {
- ext.showOptions = callback =>
- {
- if (!callback)
- {
- chrome.runtime.openOptionsPage();
- }
- else
- {
- chrome.runtime.openOptionsPage(() =>
- {
- if (chrome.runtime.lastError)
- return;
-
- chrome.tabs.query({active: true, lastFocusedWindow: true}, tabs =>
- {
- if (tabs.length > 0)
- {
- if (tabs[0].status == "complete")
- callback(new Page(tabs[0]));
- else
- afterTabLoaded(callback)(tabs[0]);
- }
- });
- });
- }
- };
- }
- else
- {
- // Edge does not yet support runtime.openOptionsPage (tested version 38)
- // and so this workaround needs to stay for now.
- ext.showOptions = callback =>
- {
- chrome.windows.getLastFocused(win =>
- {
- let optionsUrl = chrome.extension.getURL("options.html");
- let queryInfo = {url: optionsUrl};
-
- // extension pages can't be accessed in incognito windows. In order to
- // correctly mimic the way in which Chrome opens extension options,
- // we have to focus the options page in any other window.
- if (!win.incognito)
- queryInfo.windowId = win.id;
-
- chrome.tabs.query(queryInfo, tabs =>
- {
- if (tabs.length > 0)
- {
- let tab = tabs[0];
-
- chrome.windows.update(tab.windowId, {focused: true});
- chrome.tabs.update(tab.id, {active: true});
-
- if (callback)
- callback(new Page(tab));
- }
- else
- {
- ext.pages.open(optionsUrl, callback);
- }
- });
- });
- };
- }
-
- /* Windows */
- ext.windows = {
- create(createData, callback)
- {
- chrome.windows.create(createData, createdWindow =>
- {
- afterTabLoaded(callback)(createdWindow.tabs[0]);
- });
- }
- };
-}());
« no previous file with comments | « no previous file | chrome/ext/common.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld