| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| /** |
| * @fileoverview Provides a representation of a web request sender, and |
| * utility functions for creating them. |
| */ |
| 'use strict'; |
| |
| /** |
| * @typedef {{ |
| * origin: string, |
| * tabId: (number|undefined) |
| * frameId: (number|undefined) |
| * }} |
| */ |
| var WebRequestSender; |
| |
| /** |
| * Creates an object representing the sender's origin, and, if available, |
| * tab. |
| * @param {MessageSender} messageSender The message sender. |
| * @return {?WebRequestSender} The sender's origin and tab, or null if the |
| * sender is invalid. |
| */ |
| function createSenderFromMessageSender(messageSender) { |
| var origin = getOriginFromUrl(/** @type {string} */ (messageSender.url)); |
| if (!origin) { |
| return null; |
| } |
| var sender = {origin: origin}; |
| if (messageSender.tab) { |
| sender.tabId = messageSender.tab.id; |
| sender.frameId = messageSender.frameId; |
| } |
| return sender; |
| } |
| |
| /** |
| * Checks whether the given tab could have sent a message from the given |
| * origin. |
| * @param {Tab} tab The tab to match |
| * @param {string} origin The origin to check. |
| * @return {Promise} A promise resolved with the tab id if it the tab could, |
| * have sent the request, and rejected if it can't. |
| */ |
| function tabMatchesOrigin(tab, origin) { |
| // If the tab's origin matches, trust that the request came from this tab. |
| if (getOriginFromUrl(tab.url) == origin) { |
| return Promise.resolve(tab.id); |
| } |
| return Promise.reject(false); |
| } |
| |
| /** |
| * Attempts to ensure that the tabId of the sender is set, using chrome.tabs |
| * when available. |
| * @param {WebRequestSender} sender The request sender. |
| * @return {Promise} A promise resolved once the tabId retrieval is done. |
| * The promise is rejected if the tabId is untrustworthy, e.g. if the |
| * user rapidly switched tabs. |
| */ |
| function getTabIdWhenPossible(sender) { |
| if (sender.tabId) { |
| // Already got it? Done. |
| return Promise.resolve(true); |
| } else if (!chrome.tabs) { |
| // Can't get it? Done. (This happens to packaged apps, which can't access |
| // chrome.tabs.) |
| return Promise.resolve(true); |
| } else { |
| return new Promise(function(resolve, reject) { |
| chrome.tabs.query( |
| {active: true, lastFocusedWindow: true}, function(tabs) { |
| if (!tabs.length) { |
| // Safety check. |
| reject(false); |
| return; |
| } |
| var tab = tabs[0]; |
| tabMatchesOrigin(tab, sender.origin) |
| .then( |
| function(tabId) { |
| sender.tabId = tabId; |
| resolve(true); |
| }, |
| function() { |
| // Didn't match? Check if the debugger is open. |
| if (tab.url.indexOf('devtools://') != 0) { |
| reject(false); |
| return; |
| } |
| // Debugger active: find first tab with the sender's |
| // origin. |
| chrome.tabs.query({active: true}, function(tabs) { |
| if (!tabs.length) { |
| // Safety check. |
| reject(false); |
| return; |
| } |
| var numRejected = 0; |
| for (var i = 0; i < tabs.length; i++) { |
| tab = tabs[i]; |
| tabMatchesOrigin(tab, sender.origin) |
| .then( |
| function(tabId) { |
| sender.tabId = tabId; |
| resolve(true); |
| }, |
| function() { |
| if (++numRejected >= tabs.length) { |
| // None matches: reject. |
| reject(false); |
| } |
| }); |
| } |
| }); |
| }); |
| }); |
| }); |
| } |
| } |
| |
| /** |
| * Checks whether the given tab is in the foreground, i.e. is the active tab |
| * of the focused window. |
| * @param {number} tabId The tab id to check. |
| * @return {Promise<boolean>} A promise for the result of the check. |
| */ |
| function tabInForeground(tabId) { |
| return new Promise(function(resolve, reject) { |
| if (!chrome.tabs || !chrome.tabs.get) { |
| reject(); |
| return; |
| } |
| if (!chrome.windows || !chrome.windows.get) { |
| reject(); |
| return; |
| } |
| chrome.tabs.get(tabId, function(tab) { |
| if (chrome.runtime.lastError) { |
| resolve(false); |
| return; |
| } |
| if (!tab.active) { |
| resolve(false); |
| return; |
| } |
| chrome.windows.get(tab.windowId, function(aWindow) { |
| resolve(aWindow && aWindow.focused); |
| }); |
| }); |
| }); |
| } |