Chromium Code Reviews| Index: chrome/browser/extensions/extension_webrequest_api.cc |
| diff --git a/chrome/browser/extensions/extension_webrequest_api.cc b/chrome/browser/extensions/extension_webrequest_api.cc |
| index 46d14c10312903f17a03460208d9a35f07c5d786..6f0724cd7bad71b158929e11fabb2607c5ed2cf7 100644 |
| --- a/chrome/browser/extensions/extension_webrequest_api.cc |
| +++ b/chrome/browser/extensions/extension_webrequest_api.cc |
| @@ -16,6 +16,7 @@ |
| #include "chrome/common/extensions/extension.h" |
| #include "chrome/common/extensions/extension_extent.h" |
| #include "chrome/common/extensions/url_pattern.h" |
| +#include "chrome/common/url_constants.h" |
| #include "content/browser/browser_thread.h" |
| #include "net/base/net_errors.h" |
| #include "net/url_request/url_request.h" |
| @@ -29,6 +30,7 @@ namespace { |
| static const char *kWebRequestEvents[] = { |
| keys::kOnBeforeRedirect, |
| keys::kOnBeforeRequest, |
| + keys::kOnBeforeSendHeaders, |
| keys::kOnCompleted, |
| keys::kOnErrorOccurred, |
| keys::kOnHeadersReceived, |
| @@ -106,7 +108,7 @@ struct ExtensionWebRequestEventRouter::ExtraInfoSpec { |
| RESPONSE_HEADERS = 1<<3, |
| REDIRECT_REQUEST_LINE = 1<<4, |
| REDIRECT_REQUEST_HEADERS = 1<<5, |
| - BLOCKING = 1<<5, |
| + BLOCKING = 1<<6, |
| }; |
| static bool InitFromValue(const ListValue& value, int* extra_info_spec); |
| @@ -147,6 +149,35 @@ struct ExtensionWebRequestEventRouter::BlockedRequest { |
| BlockedRequest() : num_handlers_blocking(0), callback(NULL) {} |
| }; |
| + |
| +// We use this class as UserData on any URLRequests that we are tracking. This |
|
willchan no longer on Chromium
2011/03/22 23:05:35
Why is this simpler than adding a cancellation API
Matt Perry
2011/03/24 00:11:25
It isn't... I guess I'll do that then :).
|
| +// lets us know when the URLRequest is deleted, so we can remove it from our |
| +// tracked list. |
| +class ExtensionWebRequestEventRouter::TrackedRequest |
| + : public net::URLRequest::UserData { |
| +public: |
| + TrackedRequest(net::URLRequest* request, |
| + ExtensionWebRequestEventRouter* router) |
| + : router_(router), request_(request) { |
| + request->SetUserData(router_, this); |
| + } |
| + virtual ~TrackedRequest() { |
| + if (router_) |
| + router_->OnRequestDeleted(request_); |
| + } |
| + |
| + void StopTracking() { |
| + ExtensionWebRequestEventRouter* key = router_; |
| + router_ = NULL; |
| + request_->SetUserData(key, NULL); // deletes |this| |
| + } |
| + |
| + net::URLRequest* request() const { return request_; } |
| + |
| + private: |
| + ExtensionWebRequestEventRouter* router_; |
| + net::URLRequest* request_; |
| +}; |
| bool ExtensionWebRequestEventRouter::RequestFilter::InitFromValue( |
| const DictionaryValue& value) { |
| @@ -228,6 +259,10 @@ ExtensionWebRequestEventRouter::ExtensionWebRequestEventRouter() { |
| } |
| ExtensionWebRequestEventRouter::~ExtensionWebRequestEventRouter() { |
| + for (HttpRequestMap::iterator it = http_requests_.begin(); |
| + it != http_requests_.end(); ++it) { |
| + it->second->StopTracking(); // deletes the object |
| + } |
| } |
| bool ExtensionWebRequestEventRouter::OnBeforeRequest( |
| @@ -243,6 +278,13 @@ bool ExtensionWebRequestEventRouter::OnBeforeRequest( |
| if (listeners.empty()) |
| return false; |
| + // If this is an HTTP request, keep track of it. HTTP-specific events only |
| + // have the request ID, so we'll need to look up the URLRequest from that. |
| + if (request->url().SchemeIs(chrome::kHttpScheme) || |
| + request->url().SchemeIs(chrome::kHttpsScheme)) { |
| + http_requests_[request->identifier()] = new TrackedRequest(request, this); |
| + } |
| + |
| ListValue args; |
| DictionaryValue* dict = new DictionaryValue(); |
| dict->SetString(keys::kUrlKey, request->url().spec()); |
| @@ -255,18 +297,65 @@ bool ExtensionWebRequestEventRouter::OnBeforeRequest( |
| dict->SetInteger(keys::kTimeStampKey, 1); |
| args.Append(dict); |
| - std::string json_args; |
| + return DispatchEvent(profile_id, event_router, request, callback, listeners, |
| + args); |
| +} |
| + |
| +bool ExtensionWebRequestEventRouter::OnBeforeSendHeaders( |
| + ProfileId profile_id, |
| + ExtensionEventRouterForwarder* event_router, |
| + uint64 request_id, |
| + net::HttpRequestHeaders* headers, |
| + net::CompletionCallback* callback) { |
| + // TODO(jochen): Figure out what to do with events from the system context. |
| + if (profile_id == Profile::kInvalidProfileId) |
| + return false; |
| + |
| + HttpRequestMap::iterator iter = http_requests_.find(request_id); |
| + if (iter == http_requests_.end()) |
| + return false; |
| + |
| + net::URLRequest* request = iter->second->request(); |
| + iter->second->StopTracking(); |
| + http_requests_.erase(iter); |
| + |
| + std::vector<const EventListener*> listeners = |
| + GetMatchingListeners(profile_id, keys::kOnBeforeSendHeaders, request); |
| + if (listeners.empty()) |
| + return false; |
| + |
| + ListValue args; |
| + DictionaryValue* dict = new DictionaryValue(); |
| + dict->SetString(keys::kRequestIdKey, |
| + base::Uint64ToString(request->identifier())); |
| + dict->SetString(keys::kUrlKey, request->url().spec()); |
| + dict->SetDouble(keys::kTimeStampKey, base::Time::Now().ToDoubleT() * 1000); |
| + // TODO(mpcomplete): request headers. |
| + args.Append(dict); |
| + |
| + return DispatchEvent(profile_id, event_router, request, callback, listeners, |
| + args); |
| +} |
| + |
| +bool ExtensionWebRequestEventRouter::DispatchEvent( |
| + ProfileId profile_id, |
| + ExtensionEventRouterForwarder* event_router, |
| + net::URLRequest* request, |
| + net::CompletionCallback* callback, |
| + const std::vector<const EventListener*>& listeners, |
| + const ListValue& args) { |
| + std::string json_args; |
| base::JSONWriter::Write(&args, false, &json_args); |
| // TODO(mpcomplete): Consider consolidating common (extension_id,json_args) |
| // pairs into a single message sent to a list of sub_event_names. |
| int num_handlers_blocking = 0; |
| - for (std::vector<const EventListener*>::iterator it = listeners.begin(); |
| + for (std::vector<const EventListener*>::const_iterator it = listeners.begin(); |
| it != listeners.end(); ++it) { |
| event_router->DispatchEventToExtension( |
| (*it)->extension_id, (*it)->sub_event_name, json_args, |
| profile_id, true, GURL()); |
| - if ((*it)->extra_info_spec & ExtraInfoSpec::BLOCKING) { |
| + if (callback && (*it)->extra_info_spec & ExtraInfoSpec::BLOCKING) { |
| (*it)->blocked_requests.insert(request->identifier()); |
| ++num_handlers_blocking; |
| } |
| @@ -374,6 +463,20 @@ ExtensionWebRequestEventRouter::GetMatchingListeners( |
| return matching_listeners; |
| } |
| +std::vector<const ExtensionWebRequestEventRouter::EventListener*> |
| +ExtensionWebRequestEventRouter::GetMatchingListeners( |
| + ProfileId profile_id, |
| + const std::string& event_name, |
| + net::URLRequest* request) { |
| + int tab_id = -1; |
| + int window_id = -1; |
| + ResourceType::Type resource_type = ResourceType::LAST_TYPE; |
| + ExtractRequestInfo(request, &tab_id, &window_id, &resource_type); |
| + |
| + return GetMatchingListeners( |
| + profile_id, event_name, request->url(), tab_id, window_id, resource_type); |
| +} |
| + |
| void ExtensionWebRequestEventRouter::DecrementBlockCount(uint64 request_id, |
| bool cancel) { |
| // It's possible that this request was already cancelled by a previous event |
| @@ -395,6 +498,11 @@ void ExtensionWebRequestEventRouter::DecrementBlockCount(uint64 request_id, |
| } |
| } |
| +void ExtensionWebRequestEventRouter::OnRequestDeleted( |
| + net::URLRequest* request) { |
| + http_requests_.erase(request->identifier()); |
| +} |
| + |
| bool WebRequestAddEventListener::RunImpl() { |
| // Argument 0 is the callback, which we don't use here. |