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. |