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_tab_id_map.h" | 14 #include "chrome/browser/extensions/extension_tab_id_map.h" |
15 #include "chrome/browser/extensions/extension_webrequest_api_constants.h" | 15 #include "chrome/browser/extensions/extension_webrequest_api_constants.h" |
16 #include "chrome/browser/profiles/profile.h" | 16 #include "chrome/browser/profiles/profile.h" |
17 #include "chrome/common/extensions/extension.h" | 17 #include "chrome/common/extensions/extension.h" |
18 #include "chrome/common/extensions/extension_extent.h" | 18 #include "chrome/common/extensions/extension_extent.h" |
19 #include "chrome/common/extensions/url_pattern.h" | 19 #include "chrome/common/extensions/url_pattern.h" |
| 20 #include "chrome/common/url_constants.h" |
20 #include "content/browser/browser_thread.h" | 21 #include "content/browser/browser_thread.h" |
21 #include "content/browser/renderer_host/resource_dispatcher_host.h" | 22 #include "content/browser/renderer_host/resource_dispatcher_host.h" |
22 #include "content/browser/renderer_host/resource_dispatcher_host_request_info.h" | 23 #include "content/browser/renderer_host/resource_dispatcher_host_request_info.h" |
23 #include "net/base/net_errors.h" | 24 #include "net/base/net_errors.h" |
24 #include "net/url_request/url_request.h" | 25 #include "net/url_request/url_request.h" |
25 #include "googleurl/src/gurl.h" | 26 #include "googleurl/src/gurl.h" |
26 | 27 |
27 namespace keys = extension_webrequest_api_constants; | 28 namespace keys = extension_webrequest_api_constants; |
28 | 29 |
29 namespace { | 30 namespace { |
30 | 31 |
31 // List of all the webRequest events. | 32 // List of all the webRequest events. |
32 static const char *kWebRequestEvents[] = { | 33 static const char *kWebRequestEvents[] = { |
33 keys::kOnBeforeRedirect, | 34 keys::kOnBeforeRedirect, |
34 keys::kOnBeforeRequest, | 35 keys::kOnBeforeRequest, |
| 36 keys::kOnBeforeSendHeaders, |
35 keys::kOnCompleted, | 37 keys::kOnCompleted, |
36 keys::kOnErrorOccurred, | 38 keys::kOnErrorOccurred, |
37 keys::kOnHeadersReceived, | 39 keys::kOnHeadersReceived, |
38 keys::kOnRequestSent | 40 keys::kOnRequestSent |
39 }; | 41 }; |
40 | 42 |
41 static const char* kResourceTypeStrings[] = { | 43 static const char* kResourceTypeStrings[] = { |
42 "main_frame", | 44 "main_frame", |
43 "sub_frame", | 45 "sub_frame", |
44 "stylesheet", | 46 "stylesheet", |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
148 // Internal representation of the extraInfoSpec parameter on webRequest events, | 150 // Internal representation of the extraInfoSpec parameter on webRequest events, |
149 // used to specify extra information to be included with network events. | 151 // used to specify extra information to be included with network events. |
150 struct ExtensionWebRequestEventRouter::ExtraInfoSpec { | 152 struct ExtensionWebRequestEventRouter::ExtraInfoSpec { |
151 enum Flags { | 153 enum Flags { |
152 REQUEST_LINE = 1<<0, | 154 REQUEST_LINE = 1<<0, |
153 REQUEST_HEADERS = 1<<1, | 155 REQUEST_HEADERS = 1<<1, |
154 STATUS_LINE = 1<<2, | 156 STATUS_LINE = 1<<2, |
155 RESPONSE_HEADERS = 1<<3, | 157 RESPONSE_HEADERS = 1<<3, |
156 REDIRECT_REQUEST_LINE = 1<<4, | 158 REDIRECT_REQUEST_LINE = 1<<4, |
157 REDIRECT_REQUEST_HEADERS = 1<<5, | 159 REDIRECT_REQUEST_HEADERS = 1<<5, |
158 BLOCKING = 1<<5, | 160 BLOCKING = 1<<6, |
159 }; | 161 }; |
160 | 162 |
161 static bool InitFromValue(const ListValue& value, int* extra_info_spec); | 163 static bool InitFromValue(const ListValue& value, int* extra_info_spec); |
162 }; | 164 }; |
163 | 165 |
164 // Represents a single unique listener to an event, along with whatever filter | 166 // Represents a single unique listener to an event, along with whatever filter |
165 // parameters and extra_info_spec were specified at the time the listener was | 167 // parameters and extra_info_spec were specified at the time the listener was |
166 // added. | 168 // added. |
167 struct ExtensionWebRequestEventRouter::EventListener { | 169 struct ExtensionWebRequestEventRouter::EventListener { |
168 std::string extension_id; | 170 std::string extension_id; |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
293 int window_id = -1; | 295 int window_id = -1; |
294 ResourceType::Type resource_type = ResourceType::LAST_TYPE; | 296 ResourceType::Type resource_type = ResourceType::LAST_TYPE; |
295 ExtractRequestInfo(request, &tab_id, &window_id, &resource_type); | 297 ExtractRequestInfo(request, &tab_id, &window_id, &resource_type); |
296 | 298 |
297 std::vector<const EventListener*> listeners = | 299 std::vector<const EventListener*> listeners = |
298 GetMatchingListeners(profile_id, keys::kOnBeforeRequest, request->url(), | 300 GetMatchingListeners(profile_id, keys::kOnBeforeRequest, request->url(), |
299 tab_id, window_id, resource_type); | 301 tab_id, window_id, resource_type); |
300 if (listeners.empty()) | 302 if (listeners.empty()) |
301 return false; | 303 return false; |
302 | 304 |
| 305 // If this is an HTTP request, keep track of it. HTTP-specific events only |
| 306 // have the request ID, so we'll need to look up the URLRequest from that. |
| 307 if (request->url().SchemeIs(chrome::kHttpScheme) || |
| 308 request->url().SchemeIs(chrome::kHttpsScheme)) { |
| 309 http_requests_[request->identifier()] = request; |
| 310 } |
| 311 |
303 ListValue args; | 312 ListValue args; |
304 DictionaryValue* dict = new DictionaryValue(); | 313 DictionaryValue* dict = new DictionaryValue(); |
305 dict->SetString(keys::kRequestIdKey, | 314 dict->SetString(keys::kRequestIdKey, |
306 base::Uint64ToString(request->identifier())); | 315 base::Uint64ToString(request->identifier())); |
307 dict->SetString(keys::kUrlKey, request->url().spec()); | 316 dict->SetString(keys::kUrlKey, request->url().spec()); |
308 dict->SetString(keys::kMethodKey, request->method()); | 317 dict->SetString(keys::kMethodKey, request->method()); |
309 dict->SetInteger(keys::kTabIdKey, tab_id); | 318 dict->SetInteger(keys::kTabIdKey, tab_id); |
310 dict->SetString(keys::kTypeKey, ResourceTypeToString(resource_type)); | 319 dict->SetString(keys::kTypeKey, ResourceTypeToString(resource_type)); |
311 dict->SetDouble(keys::kTimeStampKey, | 320 dict->SetDouble(keys::kTimeStampKey, |
312 request->request_time().ToDoubleT() * 1000); | 321 request->request_time().ToDoubleT() * 1000); |
313 args.Append(dict); | 322 args.Append(dict); |
314 | 323 |
| 324 return DispatchEvent(profile_id, event_router, request, callback, listeners, |
| 325 args); |
| 326 } |
| 327 |
| 328 bool ExtensionWebRequestEventRouter::OnBeforeSendHeaders( |
| 329 ProfileId profile_id, |
| 330 ExtensionEventRouterForwarder* event_router, |
| 331 uint64 request_id, |
| 332 net::HttpRequestHeaders* headers, |
| 333 net::CompletionCallback* callback) { |
| 334 // TODO(jochen): Figure out what to do with events from the system context. |
| 335 if (profile_id == Profile::kInvalidProfileId) |
| 336 return false; |
| 337 |
| 338 HttpRequestMap::iterator iter = http_requests_.find(request_id); |
| 339 if (iter == http_requests_.end()) |
| 340 return false; |
| 341 |
| 342 net::URLRequest* request = iter->second; |
| 343 http_requests_.erase(iter); |
| 344 |
| 345 std::vector<const EventListener*> listeners = |
| 346 GetMatchingListeners(profile_id, keys::kOnBeforeSendHeaders, request); |
| 347 if (listeners.empty()) |
| 348 return false; |
| 349 |
| 350 ListValue args; |
| 351 DictionaryValue* dict = new DictionaryValue(); |
| 352 dict->SetString(keys::kUrlKey, request->url().spec()); |
| 353 dict->SetDouble(keys::kTimeStampKey, base::Time::Now().ToDoubleT() * 1000); |
| 354 // TODO(mpcomplete): request headers. |
| 355 return DispatchEvent(profile_id, event_router, request, callback, listeners, |
| 356 args); |
| 357 } |
| 358 |
| 359 void ExtensionWebRequestEventRouter::OnURLRequestDestroyed( |
| 360 ProfileId profile_id, net::URLRequest* request) { |
| 361 http_requests_.erase(request->identifier()); |
| 362 } |
| 363 |
| 364 bool ExtensionWebRequestEventRouter::DispatchEvent( |
| 365 ProfileId profile_id, |
| 366 ExtensionEventRouterForwarder* event_router, |
| 367 net::URLRequest* request, |
| 368 net::CompletionCallback* callback, |
| 369 const std::vector<const EventListener*>& listeners, |
| 370 const ListValue& args) { |
315 std::string json_args; | 371 std::string json_args; |
316 base::JSONWriter::Write(&args, false, &json_args); | 372 base::JSONWriter::Write(&args, false, &json_args); |
317 | 373 |
318 // TODO(mpcomplete): Consider consolidating common (extension_id,json_args) | 374 // TODO(mpcomplete): Consider consolidating common (extension_id,json_args) |
319 // pairs into a single message sent to a list of sub_event_names. | 375 // pairs into a single message sent to a list of sub_event_names. |
320 int num_handlers_blocking = 0; | 376 int num_handlers_blocking = 0; |
321 for (std::vector<const EventListener*>::iterator it = listeners.begin(); | 377 for (std::vector<const EventListener*>::const_iterator it = listeners.begin(); |
322 it != listeners.end(); ++it) { | 378 it != listeners.end(); ++it) { |
323 event_router->DispatchEventToExtension( | 379 event_router->DispatchEventToExtension( |
324 (*it)->extension_id, (*it)->sub_event_name, json_args, | 380 (*it)->extension_id, (*it)->sub_event_name, json_args, |
325 profile_id, true, GURL()); | 381 profile_id, true, GURL()); |
326 if ((*it)->extra_info_spec & ExtraInfoSpec::BLOCKING) { | 382 if (callback && (*it)->extra_info_spec & ExtraInfoSpec::BLOCKING) { |
327 (*it)->blocked_requests.insert(request->identifier()); | 383 (*it)->blocked_requests.insert(request->identifier()); |
328 ++num_handlers_blocking; | 384 ++num_handlers_blocking; |
329 } | 385 } |
330 } | 386 } |
331 | 387 |
332 if (num_handlers_blocking > 0) { | 388 if (num_handlers_blocking > 0) { |
333 CHECK(blocked_requests_.find(request->identifier()) == | 389 CHECK(blocked_requests_.find(request->identifier()) == |
334 blocked_requests_.end()); | 390 blocked_requests_.end()); |
335 blocked_requests_[request->identifier()].num_handlers_blocking = | 391 blocked_requests_[request->identifier()].num_handlers_blocking = |
336 num_handlers_blocking; | 392 num_handlers_blocking; |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
437 if (!it->filter.types.empty() && | 493 if (!it->filter.types.empty() && |
438 std::find(it->filter.types.begin(), it->filter.types.end(), | 494 std::find(it->filter.types.begin(), it->filter.types.end(), |
439 resource_type) == it->filter.types.end()) | 495 resource_type) == it->filter.types.end()) |
440 continue; | 496 continue; |
441 | 497 |
442 matching_listeners.push_back(&(*it)); | 498 matching_listeners.push_back(&(*it)); |
443 } | 499 } |
444 return matching_listeners; | 500 return matching_listeners; |
445 } | 501 } |
446 | 502 |
| 503 std::vector<const ExtensionWebRequestEventRouter::EventListener*> |
| 504 ExtensionWebRequestEventRouter::GetMatchingListeners( |
| 505 ProfileId profile_id, |
| 506 const std::string& event_name, |
| 507 net::URLRequest* request) { |
| 508 int tab_id = -1; |
| 509 int window_id = -1; |
| 510 ResourceType::Type resource_type = ResourceType::LAST_TYPE; |
| 511 ExtractRequestInfo(request, &tab_id, &window_id, &resource_type); |
| 512 |
| 513 return GetMatchingListeners( |
| 514 profile_id, event_name, request->url(), tab_id, window_id, resource_type); |
| 515 } |
| 516 |
447 void ExtensionWebRequestEventRouter::DecrementBlockCount(uint64 request_id, | 517 void ExtensionWebRequestEventRouter::DecrementBlockCount(uint64 request_id, |
448 bool cancel) { | 518 bool cancel) { |
449 // It's possible that this request was already cancelled by a previous event | 519 // It's possible that this request was already cancelled by a previous event |
450 // handler. If so, ignore this response. | 520 // handler. If so, ignore this response. |
451 if (blocked_requests_.find(request_id) == blocked_requests_.end()) | 521 if (blocked_requests_.find(request_id) == blocked_requests_.end()) |
452 return; | 522 return; |
453 | 523 |
454 BlockedRequest& blocked_request = blocked_requests_[request_id]; | 524 BlockedRequest& blocked_request = blocked_requests_[request_id]; |
455 int num_handlers_blocking = --blocked_request.num_handlers_blocking; | 525 int num_handlers_blocking = --blocked_request.num_handlers_blocking; |
456 CHECK_GE(num_handlers_blocking, 0); | 526 CHECK_GE(num_handlers_blocking, 0); |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
524 | 594 |
525 BrowserThread::PostTask( | 595 BrowserThread::PostTask( |
526 BrowserThread::IO, FROM_HERE, | 596 BrowserThread::IO, FROM_HERE, |
527 NewRunnableFunction( | 597 NewRunnableFunction( |
528 &EventHandledOnIOThread, | 598 &EventHandledOnIOThread, |
529 profile()->GetRuntimeId(), extension_id(), | 599 profile()->GetRuntimeId(), extension_id(), |
530 event_name, sub_event_name, request_id, cancel)); | 600 event_name, sub_event_name, request_id, cancel)); |
531 | 601 |
532 return true; | 602 return true; |
533 } | 603 } |
OLD | NEW |