diff options
author | mpcomplete@chromium.org <mpcomplete@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-03-22 23:18:50 +0000 |
---|---|---|
committer | mpcomplete@chromium.org <mpcomplete@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-03-22 23:18:50 +0000 |
commit | fc4facd5d143da6ccb96619981d12e9b9fc6467c (patch) | |
tree | 93cc7217ccde59452946120e03c6532c9f534620 /chrome/browser | |
parent | 2862086530e94dab7ab55e842601661aabd8a408 (diff) | |
download | chromium_src-fc4facd5d143da6ccb96619981d12e9b9fc6467c.zip chromium_src-fc4facd5d143da6ccb96619981d12e9b9fc6467c.tar.gz chromium_src-fc4facd5d143da6ccb96619981d12e9b9fc6467c.tar.bz2 |
Add tabId, type, and timeStamp parameters to extension webRequest events.
Also added support for filtering based on resource type, tabId, and windowId.
BUG=60101
TEST=covered by apitests
Review URL: http://codereview.chromium.org/6685010
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@79066 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r-- | chrome/browser/browser_process_impl.cc | 5 | ||||
-rwxr-xr-x | chrome/browser/extensions/extension_tab_id_map.cc | 150 | ||||
-rwxr-xr-x | chrome/browser/extensions/extension_tab_id_map.h | 56 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_webrequest_api.cc | 122 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_webrequest_api.h | 8 |
5 files changed, 314 insertions, 27 deletions
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc index 751a42a..06739bc 100644 --- a/chrome/browser/browser_process_impl.cc +++ b/chrome/browser/browser_process_impl.cc @@ -25,6 +25,7 @@ #include "chrome/browser/download/download_file_manager.h" #include "chrome/browser/download/save_file_manager.h" #include "chrome/browser/extensions/extension_event_router_forwarder.h" +#include "chrome/browser/extensions/extension_tab_id_map.h" #include "chrome/browser/first_run/first_run.h" #include "chrome/browser/google/google_url_tracker.h" #include "chrome/browser/gpu_process_host_ui_shim.h" @@ -135,6 +136,8 @@ BrowserProcessImpl::BrowserProcessImpl(const CommandLine& command_line) net_log_.reset(new ChromeNetLog); extension_event_router_forwarder_ = new ExtensionEventRouterForwarder; + + ExtensionTabIdMap::GetInstance()->Init(); } BrowserProcessImpl::~BrowserProcessImpl() { @@ -198,6 +201,8 @@ BrowserProcessImpl::~BrowserProcessImpl() { resource_dispatcher_host()->Shutdown(); } + ExtensionTabIdMap::GetInstance()->Shutdown(); + // The policy providers managed by |browser_policy_connector_| need to shut // down while the IO and FILE threads are still alive. browser_policy_connector_.reset(); diff --git a/chrome/browser/extensions/extension_tab_id_map.cc b/chrome/browser/extensions/extension_tab_id_map.cc new file mode 100755 index 0000000..ea3dac1 --- /dev/null +++ b/chrome/browser/extensions/extension_tab_id_map.cc @@ -0,0 +1,150 @@ +// Copyright (c) 2011 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. + +#include "chrome/browser/extensions/extension_tab_id_map.h" + +#include "content/browser/browser_thread.h" +#include "content/browser/tab_contents/tab_contents.h" +#include "content/browser/renderer_host/render_view_host.h" +#include "content/browser/renderer_host/render_process_host.h" +#include "content/common/notification_registrar.h" +#include "content/common/notification_observer.h" +#include "content/common/notification_service.h" + +// ExtensionTabIdMap is a Singleton, so it doesn't need refcounting. +DISABLE_RUNNABLE_METHOD_REFCOUNT(ExtensionTabIdMap); + +// +// ExtensionTabIdMap::TabObserver +// + +// This class listens for notifications about new and closed tabs on the UI +// thread, and notifies the ExtensionTabIdMap on the IO thread. It should only +// ever be accessed on the UI thread. +class ExtensionTabIdMap::TabObserver : public NotificationObserver { + public: + TabObserver(); + ~TabObserver(); + + private: + // NotificationObserver interface. + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details); + + NotificationRegistrar registrar_; +}; + +ExtensionTabIdMap::TabObserver::TabObserver() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + registrar_.Add(this, NotificationType::RENDER_VIEW_HOST_CREATED_FOR_TAB, + NotificationService::AllSources()); + registrar_.Add(this, NotificationType::RENDER_VIEW_HOST_DELETED, + NotificationService::AllSources()); + registrar_.Add(this, NotificationType::TAB_PARENTED, + NotificationService::AllSources()); +} + +ExtensionTabIdMap::TabObserver::~TabObserver() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); +} + +void ExtensionTabIdMap::TabObserver::Observe( + NotificationType type, const NotificationSource& source, + const NotificationDetails& details) { + switch (type.value) { + case NotificationType::RENDER_VIEW_HOST_CREATED_FOR_TAB: { + TabContents* contents = Source<TabContents>(source).ptr(); + RenderViewHost* host = Details<RenderViewHost>(details).ptr(); + // TODO(mpcmoplete): How can we tell if window_id is bogus? It may not + // have been set yet. + BrowserThread::PostTask( + BrowserThread::IO, FROM_HERE, + NewRunnableMethod( + ExtensionTabIdMap::GetInstance(), + &ExtensionTabIdMap::SetTabAndWindowId, + host->process()->id(), host->routing_id(), + contents->controller().session_id().id(), + contents->controller().window_id().id())); + break; + } + case NotificationType::TAB_PARENTED: { + NavigationController* controller = + Source<NavigationController>(source).ptr(); + RenderViewHost* host = controller->tab_contents()->render_view_host(); + BrowserThread::PostTask( + BrowserThread::IO, FROM_HERE, + NewRunnableMethod( + ExtensionTabIdMap::GetInstance(), + &ExtensionTabIdMap::SetTabAndWindowId, + host->process()->id(), host->routing_id(), + controller->session_id().id(), + controller->window_id().id())); + break; + } + case NotificationType::RENDER_VIEW_HOST_DELETED: { + RenderViewHost* host = Details<RenderViewHost>(details).ptr(); + BrowserThread::PostTask( + BrowserThread::IO, FROM_HERE, + NewRunnableMethod( + ExtensionTabIdMap::GetInstance(), + &ExtensionTabIdMap::ClearTabAndWindowId, + host->process()->id(), host->routing_id())); + break; + } + default: + NOTREACHED(); + return; + } +} + +// +// ExtensionTabIdMap +// + +ExtensionTabIdMap::ExtensionTabIdMap() : observer_(NULL) { +} + +ExtensionTabIdMap::~ExtensionTabIdMap() { +} + +// static +ExtensionTabIdMap* ExtensionTabIdMap::GetInstance() { + return Singleton<ExtensionTabIdMap>::get(); +} + +void ExtensionTabIdMap::Init() { + observer_ = new TabObserver; +} + +void ExtensionTabIdMap::Shutdown() { + delete observer_; +} + +void ExtensionTabIdMap::SetTabAndWindowId( + int render_process_host_id, int routing_id, int tab_id, int window_id) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + RenderId render_id(render_process_host_id, routing_id); + map_[render_id] = TabAndWindowId(tab_id, window_id); +} + +void ExtensionTabIdMap::ClearTabAndWindowId( + int render_process_host_id, int routing_id) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + RenderId render_id(render_process_host_id, routing_id); + map_.erase(render_id); +} + +bool ExtensionTabIdMap::GetTabAndWindowId( + int render_process_host_id, int routing_id, int* tab_id, int* window_id) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + RenderId render_id(render_process_host_id, routing_id); + TabAndWindowIdMap::iterator iter = map_.find(render_id); + if (iter != map_.end()) { + *tab_id = iter->second.first; + *window_id = iter->second.second; + return true; + } + return false; +} diff --git a/chrome/browser/extensions/extension_tab_id_map.h b/chrome/browser/extensions/extension_tab_id_map.h new file mode 100755 index 0000000..1fce693 --- /dev/null +++ b/chrome/browser/extensions/extension_tab_id_map.h @@ -0,0 +1,56 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_TAB_ID_MAP_H_ +#define CHROME_BROWSER_EXTENSIONS_EXTENSION_TAB_ID_MAP_H_ +#pragma once + +#include <map> +#include <utility> + +#include "base/basictypes.h" +#include "base/singleton.h" + +// This class keeps track of a map between renderer IDs and tab/window IDs, for +// use on the IO thread. All methods should be called on the IO thread except +// for Init and Shutdown. +class ExtensionTabIdMap { + public: + static ExtensionTabIdMap* GetInstance(); + + // These are called on the UI thread to start and stop listening to tab + // notifications. + void Init(); + void Shutdown(); + + // Looks up the tab and window ID for a given render view. Returns true + // if we have the IDs in our map. Called on the IO thread. + bool GetTabAndWindowId( + int render_process_host_id, int routing_id, int* tab_id, int* window_id); + + private: + class TabObserver; + friend class TabObserver; + friend struct DefaultSingletonTraits<ExtensionTabIdMap>; + + typedef std::pair<int, int> RenderId; + typedef std::pair<int, int> TabAndWindowId; + typedef std::map<RenderId, TabAndWindowId> TabAndWindowIdMap; + + ExtensionTabIdMap(); + ~ExtensionTabIdMap(); + + // Adds or removes a render view from our map. + void SetTabAndWindowId( + int render_process_host_id, int routing_id, int tab_id, int window_id); + void ClearTabAndWindowId( + int render_process_host_id, int routing_id); + + TabObserver* observer_; + TabAndWindowIdMap map_; + + DISALLOW_COPY_AND_ASSIGN(ExtensionTabIdMap); +}; + +#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_TAB_ID_MAP_H_ diff --git a/chrome/browser/extensions/extension_webrequest_api.cc b/chrome/browser/extensions/extension_webrequest_api.cc index 46d14c1..56a464d 100644 --- a/chrome/browser/extensions/extension_webrequest_api.cc +++ b/chrome/browser/extensions/extension_webrequest_api.cc @@ -11,12 +11,15 @@ #include "base/string_number_conversions.h" #include "base/values.h" #include "chrome/browser/extensions/extension_event_router_forwarder.h" +#include "chrome/browser/extensions/extension_tab_id_map.h" #include "chrome/browser/extensions/extension_webrequest_api_constants.h" #include "chrome/browser/profiles/profile.h" #include "chrome/common/extensions/extension.h" #include "chrome/common/extensions/extension_extent.h" #include "chrome/common/extensions/url_pattern.h" #include "content/browser/browser_thread.h" +#include "content/browser/renderer_host/resource_dispatcher_host.h" +#include "content/browser/renderer_host/resource_dispatcher_host_request_info.h" #include "net/base/net_errors.h" #include "net/url_request/url_request.h" #include "googleurl/src/gurl.h" @@ -35,8 +38,7 @@ static const char *kWebRequestEvents[] = { keys::kOnRequestSent }; -// TODO(mpcomplete): should this be a set of flags? -static const char* kRequestFilterTypes[] = { +static const char* kResourceTypeStrings[] = { "main_frame", "sub_frame", "stylesheet", @@ -46,18 +48,64 @@ static const char* kRequestFilterTypes[] = { "other", }; +static ResourceType::Type kResourceTypeValues[] = { + ResourceType::MAIN_FRAME, + ResourceType::SUB_FRAME, + ResourceType::STYLESHEET, + ResourceType::SCRIPT, + ResourceType::IMAGE, + ResourceType::OBJECT, + ResourceType::LAST_TYPE, // represents "other" +}; + +COMPILE_ASSERT( + arraysize(kResourceTypeStrings) == arraysize(kResourceTypeValues), + keep_resource_types_in_sync); + +#define ARRAYEND(array) (array + arraysize(array)) + static bool IsWebRequestEvent(const std::string& event_name) { - return std::find(kWebRequestEvents, - kWebRequestEvents + arraysize(kWebRequestEvents), - event_name) != - kWebRequestEvents + arraysize(kWebRequestEvents); + return std::find(kWebRequestEvents, ARRAYEND(kWebRequestEvents), + event_name) != ARRAYEND(kWebRequestEvents); +} + +static const char* ResourceTypeToString(ResourceType::Type type) { + ResourceType::Type* iter = + std::find(kResourceTypeValues, ARRAYEND(kResourceTypeValues), type); + if (iter == ARRAYEND(kResourceTypeValues)) + return "other"; + + return kResourceTypeStrings[iter - kResourceTypeValues]; } -static bool IsValidRequestFilterType(const std::string& type) { - return std::find(kRequestFilterTypes, - kRequestFilterTypes + arraysize(kRequestFilterTypes), - type) != - kRequestFilterTypes + arraysize(kRequestFilterTypes); +static bool ParseResourceType(const std::string& type_str, + ResourceType::Type* type) { + const char** iter = + std::find(kResourceTypeStrings, ARRAYEND(kResourceTypeStrings), type_str); + if (iter == ARRAYEND(kResourceTypeStrings)) + return false; + *type = kResourceTypeValues[iter - kResourceTypeStrings]; + return true; +} + +static void ExtractRequestInfo(net::URLRequest* request, + int* tab_id, + int* window_id, + ResourceType::Type* resource_type) { + if (!request->GetUserData(NULL)) + return; + + ResourceDispatcherHostRequestInfo* info = + ResourceDispatcherHost::InfoForRequest(request); + ExtensionTabIdMap::GetInstance()->GetTabAndWindowId( + info->child_id(), info->route_id(), tab_id, window_id); + + // Restrict the resource type to the values we care about. + ResourceType::Type* iter = + std::find(kResourceTypeValues, ARRAYEND(kResourceTypeValues), + info->resource_type()); + *resource_type = (iter != ARRAYEND(kResourceTypeValues)) ? + *iter : ResourceType::LAST_TYPE; } static void AddEventListenerOnIOThread( @@ -89,10 +137,11 @@ static void EventHandledOnIOThread( // filter what network events an extension cares about. struct ExtensionWebRequestEventRouter::RequestFilter { ExtensionExtent urls; - std::vector<std::string> types; + std::vector<ResourceType::Type> types; int tab_id; int window_id; + RequestFilter() : tab_id(-1), window_id(-1) {} bool InitFromValue(const DictionaryValue& value); }; @@ -167,12 +216,13 @@ bool ExtensionWebRequestEventRouter::RequestFilter::InitFromValue( } } else if (*key == "types") { ListValue* types_value = NULL; - if (!value.GetList("urls", &types_value)) + if (!value.GetList("types", &types_value)) return false; for (size_t i = 0; i < types_value->GetSize(); ++i) { - std::string type; - if (!types_value->GetString(i, &type) || - !IsValidRequestFilterType(type)) + std::string type_str; + ResourceType::Type type; + if (!types_value->GetString(i, &type_str) || + !ParseResourceType(type_str, &type)) return false; types.push_back(type); } @@ -238,21 +288,28 @@ bool ExtensionWebRequestEventRouter::OnBeforeRequest( // TODO(jochen): Figure out what to do with events from the system context. if (profile_id == Profile::kInvalidProfileId) return false; + + int tab_id = -1; + int window_id = -1; + ResourceType::Type resource_type = ResourceType::LAST_TYPE; + ExtractRequestInfo(request, &tab_id, &window_id, &resource_type); + std::vector<const EventListener*> listeners = - GetMatchingListeners(profile_id, keys::kOnBeforeRequest, request->url()); + GetMatchingListeners(profile_id, keys::kOnBeforeRequest, request->url(), + tab_id, window_id, resource_type); if (listeners.empty()) return false; ListValue args; DictionaryValue* dict = new DictionaryValue(); - dict->SetString(keys::kUrlKey, request->url().spec()); - dict->SetString(keys::kMethodKey, request->method()); - // TODO(mpcomplete): implement - dict->SetInteger(keys::kTabIdKey, 0); dict->SetString(keys::kRequestIdKey, base::Uint64ToString(request->identifier())); - dict->SetString(keys::kTypeKey, "main_frame"); - dict->SetInteger(keys::kTimeStampKey, 1); + dict->SetString(keys::kUrlKey, request->url().spec()); + dict->SetString(keys::kMethodKey, request->method()); + dict->SetInteger(keys::kTabIdKey, tab_id); + dict->SetString(keys::kTypeKey, ResourceTypeToString(resource_type)); + dict->SetDouble(keys::kTimeStampKey, + request->request_time().ToDoubleT() * 1000); args.Append(dict); std::string json_args; @@ -361,15 +418,28 @@ std::vector<const ExtensionWebRequestEventRouter::EventListener*> ExtensionWebRequestEventRouter::GetMatchingListeners( ProfileId profile_id, const std::string& event_name, - const GURL& url) { + const GURL& url, + int tab_id, + int window_id, + ResourceType::Type resource_type) { // TODO(mpcomplete): handle profile_id == invalid (should collect all // listeners). std::vector<const EventListener*> matching_listeners; std::set<EventListener>& listeners = listeners_[profile_id][event_name]; for (std::set<EventListener>::iterator it = listeners.begin(); it != listeners.end(); ++it) { - if (it->filter.urls.is_empty() || it->filter.urls.ContainsURL(url)) - matching_listeners.push_back(&(*it)); + if (!it->filter.urls.is_empty() && !it->filter.urls.ContainsURL(url)) + continue; + if (it->filter.tab_id != -1 && tab_id != it->filter.tab_id) + continue; + if (it->filter.window_id != -1 && window_id != it->filter.window_id) + continue; + if (!it->filter.types.empty() && + std::find(it->filter.types.begin(), it->filter.types.end(), + resource_type) == it->filter.types.end()) + continue; + + matching_listeners.push_back(&(*it)); } return matching_listeners; } diff --git a/chrome/browser/extensions/extension_webrequest_api.h b/chrome/browser/extensions/extension_webrequest_api.h index 0cd52a3..5d64fdc 100644 --- a/chrome/browser/extensions/extension_webrequest_api.h +++ b/chrome/browser/extensions/extension_webrequest_api.h @@ -16,6 +16,7 @@ #include "chrome/browser/profiles/profile.h" #include "ipc/ipc_message.h" #include "net/base/completion_callback.h" +#include "webkit/glue/resource_type.h" class ExtensionEventRouterForwarder; class GURL; @@ -83,7 +84,12 @@ class ExtensionWebRequestEventRouter { // Returns a list of event listeners that care about the given event, based // on their filter parameters. std::vector<const EventListener*> GetMatchingListeners( - ProfileId profile_id, const std::string& event_name, const GURL& url); + ProfileId profile_id, + const std::string& event_name, + const GURL& url, + int tab_id, + int window_id, + ResourceType::Type resource_type); // Decrements the count of event handlers blocking the given request. When the // count reaches 0 (or immediately if the request is being cancelled), we |