1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/extensions/api/web_request/web_request_api.h"
10 #include "base/bind_helpers.h"
11 #include "base/json/json_writer.h"
12 #include "base/lazy_instance.h"
13 #include "base/metrics/histogram.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/string_util.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "base/time/time.h"
18 #include "base/values.h"
19 #include "chrome/browser/browser_process.h"
20 #include "chrome/browser/chrome_content_browser_client.h"
21 #include "chrome/browser/extensions/activity_log/activity_action_constants.h"
22 #include "chrome/browser/extensions/activity_log/activity_actions.h"
23 #include "chrome/browser/extensions/activity_log/activity_log.h"
24 #include "chrome/browser/extensions/activity_log/web_request_constants.h"
25 #include "chrome/browser/extensions/api/declarative_webrequest/request_stage.h"
26 #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_constants.h"
27 #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry.h"
28 #include "chrome/browser/extensions/api/web_navigation/web_navigation_api_helpers.h"
29 #include "chrome/browser/extensions/api/web_request/upload_data_presenter.h"
30 #include "chrome/browser/extensions/api/web_request/web_request_api_constants.h"
31 #include "chrome/browser/extensions/api/web_request/web_request_api_helpers.h"
32 #include "chrome/browser/extensions/api/web_request/web_request_time_tracker.h"
33 #include "chrome/browser/extensions/extension_renderer_state.h"
34 #include "chrome/browser/extensions/extension_warning_service.h"
35 #include "chrome/browser/extensions/extension_warning_set.h"
36 #include "chrome/browser/profiles/profile.h"
37 #include "chrome/browser/profiles/profile_manager.h"
38 #include "chrome/common/extensions/api/web_request.h"
39 #include "chrome/common/extensions/extension_constants.h"
40 #include "chrome/common/url_constants.h"
41 #include "content/public/browser/browser_message_filter.h"
42 #include "content/public/browser/browser_thread.h"
43 #include "content/public/browser/render_process_host.h"
44 #include "content/public/browser/resource_request_info.h"
45 #include "content/public/browser/user_metrics.h"
46 #include "extensions/browser/event_router.h"
47 #include "extensions/browser/extension_message_filter.h"
48 #include "extensions/browser/extension_prefs.h"
49 #include "extensions/browser/extension_registry.h"
50 #include "extensions/browser/extension_system.h"
51 #include "extensions/browser/info_map.h"
52 #include "extensions/browser/runtime_data.h"
53 #include "extensions/common/error_utils.h"
54 #include "extensions/common/event_filtering_info.h"
55 #include "extensions/common/extension.h"
56 #include "extensions/common/extension_messages.h"
57 #include "extensions/common/extension_set.h"
58 #include "extensions/common/features/feature.h"
59 #include "extensions/common/permissions/permissions_data.h"
60 #include "extensions/common/url_pattern.h"
61 #include "grit/generated_resources.h"
62 #include "net/base/auth.h"
63 #include "net/base/net_errors.h"
64 #include "net/base/upload_data_stream.h"
65 #include "net/http/http_response_headers.h"
66 #include "net/url_request/url_request.h"
67 #include "ui/base/l10n/l10n_util.h"
70 using base::DictionaryValue;
71 using base::ListValue;
72 using base::StringValue;
73 using content::BrowserMessageFilter;
74 using content::BrowserThread;
75 using content::ResourceRequestInfo;
76 using extensions::ErrorUtils;
77 using extensions::Extension;
78 using extensions::ExtensionWarning;
79 using extensions::ExtensionWarningService;
80 using extensions::ExtensionWarningSet;
81 using extensions::InfoMap;
82 using extensions::Feature;
83 using extensions::RulesRegistryService;
84 using extensions::web_navigation_api_helpers::GetFrameId;
86 namespace helpers = extension_web_request_api_helpers;
87 namespace keys = extension_web_request_api_constants;
88 namespace web_request = extensions::api::web_request;
89 namespace declarative_keys = extensions::declarative_webrequest_constants;
90 namespace activitylog = activity_log_web_request_constants;
94 const char kWebRequest[] = "webRequest";
95 const char kWebView[] = "webview";
97 // List of all the webRequest events.
98 const char* const kWebRequestEvents[] = {
99 keys::kOnBeforeRedirectEvent,
100 web_request::OnBeforeRequest::kEventName,
101 keys::kOnBeforeSendHeadersEvent,
102 keys::kOnCompletedEvent,
103 web_request::OnErrorOccurred::kEventName,
104 keys::kOnSendHeadersEvent,
105 keys::kOnAuthRequiredEvent,
106 keys::kOnResponseStartedEvent,
107 keys::kOnHeadersReceivedEvent,
110 #define ARRAYEND(array) (array + arraysize(array))
112 const char* GetRequestStageAsString(
113 ExtensionWebRequestEventRouter::EventTypes type) {
115 case ExtensionWebRequestEventRouter::kInvalidEvent:
117 case ExtensionWebRequestEventRouter::kOnBeforeRequest:
118 return keys::kOnBeforeRequest;
119 case ExtensionWebRequestEventRouter::kOnBeforeSendHeaders:
120 return keys::kOnBeforeSendHeaders;
121 case ExtensionWebRequestEventRouter::kOnSendHeaders:
122 return keys::kOnSendHeaders;
123 case ExtensionWebRequestEventRouter::kOnHeadersReceived:
124 return keys::kOnHeadersReceived;
125 case ExtensionWebRequestEventRouter::kOnBeforeRedirect:
126 return keys::kOnBeforeRedirect;
127 case ExtensionWebRequestEventRouter::kOnAuthRequired:
128 return keys::kOnAuthRequired;
129 case ExtensionWebRequestEventRouter::kOnResponseStarted:
130 return keys::kOnResponseStarted;
131 case ExtensionWebRequestEventRouter::kOnErrorOccurred:
132 return keys::kOnErrorOccurred;
133 case ExtensionWebRequestEventRouter::kOnCompleted:
134 return keys::kOnCompleted;
137 return "Not reached";
140 bool IsWebRequestEvent(const std::string& event_name) {
141 std::string web_request_event_name(event_name);
142 if (web_request_event_name.find(kWebView) != std::string::npos)
143 web_request_event_name.replace(0, sizeof(kWebView) - 1, kWebRequest);
144 return std::find(kWebRequestEvents, ARRAYEND(kWebRequestEvents),
145 web_request_event_name) != ARRAYEND(kWebRequestEvents);
148 // Returns whether |request| has been triggered by an extension in
149 // |extension_info_map|.
150 bool IsRequestFromExtension(const net::URLRequest* request,
151 const InfoMap* extension_info_map) {
152 // |extension_info_map| is NULL for system-level requests.
153 if (!extension_info_map)
156 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
158 // If this request was not created by the ResourceDispatcher, |info| is NULL.
159 // All requests from extensions are created by the ResourceDispatcher.
163 return extension_info_map->process_map().Contains(info->GetChildID());
166 void ExtractRequestInfoDetails(net::URLRequest* request,
169 bool* parent_is_main_frame,
170 int64* parent_frame_id,
173 int* render_process_host_id,
175 ResourceType::Type* resource_type) {
176 if (!request->GetUserData(NULL))
179 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
180 ExtensionRendererState::GetInstance()->GetTabAndWindowId(
181 info, tab_id, window_id);
182 *frame_id = info->GetRenderFrameID();
183 *is_main_frame = info->IsMainFrame();
184 *parent_frame_id = info->GetParentRenderFrameID();
185 *parent_is_main_frame = info->ParentIsMainFrame();
186 *render_process_host_id = info->GetChildID();
187 *routing_id = info->GetRouteID();
189 // Restrict the resource type to the values we care about.
190 if (helpers::IsRelevantResourceType(info->GetResourceType()))
191 *resource_type = info->GetResourceType();
193 *resource_type = ResourceType::LAST_TYPE;
196 // Extracts from |request| information for the keys requestId, url, method,
197 // frameId, tabId, type, and timeStamp and writes these into |out| to be passed
199 void ExtractRequestInfo(net::URLRequest* request, base::DictionaryValue* out) {
200 bool is_main_frame = false;
202 bool parent_is_main_frame = false;
203 int64 parent_frame_id = -1;
204 int frame_id_for_extension = -1;
205 int parent_frame_id_for_extension = -1;
208 int render_process_host_id = -1;
210 ResourceType::Type resource_type = ResourceType::LAST_TYPE;
211 ExtractRequestInfoDetails(request, &is_main_frame, &frame_id,
212 &parent_is_main_frame, &parent_frame_id, &tab_id,
213 &window_id, &render_process_host_id, &routing_id,
215 frame_id_for_extension = GetFrameId(is_main_frame, frame_id);
216 parent_frame_id_for_extension = GetFrameId(parent_is_main_frame,
219 out->SetString(keys::kRequestIdKey,
220 base::Uint64ToString(request->identifier()));
221 out->SetString(keys::kUrlKey, request->url().spec());
222 out->SetString(keys::kMethodKey, request->method());
223 out->SetInteger(keys::kFrameIdKey, frame_id_for_extension);
224 out->SetInteger(keys::kParentFrameIdKey, parent_frame_id_for_extension);
225 out->SetInteger(keys::kTabIdKey, tab_id);
226 out->SetString(keys::kTypeKey, helpers::ResourceTypeToString(resource_type));
227 out->SetDouble(keys::kTimeStampKey, base::Time::Now().ToDoubleT() * 1000);
230 // Extracts the body from |request| and writes the data into |out|.
231 void ExtractRequestInfoBody(const net::URLRequest* request,
232 base::DictionaryValue* out) {
233 const net::UploadDataStream* upload_data = request->get_upload();
235 (request->method() != "POST" && request->method() != "PUT"))
236 return; // Need to exit without "out->Set(keys::kRequestBodyKey, ...);" .
238 base::DictionaryValue* requestBody = new base::DictionaryValue();
239 out->Set(keys::kRequestBodyKey, requestBody);
241 // Get the data presenters, ordered by how specific they are.
242 extensions::ParsedDataPresenter parsed_data_presenter(*request);
243 extensions::RawDataPresenter raw_data_presenter;
244 extensions::UploadDataPresenter* const presenters[] = {
245 &parsed_data_presenter, // 1: any parseable forms? (Specific to forms.)
246 &raw_data_presenter // 2: any data at all? (Non-specific.)
248 // Keys for the results of the corresponding presenters.
249 static const char* const kKeys[] = {
250 keys::kRequestBodyFormDataKey,
251 keys::kRequestBodyRawKey
254 const ScopedVector<net::UploadElementReader>& readers =
255 upload_data->element_readers();
256 bool some_succeeded = false;
257 for (size_t i = 0; !some_succeeded && i < arraysize(presenters); ++i) {
258 ScopedVector<net::UploadElementReader>::const_iterator reader;
259 for (reader = readers.begin(); reader != readers.end(); ++reader)
260 presenters[i]->FeedNext(**reader);
261 if (presenters[i]->Succeeded()) {
262 requestBody->Set(kKeys[i], presenters[i]->Result().release());
263 some_succeeded = true;
267 requestBody->SetString(keys::kRequestBodyErrorKey, "Unknown error.");
270 // Converts a HttpHeaders dictionary to a |name|, |value| pair. Returns
271 // true if successful.
272 bool FromHeaderDictionary(const base::DictionaryValue* header_value,
274 std::string* value) {
275 if (!header_value->GetString(keys::kHeaderNameKey, name))
278 // We require either a "value" or a "binaryValue" entry.
279 if (!(header_value->HasKey(keys::kHeaderValueKey) ^
280 header_value->HasKey(keys::kHeaderBinaryValueKey)))
283 if (header_value->HasKey(keys::kHeaderValueKey)) {
284 if (!header_value->GetString(keys::kHeaderValueKey, value)) {
287 } else if (header_value->HasKey(keys::kHeaderBinaryValueKey)) {
288 const base::ListValue* list = NULL;
289 if (!header_value->HasKey(keys::kHeaderBinaryValueKey)) {
291 } else if (!header_value->GetList(keys::kHeaderBinaryValueKey, &list) ||
292 !helpers::CharListToString(list, value)) {
299 // Converts the |name|, |value| pair of a http header to a HttpHeaders
300 // dictionary. Ownership is passed to the caller.
301 base::DictionaryValue* ToHeaderDictionary(const std::string& name,
302 const std::string& value) {
303 base::DictionaryValue* header = new base::DictionaryValue();
304 header->SetString(keys::kHeaderNameKey, name);
305 if (base::IsStringUTF8(value)) {
306 header->SetString(keys::kHeaderValueKey, value);
308 header->Set(keys::kHeaderBinaryValueKey,
309 helpers::StringToCharList(value));
314 // Creates a list of HttpHeaders (see the extension API JSON). If |headers| is
315 // NULL, the list is empty. Ownership is passed to the caller.
316 base::ListValue* GetResponseHeadersList(
317 const net::HttpResponseHeaders* headers) {
318 base::ListValue* headers_value = new base::ListValue();
323 while (headers->EnumerateHeaderLines(&iter, &name, &value))
324 headers_value->Append(ToHeaderDictionary(name, value));
326 return headers_value;
329 base::ListValue* GetRequestHeadersList(const net::HttpRequestHeaders& headers) {
330 base::ListValue* headers_value = new base::ListValue();
331 for (net::HttpRequestHeaders::Iterator it(headers); it.GetNext(); )
332 headers_value->Append(ToHeaderDictionary(it.name(), it.value()));
333 return headers_value;
336 // Creates a base::StringValue with the status line of |headers|. If |headers|
337 // is NULL, an empty string is returned. Ownership is passed to the caller.
338 base::StringValue* GetStatusLine(net::HttpResponseHeaders* headers) {
339 return new base::StringValue(
340 headers ? headers->GetStatusLine() : std::string());
343 void RemoveEventListenerOnUI(
345 const std::string& event_name,
347 const std::string& extension_id) {
348 DCHECK_CURRENTLY_ON(BrowserThread::UI);
350 Profile* profile = reinterpret_cast<Profile*>(profile_id);
351 if (!g_browser_process->profile_manager()->IsValidProfile(profile))
354 extensions::EventRouter* event_router = extensions::EventRouter::Get(profile);
358 content::RenderProcessHost* process =
359 content::RenderProcessHost::FromID(process_id);
363 event_router->RemoveEventListener(event_name, process, extension_id);
366 // Sends an event to subscribers of chrome.declarativeWebRequest.onMessage.
367 // |extension_id| identifies the extension that sends and receives the event.
368 // |event_argument| is passed to the event listener.
369 void SendOnMessageEventOnUI(
371 const std::string& extension_id,
372 scoped_ptr<base::DictionaryValue> event_argument) {
373 DCHECK_CURRENTLY_ON(BrowserThread::UI);
375 Profile* profile = reinterpret_cast<Profile*>(profile_id);
376 if (!g_browser_process->profile_manager()->IsValidProfile(profile))
379 scoped_ptr<base::ListValue> event_args(new base::ListValue);
380 event_args->Append(event_argument.release());
382 extensions::EventRouter* event_router = extensions::EventRouter::Get(profile);
384 scoped_ptr<extensions::Event> event(new extensions::Event(
385 declarative_keys::kOnMessage, event_args.Pass(), profile,
386 GURL(), extensions::EventRouter::USER_GESTURE_UNKNOWN,
387 extensions::EventFilteringInfo()));
388 event_router->DispatchEventToExtension(extension_id, event.Pass());
391 void RemoveEventListenerOnIOThread(
392 content::BrowserContext* browser_context,
393 const std::string& extension_id,
394 const std::string& sub_event_name) {
395 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(
396 browser_context, extension_id, sub_event_name);
401 namespace extensions {
403 WebRequestAPI::WebRequestAPI(content::BrowserContext* context)
404 : browser_context_(context) {
405 EventRouter* event_router = EventRouter::Get(browser_context_);
406 for (size_t i = 0; i < arraysize(kWebRequestEvents); ++i) {
407 // Observe the webRequest event.
408 std::string event_name = kWebRequestEvents[i];
409 event_router->RegisterObserver(this, event_name);
411 // Also observe the corresponding webview event.
412 event_name.replace(0, sizeof(kWebRequest) - 1, kWebView);
413 event_router->RegisterObserver(this, event_name);
417 WebRequestAPI::~WebRequestAPI() {
418 EventRouter::Get(browser_context_)->UnregisterObserver(this);
421 static base::LazyInstance<BrowserContextKeyedAPIFactory<WebRequestAPI> >
422 g_factory = LAZY_INSTANCE_INITIALIZER;
425 BrowserContextKeyedAPIFactory<WebRequestAPI>*
426 WebRequestAPI::GetFactoryInstance() {
427 return g_factory.Pointer();
430 void WebRequestAPI::OnListenerRemoved(const EventListenerInfo& details) {
431 DCHECK_CURRENTLY_ON(BrowserThread::UI);
432 // Note that details.event_name includes the sub-event details (e.g. "/123").
433 BrowserThread::PostTask(BrowserThread::IO,
435 base::Bind(&RemoveEventListenerOnIOThread,
436 details.browser_context,
437 details.extension_id,
438 details.event_name));
441 } // namespace extensions
443 // Represents a single unique listener to an event, along with whatever filter
444 // parameters and extra_info_spec were specified at the time the listener was
446 // NOTE(benjhayden) New APIs should not use this sub_event_name trick! It does
447 // not play well with event pages. See downloads.onDeterminingFilename and
448 // ExtensionDownloadsEventRouter for an alternative approach.
449 struct ExtensionWebRequestEventRouter::EventListener {
450 std::string extension_id;
451 std::string extension_name;
452 std::string sub_event_name;
453 RequestFilter filter;
455 int embedder_process_id;
456 int webview_instance_id;
457 base::WeakPtr<IPC::Sender> ipc_sender;
458 mutable std::set<uint64> blocked_requests;
460 // Comparator to work with std::set.
461 bool operator<(const EventListener& that) const {
462 if (extension_id < that.extension_id)
464 if (extension_id == that.extension_id &&
465 sub_event_name < that.sub_event_name)
470 EventListener() : extra_info_spec(0) {}
473 // Contains info about requests that are blocked waiting for a response from
475 struct ExtensionWebRequestEventRouter::BlockedRequest {
476 // The request that is being blocked.
477 net::URLRequest* request;
479 // Whether the request originates from an incognito tab.
482 // The event that we're currently blocked on.
485 // The number of event handlers that we are awaiting a response from.
486 int num_handlers_blocking;
488 // Pointer to NetLog to report significant changes to the request for
490 const net::BoundNetLog* net_log;
492 // The callback to call when we get a response from all event handlers.
493 net::CompletionCallback callback;
495 // If non-empty, this contains the new URL that the request will redirect to.
496 // Only valid for OnBeforeRequest and OnHeadersReceived.
499 // The request headers that will be issued along with this request. Only valid
500 // for OnBeforeSendHeaders.
501 net::HttpRequestHeaders* request_headers;
503 // The response headers that were received from the server. Only valid for
504 // OnHeadersReceived.
505 scoped_refptr<const net::HttpResponseHeaders> original_response_headers;
507 // Location where to override response headers. Only valid for
508 // OnHeadersReceived.
509 scoped_refptr<net::HttpResponseHeaders>* override_response_headers;
511 // If non-empty, this contains the auth credentials that may be filled in.
512 // Only valid for OnAuthRequired.
513 net::AuthCredentials* auth_credentials;
515 // The callback to invoke for auth. If |auth_callback.is_null()| is false,
516 // |callback| must be NULL.
517 // Only valid for OnAuthRequired.
518 net::NetworkDelegate::AuthCallback auth_callback;
520 // Time the request was paused. Used for logging purposes.
521 base::Time blocking_time;
523 // Changes requested by extensions.
524 helpers::EventResponseDeltas response_deltas;
526 // Provider of meta data about extensions, only used and non-NULL for events
527 // that are delayed until the rules registry is ready.
528 InfoMap* extension_info_map;
533 event(kInvalidEvent),
534 num_handlers_blocking(0),
537 request_headers(NULL),
538 override_response_headers(NULL),
539 auth_credentials(NULL),
540 extension_info_map(NULL) {}
543 bool ExtensionWebRequestEventRouter::RequestFilter::InitFromValue(
544 const base::DictionaryValue& value, std::string* error) {
545 if (!value.HasKey("urls"))
548 for (base::DictionaryValue::Iterator it(value); !it.IsAtEnd(); it.Advance()) {
549 if (it.key() == "urls") {
550 const base::ListValue* urls_value = NULL;
551 if (!it.value().GetAsList(&urls_value))
553 for (size_t i = 0; i < urls_value->GetSize(); ++i) {
556 URLPattern::SCHEME_HTTP | URLPattern::SCHEME_HTTPS |
557 URLPattern::SCHEME_FTP | URLPattern::SCHEME_FILE |
558 URLPattern::SCHEME_EXTENSION);
559 if (!urls_value->GetString(i, &url) ||
560 pattern.Parse(url) != URLPattern::PARSE_SUCCESS) {
561 *error = ErrorUtils::FormatErrorMessage(
562 keys::kInvalidRequestFilterUrl, url);
565 urls.AddPattern(pattern);
567 } else if (it.key() == "types") {
568 const base::ListValue* types_value = NULL;
569 if (!it.value().GetAsList(&types_value))
571 for (size_t i = 0; i < types_value->GetSize(); ++i) {
572 std::string type_str;
573 ResourceType::Type type;
574 if (!types_value->GetString(i, &type_str) ||
575 !helpers::ParseResourceType(type_str, &type))
577 types.push_back(type);
579 } else if (it.key() == "tabId") {
580 if (!it.value().GetAsInteger(&tab_id))
582 } else if (it.key() == "windowId") {
583 if (!it.value().GetAsInteger(&window_id))
593 bool ExtensionWebRequestEventRouter::ExtraInfoSpec::InitFromValue(
594 const base::ListValue& value, int* extra_info_spec) {
595 *extra_info_spec = 0;
596 for (size_t i = 0; i < value.GetSize(); ++i) {
598 if (!value.GetString(i, &str))
601 if (str == "requestHeaders")
602 *extra_info_spec |= REQUEST_HEADERS;
603 else if (str == "responseHeaders")
604 *extra_info_spec |= RESPONSE_HEADERS;
605 else if (str == "blocking")
606 *extra_info_spec |= BLOCKING;
607 else if (str == "asyncBlocking")
608 *extra_info_spec |= ASYNC_BLOCKING;
609 else if (str == "requestBody")
610 *extra_info_spec |= REQUEST_BODY;
614 // BLOCKING and ASYNC_BLOCKING are mutually exclusive.
615 if ((*extra_info_spec & BLOCKING) && (*extra_info_spec & ASYNC_BLOCKING))
622 ExtensionWebRequestEventRouter::EventResponse::EventResponse(
623 const std::string& extension_id, const base::Time& extension_install_time)
624 : extension_id(extension_id),
625 extension_install_time(extension_install_time),
629 ExtensionWebRequestEventRouter::EventResponse::~EventResponse() {
633 ExtensionWebRequestEventRouter::RequestFilter::RequestFilter()
634 : tab_id(-1), window_id(-1) {
637 ExtensionWebRequestEventRouter::RequestFilter::~RequestFilter() {
641 // ExtensionWebRequestEventRouter
645 ExtensionWebRequestEventRouter* ExtensionWebRequestEventRouter::GetInstance() {
646 return Singleton<ExtensionWebRequestEventRouter>::get();
649 ExtensionWebRequestEventRouter::ExtensionWebRequestEventRouter()
650 : request_time_tracker_(new ExtensionWebRequestTimeTracker) {
653 ExtensionWebRequestEventRouter::~ExtensionWebRequestEventRouter() {
656 void ExtensionWebRequestEventRouter::RegisterRulesRegistry(
658 const RulesRegistryService::WebViewKey& webview_key,
659 scoped_refptr<extensions::WebRequestRulesRegistry> rules_registry) {
660 RulesRegistryKey key(profile, webview_key);
661 if (rules_registry.get())
662 rules_registries_[key] = rules_registry;
664 rules_registries_.erase(key);
667 int ExtensionWebRequestEventRouter::OnBeforeRequest(
669 InfoMap* extension_info_map,
670 net::URLRequest* request,
671 const net::CompletionCallback& callback,
673 // We hide events from the system context as well as sensitive requests.
675 WebRequestPermissions::HideRequest(extension_info_map, request))
678 if (IsPageLoad(request))
681 request_time_tracker_->LogRequestStartTime(request->identifier(),
686 // Whether to initialized blocked_requests_.
687 bool initialize_blocked_requests = false;
689 initialize_blocked_requests |=
690 ProcessDeclarativeRules(profile, extension_info_map,
691 web_request::OnBeforeRequest::kEventName, request,
692 extensions::ON_BEFORE_REQUEST, NULL);
694 int extra_info_spec = 0;
695 std::vector<const EventListener*> listeners =
696 GetMatchingListeners(profile, extension_info_map,
697 web_request::OnBeforeRequest::kEventName, request,
699 if (!listeners.empty() &&
700 !GetAndSetSignaled(request->identifier(), kOnBeforeRequest)) {
701 base::ListValue args;
702 base::DictionaryValue* dict = new base::DictionaryValue();
703 ExtractRequestInfo(request, dict);
704 if (extra_info_spec & ExtraInfoSpec::REQUEST_BODY)
705 ExtractRequestInfoBody(request, dict);
708 initialize_blocked_requests |=
709 DispatchEvent(profile, request, listeners, args);
712 if (!initialize_blocked_requests)
713 return net::OK; // Nobody saw a reason for modifying the request.
715 blocked_requests_[request->identifier()].event = kOnBeforeRequest;
716 blocked_requests_[request->identifier()].is_incognito |=
717 IsIncognitoProfile(profile);
718 blocked_requests_[request->identifier()].request = request;
719 blocked_requests_[request->identifier()].callback = callback;
720 blocked_requests_[request->identifier()].new_url = new_url;
721 blocked_requests_[request->identifier()].net_log = &request->net_log();
723 if (blocked_requests_[request->identifier()].num_handlers_blocking == 0) {
724 // If there are no blocking handlers, only the declarative rules tried
725 // to modify the request and we can respond synchronously.
726 return ExecuteDeltas(profile, request->identifier(),
727 false /* call_callback*/);
729 return net::ERR_IO_PENDING;
733 int ExtensionWebRequestEventRouter::OnBeforeSendHeaders(
735 InfoMap* extension_info_map,
736 net::URLRequest* request,
737 const net::CompletionCallback& callback,
738 net::HttpRequestHeaders* headers) {
739 // We hide events from the system context as well as sensitive requests.
741 WebRequestPermissions::HideRequest(extension_info_map, request))
744 bool initialize_blocked_requests = false;
746 initialize_blocked_requests |=
747 ProcessDeclarativeRules(profile, extension_info_map,
748 keys::kOnBeforeSendHeadersEvent, request,
749 extensions::ON_BEFORE_SEND_HEADERS, NULL);
751 int extra_info_spec = 0;
752 std::vector<const EventListener*> listeners =
753 GetMatchingListeners(profile, extension_info_map,
754 keys::kOnBeforeSendHeadersEvent, request,
756 if (!listeners.empty() &&
757 !GetAndSetSignaled(request->identifier(), kOnBeforeSendHeaders)) {
758 base::ListValue args;
759 base::DictionaryValue* dict = new base::DictionaryValue();
760 ExtractRequestInfo(request, dict);
761 if (extra_info_spec & ExtraInfoSpec::REQUEST_HEADERS)
762 dict->Set(keys::kRequestHeadersKey, GetRequestHeadersList(*headers));
765 initialize_blocked_requests |=
766 DispatchEvent(profile, request, listeners, args);
769 if (!initialize_blocked_requests)
770 return net::OK; // Nobody saw a reason for modifying the request.
772 blocked_requests_[request->identifier()].event = kOnBeforeSendHeaders;
773 blocked_requests_[request->identifier()].is_incognito |=
774 IsIncognitoProfile(profile);
775 blocked_requests_[request->identifier()].request = request;
776 blocked_requests_[request->identifier()].callback = callback;
777 blocked_requests_[request->identifier()].request_headers = headers;
778 blocked_requests_[request->identifier()].net_log = &request->net_log();
780 if (blocked_requests_[request->identifier()].num_handlers_blocking == 0) {
781 // If there are no blocking handlers, only the declarative rules tried
782 // to modify the request and we can respond synchronously.
783 return ExecuteDeltas(profile, request->identifier(),
784 false /* call_callback*/);
786 return net::ERR_IO_PENDING;
790 void ExtensionWebRequestEventRouter::OnSendHeaders(
792 InfoMap* extension_info_map,
793 net::URLRequest* request,
794 const net::HttpRequestHeaders& headers) {
795 // We hide events from the system context as well as sensitive requests.
797 WebRequestPermissions::HideRequest(extension_info_map, request))
800 if (GetAndSetSignaled(request->identifier(), kOnSendHeaders))
803 ClearSignaled(request->identifier(), kOnBeforeRedirect);
805 int extra_info_spec = 0;
806 std::vector<const EventListener*> listeners =
807 GetMatchingListeners(profile, extension_info_map,
808 keys::kOnSendHeadersEvent, request,
810 if (listeners.empty())
813 base::ListValue args;
814 base::DictionaryValue* dict = new base::DictionaryValue();
815 ExtractRequestInfo(request, dict);
816 if (extra_info_spec & ExtraInfoSpec::REQUEST_HEADERS)
817 dict->Set(keys::kRequestHeadersKey, GetRequestHeadersList(headers));
820 DispatchEvent(profile, request, listeners, args);
823 int ExtensionWebRequestEventRouter::OnHeadersReceived(
825 InfoMap* extension_info_map,
826 net::URLRequest* request,
827 const net::CompletionCallback& callback,
828 const net::HttpResponseHeaders* original_response_headers,
829 scoped_refptr<net::HttpResponseHeaders>* override_response_headers,
830 GURL* allowed_unsafe_redirect_url) {
831 // We hide events from the system context as well as sensitive requests.
833 WebRequestPermissions::HideRequest(extension_info_map, request))
836 bool initialize_blocked_requests = false;
838 initialize_blocked_requests |=
839 ProcessDeclarativeRules(profile, extension_info_map,
840 keys::kOnHeadersReceivedEvent, request,
841 extensions::ON_HEADERS_RECEIVED,
842 original_response_headers);
844 int extra_info_spec = 0;
845 std::vector<const EventListener*> listeners =
846 GetMatchingListeners(profile, extension_info_map,
847 keys::kOnHeadersReceivedEvent, request,
850 if (!listeners.empty() &&
851 !GetAndSetSignaled(request->identifier(), kOnHeadersReceived)) {
852 base::ListValue args;
853 base::DictionaryValue* dict = new base::DictionaryValue();
854 ExtractRequestInfo(request, dict);
855 dict->SetString(keys::kStatusLineKey,
856 original_response_headers->GetStatusLine());
857 if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
858 dict->Set(keys::kResponseHeadersKey,
859 GetResponseHeadersList(original_response_headers));
863 initialize_blocked_requests |=
864 DispatchEvent(profile, request, listeners, args);
867 if (!initialize_blocked_requests)
868 return net::OK; // Nobody saw a reason for modifying the request.
870 blocked_requests_[request->identifier()].event = kOnHeadersReceived;
871 blocked_requests_[request->identifier()].is_incognito |=
872 IsIncognitoProfile(profile);
873 blocked_requests_[request->identifier()].request = request;
874 blocked_requests_[request->identifier()].callback = callback;
875 blocked_requests_[request->identifier()].net_log = &request->net_log();
876 blocked_requests_[request->identifier()].override_response_headers =
877 override_response_headers;
878 blocked_requests_[request->identifier()].original_response_headers =
879 original_response_headers;
880 blocked_requests_[request->identifier()].new_url =
881 allowed_unsafe_redirect_url;
883 if (blocked_requests_[request->identifier()].num_handlers_blocking == 0) {
884 // If there are no blocking handlers, only the declarative rules tried
885 // to modify the request and we can respond synchronously.
886 return ExecuteDeltas(profile, request->identifier(),
887 false /* call_callback*/);
889 return net::ERR_IO_PENDING;
893 net::NetworkDelegate::AuthRequiredResponse
894 ExtensionWebRequestEventRouter::OnAuthRequired(
896 InfoMap* extension_info_map,
897 net::URLRequest* request,
898 const net::AuthChallengeInfo& auth_info,
899 const net::NetworkDelegate::AuthCallback& callback,
900 net::AuthCredentials* credentials) {
901 // No profile means that this is for authentication challenges in the
902 // system context. Skip in that case. Also skip sensitive requests.
904 WebRequestPermissions::HideRequest(extension_info_map, request))
905 return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION;
907 int extra_info_spec = 0;
908 std::vector<const EventListener*> listeners =
909 GetMatchingListeners(profile, extension_info_map,
910 keys::kOnAuthRequiredEvent, request,
912 if (listeners.empty())
913 return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION;
915 base::ListValue args;
916 base::DictionaryValue* dict = new base::DictionaryValue();
917 ExtractRequestInfo(request, dict);
918 dict->SetBoolean(keys::kIsProxyKey, auth_info.is_proxy);
919 if (!auth_info.scheme.empty())
920 dict->SetString(keys::kSchemeKey, auth_info.scheme);
921 if (!auth_info.realm.empty())
922 dict->SetString(keys::kRealmKey, auth_info.realm);
923 base::DictionaryValue* challenger = new base::DictionaryValue();
924 challenger->SetString(keys::kHostKey, auth_info.challenger.host());
925 challenger->SetInteger(keys::kPortKey, auth_info.challenger.port());
926 dict->Set(keys::kChallengerKey, challenger);
927 dict->Set(keys::kStatusLineKey, GetStatusLine(request->response_headers()));
928 if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
929 dict->Set(keys::kResponseHeadersKey,
930 GetResponseHeadersList(request->response_headers()));
934 if (DispatchEvent(profile, request, listeners, args)) {
935 blocked_requests_[request->identifier()].event = kOnAuthRequired;
936 blocked_requests_[request->identifier()].is_incognito |=
937 IsIncognitoProfile(profile);
938 blocked_requests_[request->identifier()].request = request;
939 blocked_requests_[request->identifier()].auth_callback = callback;
940 blocked_requests_[request->identifier()].auth_credentials = credentials;
941 blocked_requests_[request->identifier()].net_log = &request->net_log();
942 return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_IO_PENDING;
944 return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION;
947 void ExtensionWebRequestEventRouter::OnBeforeRedirect(
949 InfoMap* extension_info_map,
950 net::URLRequest* request,
951 const GURL& new_location) {
952 // We hide events from the system context as well as sensitive requests.
954 WebRequestPermissions::HideRequest(extension_info_map, request))
957 if (GetAndSetSignaled(request->identifier(), kOnBeforeRedirect))
960 ClearSignaled(request->identifier(), kOnBeforeRequest);
961 ClearSignaled(request->identifier(), kOnBeforeSendHeaders);
962 ClearSignaled(request->identifier(), kOnSendHeaders);
963 ClearSignaled(request->identifier(), kOnHeadersReceived);
965 int extra_info_spec = 0;
966 std::vector<const EventListener*> listeners =
967 GetMatchingListeners(profile, extension_info_map,
968 keys::kOnBeforeRedirectEvent, request,
970 if (listeners.empty())
973 int http_status_code = request->GetResponseCode();
975 std::string response_ip = request->GetSocketAddress().host();
977 base::ListValue args;
978 base::DictionaryValue* dict = new base::DictionaryValue();
979 ExtractRequestInfo(request, dict);
980 dict->SetString(keys::kRedirectUrlKey, new_location.spec());
981 dict->SetInteger(keys::kStatusCodeKey, http_status_code);
982 if (!response_ip.empty())
983 dict->SetString(keys::kIpKey, response_ip);
984 dict->SetBoolean(keys::kFromCache, request->was_cached());
985 dict->Set(keys::kStatusLineKey, GetStatusLine(request->response_headers()));
986 if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
987 dict->Set(keys::kResponseHeadersKey,
988 GetResponseHeadersList(request->response_headers()));
992 DispatchEvent(profile, request, listeners, args);
995 void ExtensionWebRequestEventRouter::OnResponseStarted(
997 InfoMap* extension_info_map,
998 net::URLRequest* request) {
999 // We hide events from the system context as well as sensitive requests.
1001 WebRequestPermissions::HideRequest(extension_info_map, request))
1004 // OnResponseStarted is even triggered, when the request was cancelled.
1005 if (request->status().status() != net::URLRequestStatus::SUCCESS)
1008 int extra_info_spec = 0;
1009 std::vector<const EventListener*> listeners =
1010 GetMatchingListeners(profile, extension_info_map,
1011 keys::kOnResponseStartedEvent, request,
1013 if (listeners.empty())
1016 // UrlRequestFileJobs do not send headers, so we simulate their behavior.
1017 int response_code = 200;
1018 if (request->response_headers())
1019 response_code = request->response_headers()->response_code();
1021 std::string response_ip = request->GetSocketAddress().host();
1023 base::ListValue args;
1024 base::DictionaryValue* dict = new base::DictionaryValue();
1025 ExtractRequestInfo(request, dict);
1026 if (!response_ip.empty())
1027 dict->SetString(keys::kIpKey, response_ip);
1028 dict->SetBoolean(keys::kFromCache, request->was_cached());
1029 dict->SetInteger(keys::kStatusCodeKey, response_code);
1030 dict->Set(keys::kStatusLineKey, GetStatusLine(request->response_headers()));
1031 if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
1032 dict->Set(keys::kResponseHeadersKey,
1033 GetResponseHeadersList(request->response_headers()));
1037 DispatchEvent(profile, request, listeners, args);
1040 void ExtensionWebRequestEventRouter::OnCompleted(void* profile,
1041 InfoMap* extension_info_map,
1042 net::URLRequest* request) {
1043 // We hide events from the system context as well as sensitive requests.
1044 // However, if the request first became sensitive after redirecting we have
1045 // already signaled it and thus we have to signal the end of it. This is
1046 // risk-free because the handler cannot modify the request now.
1048 (WebRequestPermissions::HideRequest(extension_info_map, request) &&
1049 !WasSignaled(*request)))
1052 request_time_tracker_->LogRequestEndTime(request->identifier(),
1055 DCHECK(request->status().status() == net::URLRequestStatus::SUCCESS);
1057 DCHECK(!GetAndSetSignaled(request->identifier(), kOnCompleted));
1059 ClearPendingCallbacks(request);
1061 int extra_info_spec = 0;
1062 std::vector<const EventListener*> listeners =
1063 GetMatchingListeners(profile, extension_info_map,
1064 keys::kOnCompletedEvent, request, &extra_info_spec);
1065 if (listeners.empty())
1068 // UrlRequestFileJobs do not send headers, so we simulate their behavior.
1069 int response_code = 200;
1070 if (request->response_headers())
1071 response_code = request->response_headers()->response_code();
1073 std::string response_ip = request->GetSocketAddress().host();
1075 base::ListValue args;
1076 base::DictionaryValue* dict = new base::DictionaryValue();
1077 ExtractRequestInfo(request, dict);
1078 dict->SetInteger(keys::kStatusCodeKey, response_code);
1079 if (!response_ip.empty())
1080 dict->SetString(keys::kIpKey, response_ip);
1081 dict->SetBoolean(keys::kFromCache, request->was_cached());
1082 dict->Set(keys::kStatusLineKey, GetStatusLine(request->response_headers()));
1083 if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
1084 dict->Set(keys::kResponseHeadersKey,
1085 GetResponseHeadersList(request->response_headers()));
1089 DispatchEvent(profile, request, listeners, args);
1092 void ExtensionWebRequestEventRouter::OnErrorOccurred(
1094 InfoMap* extension_info_map,
1095 net::URLRequest* request,
1097 // We hide events from the system context as well as sensitive requests.
1098 // However, if the request first became sensitive after redirecting we have
1099 // already signaled it and thus we have to signal the end of it. This is
1100 // risk-free because the handler cannot modify the request now.
1102 (WebRequestPermissions::HideRequest(extension_info_map, request) &&
1103 !WasSignaled(*request)))
1106 request_time_tracker_->LogRequestEndTime(request->identifier(),
1109 DCHECK(request->status().status() == net::URLRequestStatus::FAILED ||
1110 request->status().status() == net::URLRequestStatus::CANCELED);
1112 DCHECK(!GetAndSetSignaled(request->identifier(), kOnErrorOccurred));
1114 ClearPendingCallbacks(request);
1116 int extra_info_spec = 0;
1117 std::vector<const EventListener*> listeners =
1118 GetMatchingListeners(profile, extension_info_map,
1119 web_request::OnErrorOccurred::kEventName, request,
1121 if (listeners.empty())
1124 base::ListValue args;
1125 base::DictionaryValue* dict = new base::DictionaryValue();
1126 ExtractRequestInfo(request, dict);
1128 std::string response_ip = request->GetSocketAddress().host();
1129 if (!response_ip.empty())
1130 dict->SetString(keys::kIpKey, response_ip);
1132 dict->SetBoolean(keys::kFromCache, request->was_cached());
1133 dict->SetString(keys::kErrorKey,
1134 net::ErrorToString(request->status().error()));
1137 DispatchEvent(profile, request, listeners, args);
1140 void ExtensionWebRequestEventRouter::OnURLRequestDestroyed(
1141 void* profile, net::URLRequest* request) {
1142 ClearPendingCallbacks(request);
1144 signaled_requests_.erase(request->identifier());
1146 request_time_tracker_->LogRequestEndTime(request->identifier(),
1150 void ExtensionWebRequestEventRouter::ClearPendingCallbacks(
1151 net::URLRequest* request) {
1152 blocked_requests_.erase(request->identifier());
1155 bool ExtensionWebRequestEventRouter::DispatchEvent(
1157 net::URLRequest* request,
1158 const std::vector<const EventListener*>& listeners,
1159 const base::ListValue& args) {
1160 // TODO(mpcomplete): Consider consolidating common (extension_id,json_args)
1161 // pairs into a single message sent to a list of sub_event_names.
1162 int num_handlers_blocking = 0;
1163 for (std::vector<const EventListener*>::const_iterator it = listeners.begin();
1164 it != listeners.end(); ++it) {
1165 // Filter out the optional keys that this listener didn't request.
1166 scoped_ptr<base::ListValue> args_filtered(args.DeepCopy());
1167 base::DictionaryValue* dict = NULL;
1168 CHECK(args_filtered->GetDictionary(0, &dict) && dict);
1169 if (!((*it)->extra_info_spec & ExtraInfoSpec::REQUEST_HEADERS))
1170 dict->Remove(keys::kRequestHeadersKey, NULL);
1171 if (!((*it)->extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS))
1172 dict->Remove(keys::kResponseHeadersKey, NULL);
1174 extensions::EventRouter::DispatchEvent(
1175 (*it)->ipc_sender.get(), profile_id,
1176 (*it)->extension_id, (*it)->sub_event_name,
1177 args_filtered.Pass(),
1178 extensions::EventRouter::USER_GESTURE_UNKNOWN,
1179 extensions::EventFilteringInfo());
1180 if ((*it)->extra_info_spec &
1181 (ExtraInfoSpec::BLOCKING | ExtraInfoSpec::ASYNC_BLOCKING)) {
1182 (*it)->blocked_requests.insert(request->identifier());
1183 // If this is the first delegate blocking the request, go ahead and log
1185 if (num_handlers_blocking == 0) {
1186 std::string delegate_info =
1187 l10n_util::GetStringFUTF8(IDS_LOAD_STATE_PARAMETER_EXTENSION,
1188 base::UTF8ToUTF16((*it)->extension_name));
1189 // LobAndReport allows extensions that block requests to be displayed in
1190 // the load status bar.
1191 request->LogAndReportBlockedBy(delegate_info.c_str());
1193 ++num_handlers_blocking;
1197 if (num_handlers_blocking > 0) {
1198 blocked_requests_[request->identifier()].request = request;
1199 blocked_requests_[request->identifier()].is_incognito |=
1200 IsIncognitoProfile(profile_id);
1201 blocked_requests_[request->identifier()].num_handlers_blocking +=
1202 num_handlers_blocking;
1203 blocked_requests_[request->identifier()].blocking_time = base::Time::Now();
1211 void ExtensionWebRequestEventRouter::OnEventHandled(
1213 const std::string& extension_id,
1214 const std::string& event_name,
1215 const std::string& sub_event_name,
1217 EventResponse* response) {
1218 EventListener listener;
1219 listener.extension_id = extension_id;
1220 listener.sub_event_name = sub_event_name;
1222 // The listener may have been removed (e.g. due to the process going away)
1223 // before we got here.
1224 std::set<EventListener>::iterator found =
1225 listeners_[profile][event_name].find(listener);
1226 if (found != listeners_[profile][event_name].end())
1227 found->blocked_requests.erase(request_id);
1229 DecrementBlockCount(profile, extension_id, event_name, request_id, response);
1232 bool ExtensionWebRequestEventRouter::AddEventListener(
1234 const std::string& extension_id,
1235 const std::string& extension_name,
1236 const std::string& event_name,
1237 const std::string& sub_event_name,
1238 const RequestFilter& filter,
1239 int extra_info_spec,
1240 int embedder_process_id,
1241 int webview_instance_id,
1242 base::WeakPtr<IPC::Sender> ipc_sender) {
1244 if (!IsWebRequestEvent(event_name))
1247 EventListener listener;
1248 listener.extension_id = extension_id;
1249 listener.extension_name = extension_name;
1250 listener.sub_event_name = sub_event_name;
1251 listener.filter = filter;
1252 listener.extra_info_spec = extra_info_spec;
1253 listener.ipc_sender = ipc_sender;
1254 listener.embedder_process_id = embedder_process_id;
1255 listener.webview_instance_id = webview_instance_id;
1256 if (listener.webview_instance_id) {
1257 content::RecordAction(
1258 base::UserMetricsAction("WebView.WebRequest.AddListener"));
1261 if (listeners_[profile][event_name].count(listener) != 0u) {
1262 // This is likely an abuse of the API by a malicious extension.
1265 listeners_[profile][event_name].insert(listener);
1269 void ExtensionWebRequestEventRouter::RemoveEventListener(
1271 const std::string& extension_id,
1272 const std::string& sub_event_name) {
1273 std::string event_name =
1274 extensions::EventRouter::GetBaseEventName(sub_event_name);
1275 DCHECK(IsWebRequestEvent(event_name));
1277 EventListener listener;
1278 listener.extension_id = extension_id;
1279 listener.sub_event_name = sub_event_name;
1281 // It's possible for AddEventListener to fail asynchronously. In that case,
1282 // the renderer believes the listener exists, while the browser does not.
1283 // Ignore a RemoveEventListener in that case.
1284 std::set<EventListener>::iterator found =
1285 listeners_[profile][event_name].find(listener);
1286 if (found == listeners_[profile][event_name].end())
1289 CHECK_EQ(listeners_[profile][event_name].count(listener), 1u) <<
1290 "extension=" << extension_id << " event=" << event_name;
1292 // Unblock any request that this event listener may have been blocking.
1293 for (std::set<uint64>::iterator it = found->blocked_requests.begin();
1294 it != found->blocked_requests.end(); ++it) {
1295 DecrementBlockCount(profile, extension_id, event_name, *it, NULL);
1298 listeners_[profile][event_name].erase(listener);
1300 helpers::ClearCacheOnNavigation();
1303 void ExtensionWebRequestEventRouter::RemoveWebViewEventListeners(
1305 const std::string& extension_id,
1306 int embedder_process_id,
1307 int webview_instance_id) {
1308 // Iterate over all listeners of all WebRequest events to delete
1309 // any listeners that belong to the provided <webview>.
1310 ListenerMapForProfile& map_for_profile = listeners_[profile];
1311 for (ListenerMapForProfile::iterator event_iter = map_for_profile.begin();
1312 event_iter != map_for_profile.end(); ++event_iter) {
1313 std::vector<EventListener> listeners_to_delete;
1314 std::set<EventListener>& listeners = event_iter->second;
1315 for (std::set<EventListener>::iterator listener_iter = listeners.begin();
1316 listener_iter != listeners.end(); ++listener_iter) {
1317 const EventListener& listener = *listener_iter;
1318 if (listener.embedder_process_id == embedder_process_id &&
1319 listener.webview_instance_id == webview_instance_id)
1320 listeners_to_delete.push_back(listener);
1322 for (size_t i = 0; i < listeners_to_delete.size(); ++i) {
1323 EventListener& listener = listeners_to_delete[i];
1324 content::BrowserThread::PostTask(
1325 content::BrowserThread::UI,
1327 base::Bind(&RemoveEventListenerOnUI,
1329 listener.sub_event_name,
1330 embedder_process_id,
1336 void ExtensionWebRequestEventRouter::OnOTRProfileCreated(
1337 void* original_profile, void* otr_profile) {
1338 cross_profile_map_[original_profile] = std::make_pair(false, otr_profile);
1339 cross_profile_map_[otr_profile] = std::make_pair(true, original_profile);
1342 void ExtensionWebRequestEventRouter::OnOTRProfileDestroyed(
1343 void* original_profile, void* otr_profile) {
1344 cross_profile_map_.erase(otr_profile);
1345 cross_profile_map_.erase(original_profile);
1348 void ExtensionWebRequestEventRouter::AddCallbackForPageLoad(
1349 const base::Closure& callback) {
1350 callbacks_for_page_load_.push_back(callback);
1353 bool ExtensionWebRequestEventRouter::IsPageLoad(
1354 net::URLRequest* request) const {
1355 bool is_main_frame = false;
1356 int64 frame_id = -1;
1357 bool parent_is_main_frame = false;
1358 int64 parent_frame_id = -1;
1361 int render_process_host_id = -1;
1362 int routing_id = -1;
1363 ResourceType::Type resource_type = ResourceType::LAST_TYPE;
1365 ExtractRequestInfoDetails(request, &is_main_frame, &frame_id,
1366 &parent_is_main_frame, &parent_frame_id,
1367 &tab_id, &window_id, &render_process_host_id,
1368 &routing_id, &resource_type);
1370 return resource_type == ResourceType::MAIN_FRAME;
1373 void ExtensionWebRequestEventRouter::NotifyPageLoad() {
1374 for (CallbacksForPageLoad::const_iterator i =
1375 callbacks_for_page_load_.begin();
1376 i != callbacks_for_page_load_.end(); ++i) {
1379 callbacks_for_page_load_.clear();
1382 void* ExtensionWebRequestEventRouter::GetCrossProfile(void* profile) const {
1383 CrossProfileMap::const_iterator cross_profile =
1384 cross_profile_map_.find(profile);
1385 if (cross_profile == cross_profile_map_.end())
1387 return cross_profile->second.second;
1390 bool ExtensionWebRequestEventRouter::IsIncognitoProfile(void* profile) const {
1391 CrossProfileMap::const_iterator cross_profile =
1392 cross_profile_map_.find(profile);
1393 if (cross_profile == cross_profile_map_.end())
1395 return cross_profile->second.first;
1398 bool ExtensionWebRequestEventRouter::WasSignaled(
1399 const net::URLRequest& request) const {
1400 SignaledRequestMap::const_iterator flag =
1401 signaled_requests_.find(request.identifier());
1402 return (flag != signaled_requests_.end()) && (flag->second != 0);
1405 void ExtensionWebRequestEventRouter::GetMatchingListenersImpl(
1407 InfoMap* extension_info_map,
1408 bool crosses_incognito,
1409 const std::string& event_name,
1413 int render_process_host_id,
1415 ResourceType::Type resource_type,
1416 bool is_async_request,
1417 bool is_request_from_extension,
1418 int* extra_info_spec,
1419 std::vector<const ExtensionWebRequestEventRouter::EventListener*>*
1420 matching_listeners) {
1421 std::string web_request_event_name(event_name);
1422 ExtensionRendererState::WebViewInfo webview_info;
1423 bool is_guest = ExtensionRendererState::GetInstance()->
1424 GetWebViewInfo(render_process_host_id, routing_id, &webview_info);
1426 web_request_event_name.replace(0, sizeof(kWebRequest) - 1, kWebView);
1428 std::set<EventListener>& listeners =
1429 listeners_[profile][web_request_event_name];
1430 for (std::set<EventListener>::iterator it = listeners.begin();
1431 it != listeners.end(); ++it) {
1432 if (!it->ipc_sender.get()) {
1433 // The IPC sender has been deleted. This listener will be removed soon
1434 // via a call to RemoveEventListener. For now, just skip it.
1439 (it->embedder_process_id != webview_info.embedder_process_id ||
1440 it->webview_instance_id != webview_info.instance_id))
1443 if (!it->filter.urls.is_empty() && !it->filter.urls.MatchesURL(url))
1445 if (it->filter.tab_id != -1 && tab_id != it->filter.tab_id)
1447 if (it->filter.window_id != -1 && window_id != it->filter.window_id)
1449 if (!it->filter.types.empty() &&
1450 std::find(it->filter.types.begin(), it->filter.types.end(),
1451 resource_type) == it->filter.types.end())
1454 if (!is_guest && !WebRequestPermissions::CanExtensionAccessURL(
1455 extension_info_map, it->extension_id, url, crosses_incognito,
1456 WebRequestPermissions::REQUIRE_HOST_PERMISSION))
1459 bool blocking_listener =
1460 (it->extra_info_spec &
1461 (ExtraInfoSpec::BLOCKING | ExtraInfoSpec::ASYNC_BLOCKING)) != 0;
1463 // We do not want to notify extensions about XHR requests that are
1464 // triggered by themselves. This is a workaround to prevent deadlocks
1465 // in case of synchronous XHR requests that block the extension renderer
1466 // and therefore prevent the extension from processing the request
1467 // handler. This is only a problem for blocking listeners.
1468 // http://crbug.com/105656
1469 bool synchronous_xhr_from_extension = !is_async_request &&
1470 is_request_from_extension && resource_type == ResourceType::XHR;
1472 // Only send webRequest events for URLs the extension has access to.
1473 if (blocking_listener && synchronous_xhr_from_extension)
1476 matching_listeners->push_back(&(*it));
1477 *extra_info_spec |= it->extra_info_spec;
1481 std::vector<const ExtensionWebRequestEventRouter::EventListener*>
1482 ExtensionWebRequestEventRouter::GetMatchingListeners(
1484 InfoMap* extension_info_map,
1485 const std::string& event_name,
1486 net::URLRequest* request,
1487 int* extra_info_spec) {
1488 // TODO(mpcomplete): handle profile == NULL (should collect all listeners).
1489 *extra_info_spec = 0;
1491 bool is_main_frame = false;
1492 int64 frame_id = -1;
1493 bool parent_is_main_frame = false;
1494 int64 parent_frame_id = -1;
1497 int render_process_host_id = -1;
1498 int routing_id = -1;
1499 ResourceType::Type resource_type = ResourceType::LAST_TYPE;
1500 const GURL& url = request->url();
1502 ExtractRequestInfoDetails(request, &is_main_frame, &frame_id,
1503 &parent_is_main_frame, &parent_frame_id,
1504 &tab_id, &window_id, &render_process_host_id,
1505 &routing_id, &resource_type);
1507 std::vector<const ExtensionWebRequestEventRouter::EventListener*>
1510 bool is_request_from_extension =
1511 IsRequestFromExtension(request, extension_info_map);
1513 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
1514 // We are conservative here and assume requests are asynchronous in case
1515 // we don't have an info object. We don't want to risk a deadlock.
1516 bool is_async_request = !info || info->IsAsync();
1518 GetMatchingListenersImpl(
1519 profile, extension_info_map, false, event_name, url,
1520 tab_id, window_id, render_process_host_id, routing_id, resource_type,
1521 is_async_request, is_request_from_extension, extra_info_spec,
1522 &matching_listeners);
1523 void* cross_profile = GetCrossProfile(profile);
1524 if (cross_profile) {
1525 GetMatchingListenersImpl(
1526 cross_profile, extension_info_map, true, event_name, url, tab_id,
1527 window_id, render_process_host_id, routing_id, resource_type,
1528 is_async_request, is_request_from_extension, extra_info_spec,
1529 &matching_listeners);
1532 return matching_listeners;
1537 helpers::EventResponseDelta* CalculateDelta(
1538 ExtensionWebRequestEventRouter::BlockedRequest* blocked_request,
1539 ExtensionWebRequestEventRouter::EventResponse* response) {
1540 switch (blocked_request->event) {
1541 case ExtensionWebRequestEventRouter::kOnBeforeRequest:
1542 return helpers::CalculateOnBeforeRequestDelta(
1543 response->extension_id, response->extension_install_time,
1544 response->cancel, response->new_url);
1545 case ExtensionWebRequestEventRouter::kOnBeforeSendHeaders: {
1546 net::HttpRequestHeaders* old_headers = blocked_request->request_headers;
1547 net::HttpRequestHeaders* new_headers = response->request_headers.get();
1548 return helpers::CalculateOnBeforeSendHeadersDelta(
1549 response->extension_id, response->extension_install_time,
1550 response->cancel, old_headers, new_headers);
1552 case ExtensionWebRequestEventRouter::kOnHeadersReceived: {
1553 const net::HttpResponseHeaders* old_headers =
1554 blocked_request->original_response_headers.get();
1555 helpers::ResponseHeaders* new_headers =
1556 response->response_headers.get();
1557 return helpers::CalculateOnHeadersReceivedDelta(
1558 response->extension_id,
1559 response->extension_install_time,
1565 case ExtensionWebRequestEventRouter::kOnAuthRequired:
1566 return helpers::CalculateOnAuthRequiredDelta(
1567 response->extension_id, response->extension_install_time,
1568 response->cancel, &response->auth_credentials);
1576 base::Value* SerializeResponseHeaders(const helpers::ResponseHeaders& headers) {
1577 scoped_ptr<base::ListValue> serialized_headers(new base::ListValue());
1578 for (helpers::ResponseHeaders::const_iterator i = headers.begin();
1579 i != headers.end(); ++i) {
1580 serialized_headers->Append(ToHeaderDictionary(i->first, i->second));
1582 return serialized_headers.release();
1585 // Convert a RequestCookieModifications/ResponseCookieModifications object to a
1586 // base::ListValue which summarizes the changes made. This is templated since
1587 // the two types (request/response) are different but contain essentially the
1589 template<typename CookieType>
1590 base::ListValue* SummarizeCookieModifications(
1591 const std::vector<linked_ptr<CookieType> >& modifications) {
1592 scoped_ptr<base::ListValue> cookie_modifications(new base::ListValue());
1593 for (typename std::vector<linked_ptr<CookieType> >::const_iterator i =
1594 modifications.begin();
1595 i != modifications.end(); ++i) {
1596 scoped_ptr<base::DictionaryValue> summary(new base::DictionaryValue());
1597 const CookieType& mod = *i->get();
1600 summary->SetString(activitylog::kCookieModificationTypeKey,
1601 activitylog::kCookieModificationAdd);
1604 summary->SetString(activitylog::kCookieModificationTypeKey,
1605 activitylog::kCookieModificationEdit);
1607 case helpers::REMOVE:
1608 summary->SetString(activitylog::kCookieModificationTypeKey,
1609 activitylog::kCookieModificationRemove);
1613 if (mod.filter->name)
1614 summary->SetString(activitylog::kCookieFilterNameKey,
1615 *mod.modification->name);
1616 if (mod.filter->domain)
1617 summary->SetString(activitylog::kCookieFilterDomainKey,
1618 *mod.modification->name);
1620 if (mod.modification) {
1621 if (mod.modification->name)
1622 summary->SetString(activitylog::kCookieModDomainKey,
1623 *mod.modification->name);
1624 if (mod.modification->domain)
1625 summary->SetString(activitylog::kCookieModDomainKey,
1626 *mod.modification->name);
1628 cookie_modifications->Append(summary.release());
1630 return cookie_modifications.release();
1633 // Converts an EventResponseDelta object to a dictionary value suitable for the
1635 scoped_ptr<base::DictionaryValue> SummarizeResponseDelta(
1636 const std::string& event_name,
1637 const helpers::EventResponseDelta& delta) {
1638 scoped_ptr<base::DictionaryValue> details(new base::DictionaryValue());
1640 details->SetBoolean(activitylog::kCancelKey, true);
1642 if (!delta.new_url.is_empty()) {
1643 details->SetString(activitylog::kNewUrlKey, delta.new_url.spec());
1646 scoped_ptr<base::ListValue> modified_headers(new base::ListValue());
1647 net::HttpRequestHeaders::Iterator iter(delta.modified_request_headers);
1648 while (iter.GetNext()) {
1649 modified_headers->Append(ToHeaderDictionary(iter.name(), iter.value()));
1651 if (!modified_headers->empty()) {
1652 details->Set(activitylog::kModifiedRequestHeadersKey,
1653 modified_headers.release());
1656 scoped_ptr<base::ListValue> deleted_headers(new base::ListValue());
1657 deleted_headers->AppendStrings(delta.deleted_request_headers);
1658 if (!deleted_headers->empty()) {
1659 details->Set(activitylog::kDeletedRequestHeadersKey,
1660 deleted_headers.release());
1663 if (!delta.added_response_headers.empty()) {
1664 details->Set(activitylog::kAddedRequestHeadersKey,
1665 SerializeResponseHeaders(delta.added_response_headers));
1667 if (!delta.deleted_response_headers.empty()) {
1668 details->Set(activitylog::kDeletedResponseHeadersKey,
1669 SerializeResponseHeaders(delta.deleted_response_headers));
1671 if (delta.auth_credentials) {
1672 details->SetString(activitylog::kAuthCredentialsKey,
1674 delta.auth_credentials->username()) + ":*");
1677 if (!delta.response_cookie_modifications.empty()) {
1679 activitylog::kResponseCookieModificationsKey,
1680 SummarizeCookieModifications(delta.response_cookie_modifications));
1683 return details.Pass();
1686 void LogExtensionActivity(void* profile_id,
1688 const std::string& extension_id,
1690 const std::string& api_call,
1691 scoped_ptr<base::DictionaryValue> details) {
1692 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
1693 BrowserThread::PostTask(BrowserThread::UI,
1695 base::Bind(&LogExtensionActivity,
1701 base::Passed(&details)));
1703 Profile* profile = static_cast<Profile*>(profile_id);
1704 if (!g_browser_process->profile_manager()->IsValidProfile(profile))
1706 scoped_refptr<extensions::Action> action =
1707 new extensions::Action(extension_id,
1709 extensions::Action::ACTION_WEB_REQUEST,
1711 action->set_page_url(url);
1712 action->set_page_incognito(is_incognito);
1713 action->mutable_other()->Set(activity_log_constants::kActionWebRequest,
1715 extensions::ActivityLog::GetInstance(profile)->LogAction(action);
1721 void ExtensionWebRequestEventRouter::DecrementBlockCount(
1723 const std::string& extension_id,
1724 const std::string& event_name,
1726 EventResponse* response) {
1727 scoped_ptr<EventResponse> response_scoped(response);
1729 // It's possible that this request was deleted, or cancelled by a previous
1730 // event handler. If so, ignore this response.
1731 if (blocked_requests_.find(request_id) == blocked_requests_.end())
1734 BlockedRequest& blocked_request = blocked_requests_[request_id];
1735 int num_handlers_blocking = --blocked_request.num_handlers_blocking;
1736 CHECK_GE(num_handlers_blocking, 0);
1739 helpers::EventResponseDelta* delta =
1740 CalculateDelta(&blocked_request, response);
1742 LogExtensionActivity(profile,
1743 blocked_request.is_incognito,
1745 blocked_request.request->url(),
1747 SummarizeResponseDelta(event_name, *delta));
1749 blocked_request.response_deltas.push_back(
1750 linked_ptr<helpers::EventResponseDelta>(delta));
1753 base::TimeDelta block_time =
1754 base::Time::Now() - blocked_request.blocking_time;
1755 if (!extension_id.empty()) {
1756 request_time_tracker_->IncrementExtensionBlockTime(
1757 extension_id, request_id, block_time);
1759 // |extension_id| is empty for requests blocked on startup waiting for the
1760 // declarative rules to be read from disk.
1761 UMA_HISTOGRAM_TIMES("Extensions.NetworkDelayStartup", block_time);
1764 if (num_handlers_blocking == 0) {
1765 blocked_request.request->LogUnblocked();
1766 ExecuteDeltas(profile, request_id, true);
1768 // Update the URLRequest to make sure it's tagged with an extension that's
1769 // still blocking it. This may end up being the same extension as before.
1770 std::set<EventListener>& listeners = listeners_[profile][event_name];
1772 for (std::set<EventListener>::iterator it = listeners.begin();
1773 it != listeners.end(); ++it) {
1774 if (it->blocked_requests.count(request_id) == 0)
1776 std::string delegate_info =
1777 l10n_util::GetStringFUTF8(IDS_LOAD_STATE_PARAMETER_EXTENSION,
1778 base::UTF8ToUTF16(it->extension_name));
1779 blocked_request.request->LogAndReportBlockedBy(delegate_info.c_str());
1785 void ExtensionWebRequestEventRouter::SendMessages(
1787 const BlockedRequest& blocked_request) {
1788 const helpers::EventResponseDeltas& deltas = blocked_request.response_deltas;
1789 for (helpers::EventResponseDeltas::const_iterator delta = deltas.begin();
1790 delta != deltas.end(); ++delta) {
1791 const std::set<std::string>& messages = (*delta)->messages_to_extension;
1792 for (std::set<std::string>::const_iterator message = messages.begin();
1793 message != messages.end(); ++message) {
1794 scoped_ptr<base::DictionaryValue> argument(new base::DictionaryValue);
1795 ExtractRequestInfo(blocked_request.request, argument.get());
1796 argument->SetString(keys::kMessageKey, *message);
1797 argument->SetString(keys::kStageKey,
1798 GetRequestStageAsString(blocked_request.event));
1800 BrowserThread::PostTask(
1803 base::Bind(&SendOnMessageEventOnUI,
1805 (*delta)->extension_id,
1806 base::Passed(&argument)));
1811 int ExtensionWebRequestEventRouter::ExecuteDeltas(
1814 bool call_callback) {
1815 BlockedRequest& blocked_request = blocked_requests_[request_id];
1816 CHECK(blocked_request.num_handlers_blocking == 0);
1817 helpers::EventResponseDeltas& deltas = blocked_request.response_deltas;
1818 base::TimeDelta block_time =
1819 base::Time::Now() - blocked_request.blocking_time;
1820 request_time_tracker_->IncrementTotalBlockTime(request_id, block_time);
1822 bool credentials_set = false;
1824 deltas.sort(&helpers::InDecreasingExtensionInstallationTimeOrder);
1825 ExtensionWarningSet warnings;
1827 bool canceled = false;
1828 helpers::MergeCancelOfResponses(
1829 blocked_request.response_deltas,
1831 blocked_request.net_log);
1833 if (blocked_request.event == kOnBeforeRequest) {
1834 CHECK(!blocked_request.callback.is_null());
1835 helpers::MergeOnBeforeRequestResponses(
1836 blocked_request.response_deltas,
1837 blocked_request.new_url,
1839 blocked_request.net_log);
1840 } else if (blocked_request.event == kOnBeforeSendHeaders) {
1841 CHECK(!blocked_request.callback.is_null());
1842 helpers::MergeOnBeforeSendHeadersResponses(
1843 blocked_request.response_deltas,
1844 blocked_request.request_headers,
1846 blocked_request.net_log);
1847 } else if (blocked_request.event == kOnHeadersReceived) {
1848 CHECK(!blocked_request.callback.is_null());
1849 helpers::MergeOnHeadersReceivedResponses(
1850 blocked_request.response_deltas,
1851 blocked_request.original_response_headers.get(),
1852 blocked_request.override_response_headers,
1853 blocked_request.new_url,
1855 blocked_request.net_log);
1856 } else if (blocked_request.event == kOnAuthRequired) {
1857 CHECK(blocked_request.callback.is_null());
1858 CHECK(!blocked_request.auth_callback.is_null());
1859 credentials_set = helpers::MergeOnAuthRequiredResponses(
1860 blocked_request.response_deltas,
1861 blocked_request.auth_credentials,
1863 blocked_request.net_log);
1868 SendMessages(profile, blocked_request);
1870 if (!warnings.empty()) {
1871 BrowserThread::PostTask(
1874 base::Bind(&ExtensionWarningService::NotifyWarningsOnUI,
1875 profile, warnings));
1879 request_time_tracker_->SetRequestCanceled(request_id);
1880 } else if (blocked_request.new_url &&
1881 !blocked_request.new_url->is_empty()) {
1882 request_time_tracker_->SetRequestRedirected(request_id);
1885 // This triggers onErrorOccurred if canceled is true.
1886 int rv = canceled ? net::ERR_BLOCKED_BY_CLIENT : net::OK;
1888 if (!blocked_request.callback.is_null()) {
1889 net::CompletionCallback callback = blocked_request.callback;
1890 // Ensure that request is removed before callback because the callback
1891 // might trigger the next event.
1892 blocked_requests_.erase(request_id);
1895 } else if (!blocked_request.auth_callback.is_null()) {
1896 net::NetworkDelegate::AuthRequiredResponse response =
1897 net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION;
1899 response = net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_CANCEL_AUTH;
1900 } else if (credentials_set) {
1901 response = net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_SET_AUTH;
1903 net::NetworkDelegate::AuthCallback callback = blocked_request.auth_callback;
1904 blocked_requests_.erase(request_id);
1906 callback.Run(response);
1908 blocked_requests_.erase(request_id);
1913 bool ExtensionWebRequestEventRouter::ProcessDeclarativeRules(
1915 InfoMap* extension_info_map,
1916 const std::string& event_name,
1917 net::URLRequest* request,
1918 extensions::RequestStage request_stage,
1919 const net::HttpResponseHeaders* original_response_headers) {
1920 bool is_main_frame = false;
1921 int64 frame_id = -1;
1922 bool parent_is_main_frame = false;
1923 int64 parent_frame_id = -1;
1926 int render_process_host_id = -1;
1927 int routing_id = -1;
1928 ResourceType::Type resource_type = ResourceType::LAST_TYPE;
1930 ExtractRequestInfoDetails(request, &is_main_frame, &frame_id,
1931 &parent_is_main_frame, &parent_frame_id,
1932 &tab_id, &window_id, &render_process_host_id,
1933 &routing_id, &resource_type);
1934 ExtensionRendererState::WebViewInfo webview_info;
1935 bool is_guest = ExtensionRendererState::GetInstance()->
1936 GetWebViewInfo(render_process_host_id, routing_id, &webview_info);
1938 RulesRegistryService::WebViewKey webview_key(
1939 is_guest ? webview_info.embedder_process_id : 0,
1940 is_guest ? webview_info.instance_id : 0);
1941 RulesRegistryKey rules_key(profile, webview_key);
1943 // If this check fails, check that the active stages are up-to-date in
1944 // browser/extensions/api/declarative_webrequest/request_stage.h .
1945 DCHECK(request_stage & extensions::kActiveStages);
1947 // Rules of the current |profile| may apply but we need to check also whether
1948 // there are applicable rules from extensions whose background page
1949 // spans from regular to incognito mode.
1951 // First parameter identifies the registry, the second indicates whether the
1952 // registry belongs to the cross profile.
1953 typedef std::pair<extensions::WebRequestRulesRegistry*, bool>
1955 typedef std::vector<RelevantRegistry> RelevantRegistries;
1956 RelevantRegistries relevant_registries;
1958 if (rules_registries_.find(rules_key) != rules_registries_.end()) {
1959 relevant_registries.push_back(
1960 std::make_pair(rules_registries_[rules_key].get(), false));
1963 void* cross_profile = GetCrossProfile(profile);
1964 RulesRegistryKey cross_profile_rules_key(cross_profile, webview_key);
1965 if (cross_profile &&
1966 rules_registries_.find(cross_profile_rules_key) !=
1967 rules_registries_.end()) {
1968 relevant_registries.push_back(
1969 std::make_pair(rules_registries_[cross_profile_rules_key].get(), true));
1972 // The following block is experimentally enabled and its impact on load time
1973 // logged with UMA Extensions.NetworkDelayRegistryLoad. crbug.com/175961
1974 for (RelevantRegistries::iterator i = relevant_registries.begin();
1975 i != relevant_registries.end(); ++i) {
1976 extensions::WebRequestRulesRegistry* rules_registry = i->first;
1977 if (!rules_registry->ready().is_signaled()) {
1978 // The rules registry is still loading. Block this request until it
1980 rules_registry->ready().Post(
1982 base::Bind(&ExtensionWebRequestEventRouter::OnRulesRegistryReady,
1986 request->identifier(),
1988 blocked_requests_[request->identifier()].num_handlers_blocking++;
1989 blocked_requests_[request->identifier()].request = request;
1990 blocked_requests_[request->identifier()].is_incognito |=
1991 IsIncognitoProfile(profile);
1992 blocked_requests_[request->identifier()].blocking_time =
1994 blocked_requests_[request->identifier()].original_response_headers =
1995 original_response_headers;
1996 blocked_requests_[request->identifier()].extension_info_map =
2002 base::Time start = base::Time::Now();
2004 bool deltas_created = false;
2005 for (RelevantRegistries::iterator i = relevant_registries.begin();
2006 i != relevant_registries.end(); ++i) {
2007 extensions::WebRequestRulesRegistry* rules_registry =
2009 helpers::EventResponseDeltas result =
2010 rules_registry->CreateDeltas(
2012 extensions::WebRequestData(
2013 request, request_stage, original_response_headers),
2016 if (!result.empty()) {
2017 helpers::EventResponseDeltas& deltas =
2018 blocked_requests_[request->identifier()].response_deltas;
2019 deltas.insert(deltas.end(), result.begin(), result.end());
2020 deltas_created = true;
2024 base::TimeDelta elapsed_time = start - base::Time::Now();
2025 UMA_HISTOGRAM_TIMES("Extensions.DeclarativeWebRequestNetworkDelay",
2028 return deltas_created;
2031 void ExtensionWebRequestEventRouter::OnRulesRegistryReady(
2033 const std::string& event_name,
2035 extensions::RequestStage request_stage) {
2036 // It's possible that this request was deleted, or cancelled by a previous
2037 // event handler. If so, ignore this response.
2038 if (blocked_requests_.find(request_id) == blocked_requests_.end())
2041 BlockedRequest& blocked_request = blocked_requests_[request_id];
2042 base::TimeDelta block_time =
2043 base::Time::Now() - blocked_request.blocking_time;
2044 UMA_HISTOGRAM_TIMES("Extensions.NetworkDelayRegistryLoad", block_time);
2046 ProcessDeclarativeRules(profile,
2047 blocked_request.extension_info_map,
2049 blocked_request.request,
2051 blocked_request.original_response_headers.get());
2052 // Reset to NULL so that nobody relies on this being set.
2053 blocked_request.extension_info_map = NULL;
2054 DecrementBlockCount(profile, std::string(), event_name, request_id, NULL);
2057 bool ExtensionWebRequestEventRouter::GetAndSetSignaled(uint64 request_id,
2058 EventTypes event_type) {
2059 SignaledRequestMap::iterator iter = signaled_requests_.find(request_id);
2060 if (iter == signaled_requests_.end()) {
2061 signaled_requests_[request_id] = event_type;
2064 bool was_signaled_before = (iter->second & event_type) != 0;
2065 iter->second |= event_type;
2066 return was_signaled_before;
2069 void ExtensionWebRequestEventRouter::ClearSignaled(uint64 request_id,
2070 EventTypes event_type) {
2071 SignaledRequestMap::iterator iter = signaled_requests_.find(request_id);
2072 if (iter == signaled_requests_.end())
2074 iter->second &= ~event_type;
2077 // Special QuotaLimitHeuristic for WebRequestHandlerBehaviorChangedFunction.
2079 // Each call of webRequest.handlerBehaviorChanged() clears the in-memory cache
2080 // of WebKit at the time of the next page load (top level navigation event).
2081 // This quota heuristic is intended to limit the number of times the cache is
2082 // cleared by an extension.
2084 // As we want to account for the number of times the cache is really cleared
2085 // (opposed to the number of times webRequest.handlerBehaviorChanged() is
2086 // called), we cannot decide whether a call of
2087 // webRequest.handlerBehaviorChanged() should trigger a quota violation at the
2088 // time it is called. Instead we only decrement the bucket counter at the time
2089 // when the cache is cleared (when page loads happen).
2090 class ClearCacheQuotaHeuristic : public extensions::QuotaLimitHeuristic {
2092 ClearCacheQuotaHeuristic(const Config& config, BucketMapper* map)
2093 : QuotaLimitHeuristic(
2096 "MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES"),
2097 callback_registered_(false),
2098 weak_ptr_factory_(this) {}
2099 virtual ~ClearCacheQuotaHeuristic() {}
2100 virtual bool Apply(Bucket* bucket,
2101 const base::TimeTicks& event_time) OVERRIDE;
2104 // Callback that is triggered by the ExtensionWebRequestEventRouter on a page
2107 // We don't need to take care of the life time of |bucket|: It is owned by the
2108 // BucketMapper of our base class in |QuotaLimitHeuristic::bucket_mapper_|. As
2109 // long as |this| exists, the respective BucketMapper and its bucket will
2111 void OnPageLoad(Bucket* bucket);
2113 // Flag to prevent that we register more than one call back in-between
2114 // clearing the cache.
2115 bool callback_registered_;
2117 base::WeakPtrFactory<ClearCacheQuotaHeuristic> weak_ptr_factory_;
2119 DISALLOW_COPY_AND_ASSIGN(ClearCacheQuotaHeuristic);
2122 bool ClearCacheQuotaHeuristic::Apply(Bucket* bucket,
2123 const base::TimeTicks& event_time) {
2124 if (event_time > bucket->expiration())
2125 bucket->Reset(config(), event_time);
2127 // Call bucket->DeductToken() on a new page load, this is when
2128 // webRequest.handlerBehaviorChanged() clears the cache.
2129 if (!callback_registered_) {
2130 ExtensionWebRequestEventRouter::GetInstance()->AddCallbackForPageLoad(
2131 base::Bind(&ClearCacheQuotaHeuristic::OnPageLoad,
2132 weak_ptr_factory_.GetWeakPtr(),
2134 callback_registered_ = true;
2137 // We only check whether tokens are left here. Deducting a token happens in
2139 return bucket->has_tokens();
2142 void ClearCacheQuotaHeuristic::OnPageLoad(Bucket* bucket) {
2143 callback_registered_ = false;
2144 bucket->DeductToken();
2147 bool WebRequestInternalAddEventListenerFunction::RunSync() {
2148 // Argument 0 is the callback, which we don't use here.
2149 ExtensionWebRequestEventRouter::RequestFilter filter;
2150 base::DictionaryValue* value = NULL;
2152 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &value));
2153 // Failure + an empty error string means a fatal error.
2154 EXTENSION_FUNCTION_VALIDATE(filter.InitFromValue(*value, &error_) ||
2156 if (!error_.empty())
2159 int extra_info_spec = 0;
2160 if (HasOptionalArgument(2)) {
2161 base::ListValue* value = NULL;
2162 EXTENSION_FUNCTION_VALIDATE(args_->GetList(2, &value));
2163 EXTENSION_FUNCTION_VALIDATE(
2164 ExtensionWebRequestEventRouter::ExtraInfoSpec::InitFromValue(
2165 *value, &extra_info_spec));
2168 std::string event_name;
2169 EXTENSION_FUNCTION_VALIDATE(args_->GetString(3, &event_name));
2171 std::string sub_event_name;
2172 EXTENSION_FUNCTION_VALIDATE(args_->GetString(4, &sub_event_name));
2174 int webview_instance_id = 0;
2175 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(5, &webview_instance_id));
2177 base::WeakPtr<extensions::ExtensionMessageFilter> ipc_sender =
2179 int embedder_process_id =
2180 ipc_sender.get() ? ipc_sender->render_process_id() : -1;
2182 const Extension* extension =
2183 extension_info_map()->extensions().GetByID(extension_id());
2184 std::string extension_name = extension ? extension->name() : extension_id();
2186 bool is_guest = webview_instance_id != 0;
2187 // We check automatically whether the extension has the 'webRequest'
2188 // permission. For blocking calls we require the additional permission
2189 // 'webRequestBlocking'.
2190 if ((!is_guest && extra_info_spec &
2191 (ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING |
2192 ExtensionWebRequestEventRouter::ExtraInfoSpec::ASYNC_BLOCKING)) &&
2193 !extension->HasAPIPermission(
2194 extensions::APIPermission::kWebRequestBlocking)) {
2195 error_ = keys::kBlockingPermissionRequired;
2199 // We allow to subscribe to patterns that are broader than the host
2200 // permissions. E.g., we could subscribe to http://www.example.com/*
2201 // while having host permissions for http://www.example.com/foo/* and
2202 // http://www.example.com/bar/*.
2203 // For this reason we do only a coarse check here to warn the extension
2204 // developer if he does something obviously wrong.
2205 if (!is_guest && extensions::PermissionsData::GetEffectiveHostPermissions(
2206 extension).is_empty()) {
2207 error_ = keys::kHostPermissionsRequired;
2212 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
2213 profile_id(), extension_id(), extension_name,
2214 event_name, sub_event_name, filter, extra_info_spec,
2215 embedder_process_id, webview_instance_id, ipc_sender_weak());
2216 EXTENSION_FUNCTION_VALIDATE(success);
2218 helpers::ClearCacheOnNavigation();
2220 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
2221 &helpers::NotifyWebRequestAPIUsed,
2222 profile_id(), make_scoped_refptr(GetExtension())));
2227 void WebRequestInternalEventHandledFunction::RespondWithError(
2228 const std::string& event_name,
2229 const std::string& sub_event_name,
2231 scoped_ptr<ExtensionWebRequestEventRouter::EventResponse> response,
2232 const std::string& error) {
2234 ExtensionWebRequestEventRouter::GetInstance()->OnEventHandled(
2240 response.release());
2243 bool WebRequestInternalEventHandledFunction::RunSync() {
2244 std::string event_name;
2245 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &event_name));
2247 std::string sub_event_name;
2248 EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &sub_event_name));
2250 std::string request_id_str;
2251 EXTENSION_FUNCTION_VALIDATE(args_->GetString(2, &request_id_str));
2253 EXTENSION_FUNCTION_VALIDATE(base::StringToUint64(request_id_str,
2256 scoped_ptr<ExtensionWebRequestEventRouter::EventResponse> response;
2257 if (HasOptionalArgument(3)) {
2258 base::DictionaryValue* value = NULL;
2259 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(3, &value));
2261 if (!value->empty()) {
2262 base::Time install_time =
2263 extension_info_map()->GetInstallTime(extension_id());
2264 response.reset(new ExtensionWebRequestEventRouter::EventResponse(
2265 extension_id(), install_time));
2268 if (value->HasKey("cancel")) {
2269 // Don't allow cancel mixed with other keys.
2270 if (value->size() != 1) {
2271 RespondWithError(event_name,
2275 keys::kInvalidBlockingResponse);
2279 bool cancel = false;
2280 EXTENSION_FUNCTION_VALIDATE(value->GetBoolean("cancel", &cancel));
2281 response->cancel = cancel;
2284 if (value->HasKey("redirectUrl")) {
2285 std::string new_url_str;
2286 EXTENSION_FUNCTION_VALIDATE(value->GetString("redirectUrl",
2288 response->new_url = GURL(new_url_str);
2289 if (!response->new_url.is_valid()) {
2290 RespondWithError(event_name,
2294 ErrorUtils::FormatErrorMessage(
2295 keys::kInvalidRedirectUrl, new_url_str));
2300 const bool hasRequestHeaders = value->HasKey("requestHeaders");
2301 const bool hasResponseHeaders = value->HasKey("responseHeaders");
2302 if (hasRequestHeaders || hasResponseHeaders) {
2303 if (hasRequestHeaders && hasResponseHeaders) {
2304 // Allow only one of the keys, not both.
2305 RespondWithError(event_name,
2309 keys::kInvalidHeaderKeyCombination);
2313 base::ListValue* headers_value = NULL;
2314 scoped_ptr<net::HttpRequestHeaders> request_headers;
2315 scoped_ptr<helpers::ResponseHeaders> response_headers;
2316 if (hasRequestHeaders) {
2317 request_headers.reset(new net::HttpRequestHeaders());
2318 EXTENSION_FUNCTION_VALIDATE(value->GetList(keys::kRequestHeadersKey,
2321 response_headers.reset(new helpers::ResponseHeaders());
2322 EXTENSION_FUNCTION_VALIDATE(value->GetList(keys::kResponseHeadersKey,
2326 for (size_t i = 0; i < headers_value->GetSize(); ++i) {
2327 base::DictionaryValue* header_value = NULL;
2330 EXTENSION_FUNCTION_VALIDATE(
2331 headers_value->GetDictionary(i, &header_value));
2332 if (!FromHeaderDictionary(header_value, &name, &value)) {
2333 std::string serialized_header;
2334 base::JSONWriter::Write(header_value, &serialized_header);
2335 RespondWithError(event_name,
2339 ErrorUtils::FormatErrorMessage(keys::kInvalidHeader,
2340 serialized_header));
2343 if (!helpers::IsValidHeaderName(name)) {
2344 RespondWithError(event_name,
2348 keys::kInvalidHeaderName);
2351 if (!helpers::IsValidHeaderValue(value)) {
2352 RespondWithError(event_name,
2356 ErrorUtils::FormatErrorMessage(
2357 keys::kInvalidHeaderValue, name));
2360 if (hasRequestHeaders)
2361 request_headers->SetHeader(name, value);
2363 response_headers->push_back(helpers::ResponseHeader(name, value));
2365 if (hasRequestHeaders)
2366 response->request_headers.reset(request_headers.release());
2368 response->response_headers.reset(response_headers.release());
2371 if (value->HasKey(keys::kAuthCredentialsKey)) {
2372 base::DictionaryValue* credentials_value = NULL;
2373 EXTENSION_FUNCTION_VALIDATE(value->GetDictionary(
2374 keys::kAuthCredentialsKey,
2375 &credentials_value));
2376 base::string16 username;
2377 base::string16 password;
2378 EXTENSION_FUNCTION_VALIDATE(
2379 credentials_value->GetString(keys::kUsernameKey, &username));
2380 EXTENSION_FUNCTION_VALIDATE(
2381 credentials_value->GetString(keys::kPasswordKey, &password));
2382 response->auth_credentials.reset(
2383 new net::AuthCredentials(username, password));
2387 ExtensionWebRequestEventRouter::GetInstance()->OnEventHandled(
2388 profile_id(), extension_id(), event_name, sub_event_name, request_id,
2389 response.release());
2394 void WebRequestHandlerBehaviorChangedFunction::GetQuotaLimitHeuristics(
2395 extensions::QuotaLimitHeuristics* heuristics) const {
2396 extensions::QuotaLimitHeuristic::Config config = {
2397 // See web_request.json for current value.
2398 web_request::MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES,
2399 base::TimeDelta::FromMinutes(10)};
2400 extensions::QuotaLimitHeuristic::BucketMapper* bucket_mapper =
2401 new extensions::QuotaLimitHeuristic::SingletonBucketMapper();
2402 ClearCacheQuotaHeuristic* heuristic =
2403 new ClearCacheQuotaHeuristic(config, bucket_mapper);
2404 heuristics->push_back(heuristic);
2407 void WebRequestHandlerBehaviorChangedFunction::OnQuotaExceeded(
2408 const std::string& violation_error) {
2409 // Post warning message.
2410 ExtensionWarningSet warnings;
2412 ExtensionWarning::CreateRepeatedCacheFlushesWarning(extension_id()));
2413 BrowserThread::PostTask(
2416 base::Bind(&ExtensionWarningService::NotifyWarningsOnUI,
2417 profile_id(), warnings));
2419 // Continue gracefully.
2423 bool WebRequestHandlerBehaviorChangedFunction::RunSync() {
2424 helpers::ClearCacheOnNavigation();
2428 void SendExtensionWebRequestStatusToHost(content::RenderProcessHost* host) {
2429 Profile* profile = Profile::FromBrowserContext(host->GetBrowserContext());
2433 bool adblock = false;
2434 bool adblock_plus = false;
2436 const extensions::ExtensionSet& extensions =
2437 extensions::ExtensionRegistry::Get(profile)->enabled_extensions();
2438 extensions::RuntimeData* runtime_data =
2439 extensions::ExtensionSystem::Get(profile)->runtime_data();
2440 for (extensions::ExtensionSet::const_iterator it = extensions.begin();
2441 it != extensions.end(); ++it) {
2442 if (runtime_data->HasUsedWebRequest(it->get())) {
2443 if ((*it)->name().find("Adblock Plus") != std::string::npos) {
2444 adblock_plus = true;
2445 } else if ((*it)->name().find("AdBlock") != std::string::npos) {
2453 host->Send(new ExtensionMsg_UsingWebRequestAPI(adblock, adblock_plus, other));