OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/extensions/extension_webrequest_api.h" | 5 #include "chrome/browser/extensions/extension_webrequest_api.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/json/json_writer.h" | 9 #include "base/json/json_writer.h" |
10 #include "base/metrics/histogram.h" | 10 #include "base/metrics/histogram.h" |
11 #include "base/string_number_conversions.h" | 11 #include "base/string_number_conversions.h" |
12 #include "base/values.h" | 12 #include "base/values.h" |
13 #include "chrome/browser/extensions/extension_event_router_forwarder.h" | 13 #include "chrome/browser/extensions/extension_event_router_forwarder.h" |
14 #include "chrome/browser/extensions/extension_webrequest_api_constants.h" | 14 #include "chrome/browser/extensions/extension_webrequest_api_constants.h" |
15 #include "chrome/browser/profiles/profile.h" | 15 #include "chrome/browser/profiles/profile.h" |
16 #include "chrome/common/extensions/extension.h" | 16 #include "chrome/common/extensions/extension.h" |
17 #include "chrome/common/extensions/extension_extent.h" | 17 #include "chrome/common/extensions/extension_extent.h" |
18 #include "chrome/common/extensions/url_pattern.h" | 18 #include "chrome/common/extensions/url_pattern.h" |
19 #include "chrome/common/url_constants.h" | |
19 #include "content/browser/browser_thread.h" | 20 #include "content/browser/browser_thread.h" |
20 #include "net/base/net_errors.h" | 21 #include "net/base/net_errors.h" |
21 #include "net/url_request/url_request.h" | 22 #include "net/url_request/url_request.h" |
22 #include "googleurl/src/gurl.h" | 23 #include "googleurl/src/gurl.h" |
23 | 24 |
24 namespace keys = extension_webrequest_api_constants; | 25 namespace keys = extension_webrequest_api_constants; |
25 | 26 |
26 namespace { | 27 namespace { |
27 | 28 |
28 // List of all the webRequest events. | 29 // List of all the webRequest events. |
29 static const char *kWebRequestEvents[] = { | 30 static const char *kWebRequestEvents[] = { |
30 keys::kOnBeforeRedirect, | 31 keys::kOnBeforeRedirect, |
31 keys::kOnBeforeRequest, | 32 keys::kOnBeforeRequest, |
33 keys::kOnBeforeSendHeaders, | |
32 keys::kOnCompleted, | 34 keys::kOnCompleted, |
33 keys::kOnErrorOccurred, | 35 keys::kOnErrorOccurred, |
34 keys::kOnHeadersReceived, | 36 keys::kOnHeadersReceived, |
35 keys::kOnRequestSent | 37 keys::kOnRequestSent |
36 }; | 38 }; |
37 | 39 |
38 // TODO(mpcomplete): should this be a set of flags? | 40 // TODO(mpcomplete): should this be a set of flags? |
39 static const char* kRequestFilterTypes[] = { | 41 static const char* kRequestFilterTypes[] = { |
40 "main_frame", | 42 "main_frame", |
41 "sub_frame", | 43 "sub_frame", |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
99 // Internal representation of the extraInfoSpec parameter on webRequest events, | 101 // Internal representation of the extraInfoSpec parameter on webRequest events, |
100 // used to specify extra information to be included with network events. | 102 // used to specify extra information to be included with network events. |
101 struct ExtensionWebRequestEventRouter::ExtraInfoSpec { | 103 struct ExtensionWebRequestEventRouter::ExtraInfoSpec { |
102 enum Flags { | 104 enum Flags { |
103 REQUEST_LINE = 1<<0, | 105 REQUEST_LINE = 1<<0, |
104 REQUEST_HEADERS = 1<<1, | 106 REQUEST_HEADERS = 1<<1, |
105 STATUS_LINE = 1<<2, | 107 STATUS_LINE = 1<<2, |
106 RESPONSE_HEADERS = 1<<3, | 108 RESPONSE_HEADERS = 1<<3, |
107 REDIRECT_REQUEST_LINE = 1<<4, | 109 REDIRECT_REQUEST_LINE = 1<<4, |
108 REDIRECT_REQUEST_HEADERS = 1<<5, | 110 REDIRECT_REQUEST_HEADERS = 1<<5, |
109 BLOCKING = 1<<5, | 111 BLOCKING = 1<<6, |
110 }; | 112 }; |
111 | 113 |
112 static bool InitFromValue(const ListValue& value, int* extra_info_spec); | 114 static bool InitFromValue(const ListValue& value, int* extra_info_spec); |
113 }; | 115 }; |
114 | 116 |
115 // Represents a single unique listener to an event, along with whatever filter | 117 // Represents a single unique listener to an event, along with whatever filter |
116 // parameters and extra_info_spec were specified at the time the listener was | 118 // parameters and extra_info_spec were specified at the time the listener was |
117 // added. | 119 // added. |
118 struct ExtensionWebRequestEventRouter::EventListener { | 120 struct ExtensionWebRequestEventRouter::EventListener { |
119 std::string extension_id; | 121 std::string extension_id; |
(...skipping 21 matching lines...) Expand all Loading... | |
141 | 143 |
142 // The callback to call when we get a response from all event handlers. | 144 // The callback to call when we get a response from all event handlers. |
143 net::CompletionCallback* callback; | 145 net::CompletionCallback* callback; |
144 | 146 |
145 // Time the request was issued. Used for logging purposes. | 147 // Time the request was issued. Used for logging purposes. |
146 base::Time request_time; | 148 base::Time request_time; |
147 | 149 |
148 BlockedRequest() : num_handlers_blocking(0), callback(NULL) {} | 150 BlockedRequest() : num_handlers_blocking(0), callback(NULL) {} |
149 }; | 151 }; |
150 | 152 |
153 // 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 :).
| |
154 // lets us know when the URLRequest is deleted, so we can remove it from our | |
155 // tracked list. | |
156 class ExtensionWebRequestEventRouter::TrackedRequest | |
157 : public net::URLRequest::UserData { | |
158 public: | |
159 TrackedRequest(net::URLRequest* request, | |
160 ExtensionWebRequestEventRouter* router) | |
161 : router_(router), request_(request) { | |
162 request->SetUserData(router_, this); | |
163 } | |
164 virtual ~TrackedRequest() { | |
165 if (router_) | |
166 router_->OnRequestDeleted(request_); | |
167 } | |
168 | |
169 void StopTracking() { | |
170 ExtensionWebRequestEventRouter* key = router_; | |
171 router_ = NULL; | |
172 request_->SetUserData(key, NULL); // deletes |this| | |
173 } | |
174 | |
175 net::URLRequest* request() const { return request_; } | |
176 | |
177 private: | |
178 ExtensionWebRequestEventRouter* router_; | |
179 net::URLRequest* request_; | |
180 }; | |
181 | |
151 bool ExtensionWebRequestEventRouter::RequestFilter::InitFromValue( | 182 bool ExtensionWebRequestEventRouter::RequestFilter::InitFromValue( |
152 const DictionaryValue& value) { | 183 const DictionaryValue& value) { |
153 for (DictionaryValue::key_iterator key = value.begin_keys(); | 184 for (DictionaryValue::key_iterator key = value.begin_keys(); |
154 key != value.end_keys(); ++key) { | 185 key != value.end_keys(); ++key) { |
155 if (*key == "urls") { | 186 if (*key == "urls") { |
156 ListValue* urls_value = NULL; | 187 ListValue* urls_value = NULL; |
157 if (!value.GetList("urls", &urls_value)) | 188 if (!value.GetList("urls", &urls_value)) |
158 return false; | 189 return false; |
159 for (size_t i = 0; i < urls_value->GetSize(); ++i) { | 190 for (size_t i = 0; i < urls_value->GetSize(); ++i) { |
160 std::string url; | 191 std::string url; |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
221 | 252 |
222 // static | 253 // static |
223 ExtensionWebRequestEventRouter* ExtensionWebRequestEventRouter::GetInstance() { | 254 ExtensionWebRequestEventRouter* ExtensionWebRequestEventRouter::GetInstance() { |
224 return Singleton<ExtensionWebRequestEventRouter>::get(); | 255 return Singleton<ExtensionWebRequestEventRouter>::get(); |
225 } | 256 } |
226 | 257 |
227 ExtensionWebRequestEventRouter::ExtensionWebRequestEventRouter() { | 258 ExtensionWebRequestEventRouter::ExtensionWebRequestEventRouter() { |
228 } | 259 } |
229 | 260 |
230 ExtensionWebRequestEventRouter::~ExtensionWebRequestEventRouter() { | 261 ExtensionWebRequestEventRouter::~ExtensionWebRequestEventRouter() { |
262 for (HttpRequestMap::iterator it = http_requests_.begin(); | |
263 it != http_requests_.end(); ++it) { | |
264 it->second->StopTracking(); // deletes the object | |
265 } | |
231 } | 266 } |
232 | 267 |
233 bool ExtensionWebRequestEventRouter::OnBeforeRequest( | 268 bool ExtensionWebRequestEventRouter::OnBeforeRequest( |
234 ProfileId profile_id, | 269 ProfileId profile_id, |
235 ExtensionEventRouterForwarder* event_router, | 270 ExtensionEventRouterForwarder* event_router, |
236 net::URLRequest* request, | 271 net::URLRequest* request, |
237 net::CompletionCallback* callback) { | 272 net::CompletionCallback* callback) { |
238 // TODO(jochen): Figure out what to do with events from the system context. | 273 // TODO(jochen): Figure out what to do with events from the system context. |
239 if (profile_id == Profile::kInvalidProfileId) | 274 if (profile_id == Profile::kInvalidProfileId) |
240 return false; | 275 return false; |
241 std::vector<const EventListener*> listeners = | 276 std::vector<const EventListener*> listeners = |
242 GetMatchingListeners(profile_id, keys::kOnBeforeRequest, request->url()); | 277 GetMatchingListeners(profile_id, keys::kOnBeforeRequest, request->url()); |
243 if (listeners.empty()) | 278 if (listeners.empty()) |
244 return false; | 279 return false; |
245 | 280 |
281 // If this is an HTTP request, keep track of it. HTTP-specific events only | |
282 // have the request ID, so we'll need to look up the URLRequest from that. | |
283 if (request->url().SchemeIs(chrome::kHttpScheme) || | |
284 request->url().SchemeIs(chrome::kHttpsScheme)) { | |
285 http_requests_[request->identifier()] = new TrackedRequest(request, this); | |
286 } | |
287 | |
246 ListValue args; | 288 ListValue args; |
247 DictionaryValue* dict = new DictionaryValue(); | 289 DictionaryValue* dict = new DictionaryValue(); |
248 dict->SetString(keys::kUrlKey, request->url().spec()); | 290 dict->SetString(keys::kUrlKey, request->url().spec()); |
249 dict->SetString(keys::kMethodKey, request->method()); | 291 dict->SetString(keys::kMethodKey, request->method()); |
250 // TODO(mpcomplete): implement | 292 // TODO(mpcomplete): implement |
251 dict->SetInteger(keys::kTabIdKey, 0); | 293 dict->SetInteger(keys::kTabIdKey, 0); |
252 dict->SetString(keys::kRequestIdKey, | 294 dict->SetString(keys::kRequestIdKey, |
253 base::Uint64ToString(request->identifier())); | 295 base::Uint64ToString(request->identifier())); |
254 dict->SetString(keys::kTypeKey, "main_frame"); | 296 dict->SetString(keys::kTypeKey, "main_frame"); |
255 dict->SetInteger(keys::kTimeStampKey, 1); | 297 dict->SetInteger(keys::kTimeStampKey, 1); |
256 args.Append(dict); | 298 args.Append(dict); |
257 | 299 |
300 return DispatchEvent(profile_id, event_router, request, callback, listeners, | |
301 args); | |
302 } | |
303 | |
304 bool ExtensionWebRequestEventRouter::OnBeforeSendHeaders( | |
305 ProfileId profile_id, | |
306 ExtensionEventRouterForwarder* event_router, | |
307 uint64 request_id, | |
308 net::HttpRequestHeaders* headers, | |
309 net::CompletionCallback* callback) { | |
310 // TODO(jochen): Figure out what to do with events from the system context. | |
311 if (profile_id == Profile::kInvalidProfileId) | |
312 return false; | |
313 | |
314 HttpRequestMap::iterator iter = http_requests_.find(request_id); | |
315 if (iter == http_requests_.end()) | |
316 return false; | |
317 | |
318 net::URLRequest* request = iter->second->request(); | |
319 iter->second->StopTracking(); | |
320 http_requests_.erase(iter); | |
321 | |
322 std::vector<const EventListener*> listeners = | |
323 GetMatchingListeners(profile_id, keys::kOnBeforeSendHeaders, request); | |
324 if (listeners.empty()) | |
325 return false; | |
326 | |
327 ListValue args; | |
328 DictionaryValue* dict = new DictionaryValue(); | |
329 dict->SetString(keys::kRequestIdKey, | |
330 base::Uint64ToString(request->identifier())); | |
331 dict->SetString(keys::kUrlKey, request->url().spec()); | |
332 dict->SetDouble(keys::kTimeStampKey, base::Time::Now().ToDoubleT() * 1000); | |
333 // TODO(mpcomplete): request headers. | |
334 args.Append(dict); | |
335 | |
336 return DispatchEvent(profile_id, event_router, request, callback, listeners, | |
337 args); | |
338 } | |
339 | |
340 bool ExtensionWebRequestEventRouter::DispatchEvent( | |
341 ProfileId profile_id, | |
342 ExtensionEventRouterForwarder* event_router, | |
343 net::URLRequest* request, | |
344 net::CompletionCallback* callback, | |
345 const std::vector<const EventListener*>& listeners, | |
346 const ListValue& args) { | |
258 std::string json_args; | 347 std::string json_args; |
259 base::JSONWriter::Write(&args, false, &json_args); | 348 base::JSONWriter::Write(&args, false, &json_args); |
260 | 349 |
261 // TODO(mpcomplete): Consider consolidating common (extension_id,json_args) | 350 // TODO(mpcomplete): Consider consolidating common (extension_id,json_args) |
262 // pairs into a single message sent to a list of sub_event_names. | 351 // pairs into a single message sent to a list of sub_event_names. |
263 int num_handlers_blocking = 0; | 352 int num_handlers_blocking = 0; |
264 for (std::vector<const EventListener*>::iterator it = listeners.begin(); | 353 for (std::vector<const EventListener*>::const_iterator it = listeners.begin(); |
265 it != listeners.end(); ++it) { | 354 it != listeners.end(); ++it) { |
266 event_router->DispatchEventToExtension( | 355 event_router->DispatchEventToExtension( |
267 (*it)->extension_id, (*it)->sub_event_name, json_args, | 356 (*it)->extension_id, (*it)->sub_event_name, json_args, |
268 profile_id, true, GURL()); | 357 profile_id, true, GURL()); |
269 if ((*it)->extra_info_spec & ExtraInfoSpec::BLOCKING) { | 358 if (callback && (*it)->extra_info_spec & ExtraInfoSpec::BLOCKING) { |
270 (*it)->blocked_requests.insert(request->identifier()); | 359 (*it)->blocked_requests.insert(request->identifier()); |
271 ++num_handlers_blocking; | 360 ++num_handlers_blocking; |
272 } | 361 } |
273 } | 362 } |
274 | 363 |
275 if (num_handlers_blocking > 0) { | 364 if (num_handlers_blocking > 0) { |
276 CHECK(blocked_requests_.find(request->identifier()) == | 365 CHECK(blocked_requests_.find(request->identifier()) == |
277 blocked_requests_.end()); | 366 blocked_requests_.end()); |
278 blocked_requests_[request->identifier()].num_handlers_blocking = | 367 blocked_requests_[request->identifier()].num_handlers_blocking = |
279 num_handlers_blocking; | 368 num_handlers_blocking; |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
367 std::vector<const EventListener*> matching_listeners; | 456 std::vector<const EventListener*> matching_listeners; |
368 std::set<EventListener>& listeners = listeners_[profile_id][event_name]; | 457 std::set<EventListener>& listeners = listeners_[profile_id][event_name]; |
369 for (std::set<EventListener>::iterator it = listeners.begin(); | 458 for (std::set<EventListener>::iterator it = listeners.begin(); |
370 it != listeners.end(); ++it) { | 459 it != listeners.end(); ++it) { |
371 if (it->filter.urls.is_empty() || it->filter.urls.ContainsURL(url)) | 460 if (it->filter.urls.is_empty() || it->filter.urls.ContainsURL(url)) |
372 matching_listeners.push_back(&(*it)); | 461 matching_listeners.push_back(&(*it)); |
373 } | 462 } |
374 return matching_listeners; | 463 return matching_listeners; |
375 } | 464 } |
376 | 465 |
466 std::vector<const ExtensionWebRequestEventRouter::EventListener*> | |
467 ExtensionWebRequestEventRouter::GetMatchingListeners( | |
468 ProfileId profile_id, | |
469 const std::string& event_name, | |
470 net::URLRequest* request) { | |
471 int tab_id = -1; | |
472 int window_id = -1; | |
473 ResourceType::Type resource_type = ResourceType::LAST_TYPE; | |
474 ExtractRequestInfo(request, &tab_id, &window_id, &resource_type); | |
475 | |
476 return GetMatchingListeners( | |
477 profile_id, event_name, request->url(), tab_id, window_id, resource_type); | |
478 } | |
479 | |
377 void ExtensionWebRequestEventRouter::DecrementBlockCount(uint64 request_id, | 480 void ExtensionWebRequestEventRouter::DecrementBlockCount(uint64 request_id, |
378 bool cancel) { | 481 bool cancel) { |
379 // It's possible that this request was already cancelled by a previous event | 482 // It's possible that this request was already cancelled by a previous event |
380 // handler. If so, ignore this response. | 483 // handler. If so, ignore this response. |
381 if (blocked_requests_.find(request_id) == blocked_requests_.end()) | 484 if (blocked_requests_.find(request_id) == blocked_requests_.end()) |
382 return; | 485 return; |
383 | 486 |
384 BlockedRequest& blocked_request = blocked_requests_[request_id]; | 487 BlockedRequest& blocked_request = blocked_requests_[request_id]; |
385 int num_handlers_blocking = --blocked_request.num_handlers_blocking; | 488 int num_handlers_blocking = --blocked_request.num_handlers_blocking; |
386 CHECK_GE(num_handlers_blocking, 0); | 489 CHECK_GE(num_handlers_blocking, 0); |
387 | 490 |
388 HISTOGRAM_TIMES("Extensions.NetworkDelay", | 491 HISTOGRAM_TIMES("Extensions.NetworkDelay", |
389 base::Time::Now() - blocked_request.request_time); | 492 base::Time::Now() - blocked_request.request_time); |
390 | 493 |
391 if (num_handlers_blocking == 0 || cancel) { | 494 if (num_handlers_blocking == 0 || cancel) { |
392 CHECK(blocked_request.callback); | 495 CHECK(blocked_request.callback); |
393 blocked_request.callback->Run(cancel ? net::ERR_EMPTY_RESPONSE : net::OK); | 496 blocked_request.callback->Run(cancel ? net::ERR_EMPTY_RESPONSE : net::OK); |
394 blocked_requests_.erase(request_id); | 497 blocked_requests_.erase(request_id); |
395 } | 498 } |
396 } | 499 } |
397 | 500 |
501 void ExtensionWebRequestEventRouter::OnRequestDeleted( | |
502 net::URLRequest* request) { | |
503 http_requests_.erase(request->identifier()); | |
504 } | |
505 | |
398 bool WebRequestAddEventListener::RunImpl() { | 506 bool WebRequestAddEventListener::RunImpl() { |
399 // Argument 0 is the callback, which we don't use here. | 507 // Argument 0 is the callback, which we don't use here. |
400 | 508 |
401 ExtensionWebRequestEventRouter::RequestFilter filter; | 509 ExtensionWebRequestEventRouter::RequestFilter filter; |
402 if (HasOptionalArgument(1)) { | 510 if (HasOptionalArgument(1)) { |
403 DictionaryValue* value = NULL; | 511 DictionaryValue* value = NULL; |
404 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &value)); | 512 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &value)); |
405 EXTENSION_FUNCTION_VALIDATE(filter.InitFromValue(*value)); | 513 EXTENSION_FUNCTION_VALIDATE(filter.InitFromValue(*value)); |
406 } | 514 } |
407 | 515 |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
454 | 562 |
455 BrowserThread::PostTask( | 563 BrowserThread::PostTask( |
456 BrowserThread::IO, FROM_HERE, | 564 BrowserThread::IO, FROM_HERE, |
457 NewRunnableFunction( | 565 NewRunnableFunction( |
458 &EventHandledOnIOThread, | 566 &EventHandledOnIOThread, |
459 profile()->GetRuntimeId(), extension_id(), | 567 profile()->GetRuntimeId(), extension_id(), |
460 event_name, sub_event_name, request_id, cancel)); | 568 event_name, sub_event_name, request_id, cancel)); |
461 | 569 |
462 return true; | 570 return true; |
463 } | 571 } |
OLD | NEW |