Don't show supervised user as "already on this device" while they're being imported.
[chromium-blink-merge.git] / extensions / browser / api / web_request / web_request_api.cc
blobf6c75274dca5baff22e2f25a09487a06a1055474
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 "extensions/browser/api/web_request/web_request_api.h"
7 #include <algorithm>
9 #include "base/bind.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 "content/public/browser/browser_message_filter.h"
20 #include "content/public/browser/browser_thread.h"
21 #include "content/public/browser/render_frame_host.h"
22 #include "content/public/browser/render_process_host.h"
23 #include "content/public/browser/resource_request_info.h"
24 #include "content/public/browser/user_metrics.h"
25 #include "extensions/browser/api/activity_log/web_request_constants.h"
26 #include "extensions/browser/api/declarative/rules_registry_service.h"
27 #include "extensions/browser/api/declarative_webrequest/request_stage.h"
28 #include "extensions/browser/api/declarative_webrequest/webrequest_constants.h"
29 #include "extensions/browser/api/declarative_webrequest/webrequest_rules_registry.h"
30 #include "extensions/browser/api/extensions_api_client.h"
31 #include "extensions/browser/api/web_request/upload_data_presenter.h"
32 #include "extensions/browser/api/web_request/web_request_api_constants.h"
33 #include "extensions/browser/api/web_request/web_request_api_helpers.h"
34 #include "extensions/browser/api/web_request/web_request_event_router_delegate.h"
35 #include "extensions/browser/api/web_request/web_request_time_tracker.h"
36 #include "extensions/browser/event_router.h"
37 #include "extensions/browser/extension_prefs.h"
38 #include "extensions/browser/extension_registry.h"
39 #include "extensions/browser/extension_system.h"
40 #include "extensions/browser/extensions_browser_client.h"
41 #include "extensions/browser/guest_view/web_view/web_view_constants.h"
42 #include "extensions/browser/guest_view/web_view/web_view_renderer_state.h"
43 #include "extensions/browser/info_map.h"
44 #include "extensions/browser/io_thread_extension_message_filter.h"
45 #include "extensions/browser/runtime_data.h"
46 #include "extensions/browser/warning_service.h"
47 #include "extensions/browser/warning_set.h"
48 #include "extensions/common/api/web_request.h"
49 #include "extensions/common/error_utils.h"
50 #include "extensions/common/event_filtering_info.h"
51 #include "extensions/common/extension.h"
52 #include "extensions/common/features/feature.h"
53 #include "extensions/common/permissions/permissions_data.h"
54 #include "extensions/common/url_pattern.h"
55 #include "extensions/strings/grit/extensions_strings.h"
56 #include "net/base/auth.h"
57 #include "net/base/net_errors.h"
58 #include "net/base/upload_data_stream.h"
59 #include "net/http/http_response_headers.h"
60 #include "net/http/http_util.h"
61 #include "net/url_request/url_request.h"
62 #include "ui/base/l10n/l10n_util.h"
63 #include "url/gurl.h"
65 using base::DictionaryValue;
66 using base::ListValue;
67 using base::StringValue;
68 using content::BrowserMessageFilter;
69 using content::BrowserThread;
70 using content::ResourceRequestInfo;
71 using content::ResourceType;
72 using extensions::ErrorUtils;
73 using extensions::Extension;
74 using extensions::InfoMap;
75 using extensions::Feature;
76 using extensions::RulesRegistryService;
77 using extensions::Warning;
78 using extensions::WarningService;
79 using extensions::WarningSet;
81 namespace activitylog = activity_log_web_request_constants;
82 namespace helpers = extension_web_request_api_helpers;
83 namespace keys = extension_web_request_api_constants;
84 namespace web_request = extensions::core_api::web_request;
85 namespace declarative_keys = extensions::declarative_webrequest_constants;
87 namespace {
89 const char kWebRequestEventPrefix[] = "webRequest.";
91 // List of all the webRequest events.
92 const char* const kWebRequestEvents[] = {
93 keys::kOnBeforeRedirectEvent,
94 web_request::OnBeforeRequest::kEventName,
95 keys::kOnBeforeSendHeadersEvent,
96 keys::kOnCompletedEvent,
97 web_request::OnErrorOccurred::kEventName,
98 keys::kOnSendHeadersEvent,
99 keys::kOnAuthRequiredEvent,
100 keys::kOnResponseStartedEvent,
101 keys::kOnHeadersReceivedEvent,
104 const size_t kWebRequestEventsLength = arraysize(kWebRequestEvents);
106 const char* GetRequestStageAsString(
107 ExtensionWebRequestEventRouter::EventTypes type) {
108 switch (type) {
109 case ExtensionWebRequestEventRouter::kInvalidEvent:
110 return "Invalid";
111 case ExtensionWebRequestEventRouter::kOnBeforeRequest:
112 return keys::kOnBeforeRequest;
113 case ExtensionWebRequestEventRouter::kOnBeforeSendHeaders:
114 return keys::kOnBeforeSendHeaders;
115 case ExtensionWebRequestEventRouter::kOnSendHeaders:
116 return keys::kOnSendHeaders;
117 case ExtensionWebRequestEventRouter::kOnHeadersReceived:
118 return keys::kOnHeadersReceived;
119 case ExtensionWebRequestEventRouter::kOnBeforeRedirect:
120 return keys::kOnBeforeRedirect;
121 case ExtensionWebRequestEventRouter::kOnAuthRequired:
122 return keys::kOnAuthRequired;
123 case ExtensionWebRequestEventRouter::kOnResponseStarted:
124 return keys::kOnResponseStarted;
125 case ExtensionWebRequestEventRouter::kOnErrorOccurred:
126 return keys::kOnErrorOccurred;
127 case ExtensionWebRequestEventRouter::kOnCompleted:
128 return keys::kOnCompleted;
130 NOTREACHED();
131 return "Not reached";
134 int GetFrameId(bool is_main_frame, int frame_id) {
135 return is_main_frame ? 0 : frame_id;
138 bool IsWebRequestEvent(const std::string& event_name) {
139 std::string web_request_event_name(event_name);
140 if (StartsWithASCII(
141 web_request_event_name, webview::kWebViewEventPrefix, true)) {
142 web_request_event_name.replace(
143 0, strlen(webview::kWebViewEventPrefix), kWebRequestEventPrefix);
145 return std::find(
146 kWebRequestEvents,
147 kWebRequestEvents + kWebRequestEventsLength,
148 web_request_event_name) != (kWebRequestEvents + kWebRequestEventsLength);
151 // Returns whether |request| has been triggered by an extension in
152 // |extension_info_map|.
153 bool IsRequestFromExtension(const net::URLRequest* request,
154 const InfoMap* extension_info_map) {
155 // |extension_info_map| is NULL for system-level requests.
156 if (!extension_info_map)
157 return false;
159 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
161 // If this request was not created by the ResourceDispatcher, |info| is NULL.
162 // All requests from extensions are created by the ResourceDispatcher.
163 if (!info)
164 return false;
166 return extension_info_map->process_map().Contains(info->GetChildID());
169 void ExtractRequestRoutingInfo(net::URLRequest* request,
170 int* render_process_host_id,
171 int* routing_id) {
172 if (!request->GetUserData(NULL))
173 return;
174 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
175 *render_process_host_id = info->GetChildID();
176 *routing_id = info->GetRouteID();
179 // Given a |request|, this function determines whether it originated from
180 // a <webview> guest process or not. If it is from a <webview> guest process,
181 // then |web_view_info| is returned with information about the instance ID
182 // that uniquely identifies the <webview> and its embedder.
183 bool GetWebViewInfo(
184 net::URLRequest* request,
185 extensions::WebViewRendererState::WebViewInfo* web_view_info) {
186 int render_process_host_id = -1;
187 int routing_id = -1;
188 ExtractRequestRoutingInfo(request, &render_process_host_id, &routing_id);
189 return extensions::WebViewRendererState::GetInstance()->
190 GetInfo(render_process_host_id, routing_id, web_view_info);
193 void ExtractRequestInfoDetails(net::URLRequest* request,
194 bool* is_main_frame,
195 int* frame_id,
196 bool* parent_is_main_frame,
197 int* parent_frame_id,
198 int* render_process_host_id,
199 int* routing_id,
200 ResourceType* resource_type) {
201 if (!request->GetUserData(NULL))
202 return;
204 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
205 *frame_id = info->GetRenderFrameID();
206 *is_main_frame = info->IsMainFrame();
207 *parent_frame_id = info->GetParentRenderFrameID();
208 *parent_is_main_frame = info->ParentIsMainFrame();
209 *render_process_host_id = info->GetChildID();
210 *routing_id = info->GetRouteID();
212 // Restrict the resource type to the values we care about.
213 if (helpers::IsRelevantResourceType(info->GetResourceType()))
214 *resource_type = info->GetResourceType();
215 else
216 *resource_type = content::RESOURCE_TYPE_LAST_TYPE;
219 // Extracts the body from |request| and writes the data into |out|.
220 void ExtractRequestInfoBody(const net::URLRequest* request,
221 base::DictionaryValue* out) {
222 const net::UploadDataStream* upload_data = request->get_upload();
223 if (!upload_data ||
224 (request->method() != "POST" && request->method() != "PUT"))
225 return; // Need to exit without "out->Set(keys::kRequestBodyKey, ...);" .
227 base::DictionaryValue* request_body = new base::DictionaryValue();
228 out->Set(keys::kRequestBodyKey, request_body);
230 // Get the data presenters, ordered by how specific they are.
231 extensions::ParsedDataPresenter parsed_data_presenter(*request);
232 extensions::RawDataPresenter raw_data_presenter;
233 extensions::UploadDataPresenter* const presenters[] = {
234 &parsed_data_presenter, // 1: any parseable forms? (Specific to forms.)
235 &raw_data_presenter // 2: any data at all? (Non-specific.)
237 // Keys for the results of the corresponding presenters.
238 static const char* const kKeys[] = {
239 keys::kRequestBodyFormDataKey,
240 keys::kRequestBodyRawKey
243 const ScopedVector<net::UploadElementReader>* readers =
244 upload_data->GetElementReaders();
245 bool some_succeeded = false;
246 if (readers) {
247 for (size_t i = 0; !some_succeeded && i < arraysize(presenters); ++i) {
248 ScopedVector<net::UploadElementReader>::const_iterator reader;
249 for (reader = readers->begin(); reader != readers->end(); ++reader)
250 presenters[i]->FeedNext(**reader);
251 if (presenters[i]->Succeeded()) {
252 request_body->Set(kKeys[i], presenters[i]->Result().release());
253 some_succeeded = true;
257 if (!some_succeeded)
258 request_body->SetString(keys::kRequestBodyErrorKey, "Unknown error.");
261 // Converts a HttpHeaders dictionary to a |name|, |value| pair. Returns
262 // true if successful.
263 bool FromHeaderDictionary(const base::DictionaryValue* header_value,
264 std::string* name,
265 std::string* value) {
266 if (!header_value->GetString(keys::kHeaderNameKey, name))
267 return false;
269 // We require either a "value" or a "binaryValue" entry.
270 if (!(header_value->HasKey(keys::kHeaderValueKey) ^
271 header_value->HasKey(keys::kHeaderBinaryValueKey)))
272 return false;
274 if (header_value->HasKey(keys::kHeaderValueKey)) {
275 if (!header_value->GetString(keys::kHeaderValueKey, value)) {
276 return false;
278 } else if (header_value->HasKey(keys::kHeaderBinaryValueKey)) {
279 const base::ListValue* list = NULL;
280 if (!header_value->HasKey(keys::kHeaderBinaryValueKey)) {
281 *value = "";
282 } else if (!header_value->GetList(keys::kHeaderBinaryValueKey, &list) ||
283 !helpers::CharListToString(list, value)) {
284 return false;
287 return true;
290 // Creates a list of HttpHeaders (see the extension API JSON). If |headers| is
291 // NULL, the list is empty. Ownership is passed to the caller.
292 base::ListValue* GetResponseHeadersList(
293 const net::HttpResponseHeaders* headers) {
294 base::ListValue* headers_value = new base::ListValue();
295 if (headers) {
296 void* iter = NULL;
297 std::string name;
298 std::string value;
299 while (headers->EnumerateHeaderLines(&iter, &name, &value))
300 headers_value->Append(helpers::CreateHeaderDictionary(name, value));
302 return headers_value;
305 base::ListValue* GetRequestHeadersList(const net::HttpRequestHeaders& headers) {
306 base::ListValue* headers_value = new base::ListValue();
307 for (net::HttpRequestHeaders::Iterator it(headers); it.GetNext(); )
308 headers_value->Append(
309 helpers::CreateHeaderDictionary(it.name(), it.value()));
310 return headers_value;
313 // Creates a base::StringValue with the status line of |headers|. If |headers|
314 // is NULL, an empty string is returned. Ownership is passed to the caller.
315 base::StringValue* GetStatusLine(net::HttpResponseHeaders* headers) {
316 return new base::StringValue(
317 headers ? headers->GetStatusLine() : std::string());
320 // Sends an event to subscribers of chrome.declarativeWebRequest.onMessage or
321 // to subscribers of webview.onMessage if the action is being operated upon
322 // a <webview> guest renderer.
323 // |extension_id| identifies the extension that sends and receives the event.
324 // |is_web_view_guest| indicates whether the action is for a <webview>.
325 // |web_view_info| is a struct containing information about the <webview>
326 // embedder.
327 // |event_argument| is passed to the event listener.
328 void SendOnMessageEventOnUI(
329 void* browser_context_id,
330 const std::string& extension_id,
331 bool is_web_view_guest,
332 const extensions::WebViewRendererState::WebViewInfo& web_view_info,
333 scoped_ptr<base::DictionaryValue> event_argument) {
334 DCHECK_CURRENTLY_ON(BrowserThread::UI);
336 content::BrowserContext* browser_context =
337 reinterpret_cast<content::BrowserContext*>(browser_context_id);
338 if (!extensions::ExtensionsBrowserClient::Get()->IsValidContext(
339 browser_context))
340 return;
342 scoped_ptr<base::ListValue> event_args(new base::ListValue);
343 event_args->Append(event_argument.release());
345 extensions::EventRouter* event_router =
346 extensions::EventRouter::Get(browser_context);
348 extensions::EventFilteringInfo event_filtering_info;
350 std::string event_name;
351 // The instance ID uniquely identifies a <webview> instance within an embedder
352 // process. We use a filter here so that only event listeners for a particular
353 // <webview> will fire.
354 if (is_web_view_guest) {
355 event_filtering_info.SetInstanceID(web_view_info.instance_id);
356 event_name = webview::kEventMessage;
357 } else {
358 event_name = declarative_keys::kOnMessage;
361 scoped_ptr<extensions::Event> event(new extensions::Event(
362 event_name,
363 event_args.Pass(), browser_context, GURL(),
364 extensions::EventRouter::USER_GESTURE_UNKNOWN,
365 event_filtering_info));
366 event_router->DispatchEventToExtension(extension_id, event.Pass());
369 void RemoveEventListenerOnIOThread(
370 void* browser_context,
371 const std::string& extension_id,
372 const std::string& sub_event_name,
373 int embedder_process_id,
374 int web_view_instance_id) {
375 DCHECK_CURRENTLY_ON(BrowserThread::IO);
376 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(
377 browser_context, extension_id, sub_event_name,
378 embedder_process_id, web_view_instance_id);
381 } // namespace
383 namespace extensions {
385 WebRequestAPI::WebRequestAPI(content::BrowserContext* context)
386 : browser_context_(context) {
387 EventRouter* event_router = EventRouter::Get(browser_context_);
388 for (size_t i = 0; i < arraysize(kWebRequestEvents); ++i) {
389 // Observe the webRequest event.
390 std::string event_name = kWebRequestEvents[i];
391 event_router->RegisterObserver(this, event_name);
393 // Also observe the corresponding webview event.
394 event_name.replace(
395 0, sizeof(kWebRequestEventPrefix) - 1, webview::kWebViewEventPrefix);
396 event_router->RegisterObserver(this, event_name);
400 WebRequestAPI::~WebRequestAPI() {
401 EventRouter::Get(browser_context_)->UnregisterObserver(this);
404 static base::LazyInstance<BrowserContextKeyedAPIFactory<WebRequestAPI> >
405 g_factory = LAZY_INSTANCE_INITIALIZER;
407 // static
408 BrowserContextKeyedAPIFactory<WebRequestAPI>*
409 WebRequestAPI::GetFactoryInstance() {
410 return g_factory.Pointer();
413 void WebRequestAPI::OnListenerRemoved(const EventListenerInfo& details) {
414 DCHECK_CURRENTLY_ON(BrowserThread::UI);
415 // Note that details.event_name includes the sub-event details (e.g. "/123").
416 // TODO(fsamuel): <webview> events will not be removed through this code path.
417 // <webview> events will be removed in RemoveWebViewEventListeners. Ideally,
418 // this code should be decoupled from extensions, we should use the host ID
419 // instead, and not have two different code paths. This is a huge undertaking
420 // unfortunately, so we'll resort to two code paths for now.
421 BrowserThread::PostTask(BrowserThread::IO,
422 FROM_HERE,
423 base::Bind(&RemoveEventListenerOnIOThread,
424 details.browser_context,
425 details.extension_id,
426 details.event_name,
427 0 /* embedder_process_id */,
428 0 /* web_view_instance_id */));
431 } // namespace extensions
433 // Represents a single unique listener to an event, along with whatever filter
434 // parameters and extra_info_spec were specified at the time the listener was
435 // added.
436 // NOTE(benjhayden) New APIs should not use this sub_event_name trick! It does
437 // not play well with event pages. See downloads.onDeterminingFilename and
438 // ExtensionDownloadsEventRouter for an alternative approach.
439 struct ExtensionWebRequestEventRouter::EventListener {
440 std::string extension_id;
441 std::string extension_name;
442 std::string sub_event_name;
443 RequestFilter filter;
444 int extra_info_spec;
445 int embedder_process_id;
446 int web_view_instance_id;
447 base::WeakPtr<IPC::Sender> ipc_sender;
448 mutable std::set<uint64> blocked_requests;
450 // Comparator to work with std::set.
451 bool operator<(const EventListener& that) const {
452 if (extension_id != that.extension_id)
453 return extension_id < that.extension_id;
455 if (sub_event_name != that.sub_event_name)
456 return sub_event_name < that.sub_event_name;
458 if (embedder_process_id != that.embedder_process_id)
459 return embedder_process_id < that.embedder_process_id;
461 if (web_view_instance_id != that.web_view_instance_id)
462 return web_view_instance_id < that.web_view_instance_id;
464 return false;
467 EventListener() :
468 extra_info_spec(0),
469 embedder_process_id(0),
470 web_view_instance_id(0) {}
473 // Contains info about requests that are blocked waiting for a response from
474 // an extension.
475 struct ExtensionWebRequestEventRouter::BlockedRequest {
476 // The request that is being blocked.
477 net::URLRequest* request;
479 // Whether the request originates from an incognito tab.
480 bool is_incognito;
482 // The event that we're currently blocked on.
483 EventTypes event;
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
489 // debugging.
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.
497 GURL* new_url;
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;
530 BlockedRequest()
531 : request(NULL),
532 is_incognito(false),
533 event(kInvalidEvent),
534 num_handlers_blocking(0),
535 net_log(NULL),
536 new_url(NULL),
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"))
546 return false;
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))
552 return false;
553 for (size_t i = 0; i < urls_value->GetSize(); ++i) {
554 std::string url;
555 URLPattern pattern(
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);
563 return false;
565 urls.AddPattern(pattern);
567 } else if (it.key() == "types") {
568 const base::ListValue* types_value = NULL;
569 if (!it.value().GetAsList(&types_value))
570 return false;
571 for (size_t i = 0; i < types_value->GetSize(); ++i) {
572 std::string type_str;
573 ResourceType type;
574 if (!types_value->GetString(i, &type_str) ||
575 !helpers::ParseResourceType(type_str, &type))
576 return false;
577 types.push_back(type);
579 } else if (it.key() == "tabId") {
580 if (!it.value().GetAsInteger(&tab_id))
581 return false;
582 } else if (it.key() == "windowId") {
583 if (!it.value().GetAsInteger(&window_id))
584 return false;
585 } else {
586 return false;
589 return true;
592 // static
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) {
597 std::string str;
598 if (!value.GetString(i, &str))
599 return false;
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;
611 else
612 return false;
614 // BLOCKING and ASYNC_BLOCKING are mutually exclusive.
615 if ((*extra_info_spec & BLOCKING) && (*extra_info_spec & ASYNC_BLOCKING))
616 return false;
618 return true;
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),
626 cancel(false) {
629 ExtensionWebRequestEventRouter::EventResponse::~EventResponse() {
632 ExtensionWebRequestEventRouter::RequestFilter::RequestFilter()
633 : tab_id(-1), window_id(-1) {
636 ExtensionWebRequestEventRouter::RequestFilter::~RequestFilter() {
640 // ExtensionWebRequestEventRouter
643 // static
644 ExtensionWebRequestEventRouter* ExtensionWebRequestEventRouter::GetInstance() {
645 return Singleton<ExtensionWebRequestEventRouter>::get();
648 ExtensionWebRequestEventRouter::ExtensionWebRequestEventRouter()
649 : request_time_tracker_(new ExtensionWebRequestTimeTracker) {
650 web_request_event_router_delegate_.reset(
651 extensions::ExtensionsAPIClient::Get()->
652 CreateWebRequestEventRouterDelegate());
655 ExtensionWebRequestEventRouter::~ExtensionWebRequestEventRouter() {
658 void ExtensionWebRequestEventRouter::RegisterRulesRegistry(
659 void* browser_context,
660 int rules_registry_id,
661 scoped_refptr<extensions::WebRequestRulesRegistry> rules_registry) {
662 RulesRegistryKey key(browser_context, rules_registry_id);
663 if (rules_registry.get())
664 rules_registries_[key] = rules_registry;
665 else
666 rules_registries_.erase(key);
669 void ExtensionWebRequestEventRouter::ExtractRequestInfo(
670 net::URLRequest* request, base::DictionaryValue* out) {
671 bool is_main_frame = false;
672 int frame_id = -1;
673 bool parent_is_main_frame = false;
674 int parent_frame_id = -1;
675 int frame_id_for_extension = -1;
676 int parent_frame_id_for_extension = -1;
677 int render_process_host_id = -1;
678 int routing_id = -1;
679 ResourceType resource_type = content::RESOURCE_TYPE_LAST_TYPE;
680 ExtractRequestInfoDetails(request, &is_main_frame, &frame_id,
681 &parent_is_main_frame, &parent_frame_id,
682 &render_process_host_id, &routing_id,
683 &resource_type);
684 frame_id_for_extension = GetFrameId(is_main_frame, frame_id);
685 parent_frame_id_for_extension = GetFrameId(parent_is_main_frame,
686 parent_frame_id);
688 out->SetString(keys::kRequestIdKey,
689 base::Uint64ToString(request->identifier()));
690 out->SetString(keys::kUrlKey, request->url().spec());
691 out->SetString(keys::kMethodKey, request->method());
692 out->SetInteger(keys::kFrameIdKey, frame_id_for_extension);
693 out->SetInteger(keys::kParentFrameIdKey, parent_frame_id_for_extension);
694 out->SetString(keys::kTypeKey, helpers::ResourceTypeToString(resource_type));
695 out->SetDouble(keys::kTimeStampKey, base::Time::Now().ToDoubleT() * 1000);
696 if (web_request_event_router_delegate_) {
697 web_request_event_router_delegate_->ExtractExtraRequestDetails(
698 request, out);
702 int ExtensionWebRequestEventRouter::OnBeforeRequest(
703 void* browser_context,
704 InfoMap* extension_info_map,
705 net::URLRequest* request,
706 const net::CompletionCallback& callback,
707 GURL* new_url) {
708 // We hide events from the system context as well as sensitive requests.
709 if (!browser_context ||
710 WebRequestPermissions::HideRequest(extension_info_map, request))
711 return net::OK;
713 if (IsPageLoad(request))
714 NotifyPageLoad();
716 request_time_tracker_->LogRequestStartTime(request->identifier(),
717 base::Time::Now(),
718 request->url(),
719 browser_context);
721 // Whether to initialized blocked_requests_.
722 bool initialize_blocked_requests = false;
724 initialize_blocked_requests |=
725 ProcessDeclarativeRules(browser_context, extension_info_map,
726 web_request::OnBeforeRequest::kEventName, request,
727 extensions::ON_BEFORE_REQUEST, NULL);
729 int extra_info_spec = 0;
730 std::vector<const EventListener*> listeners =
731 GetMatchingListeners(browser_context, extension_info_map,
732 web_request::OnBeforeRequest::kEventName, request,
733 &extra_info_spec);
734 if (!listeners.empty() &&
735 !GetAndSetSignaled(request->identifier(), kOnBeforeRequest)) {
736 base::ListValue args;
737 base::DictionaryValue* dict = new base::DictionaryValue();
738 ExtractRequestInfo(request, dict);
739 if (extra_info_spec & ExtraInfoSpec::REQUEST_BODY)
740 ExtractRequestInfoBody(request, dict);
741 args.Append(dict);
743 initialize_blocked_requests |=
744 DispatchEvent(browser_context, request, listeners, args);
747 if (!initialize_blocked_requests)
748 return net::OK; // Nobody saw a reason for modifying the request.
750 blocked_requests_[request->identifier()].event = kOnBeforeRequest;
751 blocked_requests_[request->identifier()].is_incognito |=
752 IsIncognitoBrowserContext(browser_context);
753 blocked_requests_[request->identifier()].request = request;
754 blocked_requests_[request->identifier()].callback = callback;
755 blocked_requests_[request->identifier()].new_url = new_url;
756 blocked_requests_[request->identifier()].net_log = &request->net_log();
758 if (blocked_requests_[request->identifier()].num_handlers_blocking == 0) {
759 // If there are no blocking handlers, only the declarative rules tried
760 // to modify the request and we can respond synchronously.
761 return ExecuteDeltas(browser_context, request->identifier(),
762 false /* call_callback*/);
763 } else {
764 return net::ERR_IO_PENDING;
768 int ExtensionWebRequestEventRouter::OnBeforeSendHeaders(
769 void* browser_context,
770 InfoMap* extension_info_map,
771 net::URLRequest* request,
772 const net::CompletionCallback& callback,
773 net::HttpRequestHeaders* headers) {
774 // We hide events from the system context as well as sensitive requests.
775 if (!browser_context ||
776 WebRequestPermissions::HideRequest(extension_info_map, request))
777 return net::OK;
779 bool initialize_blocked_requests = false;
781 initialize_blocked_requests |=
782 ProcessDeclarativeRules(browser_context, extension_info_map,
783 keys::kOnBeforeSendHeadersEvent, request,
784 extensions::ON_BEFORE_SEND_HEADERS, NULL);
786 int extra_info_spec = 0;
787 std::vector<const EventListener*> listeners =
788 GetMatchingListeners(browser_context, extension_info_map,
789 keys::kOnBeforeSendHeadersEvent, request,
790 &extra_info_spec);
791 if (!listeners.empty() &&
792 !GetAndSetSignaled(request->identifier(), kOnBeforeSendHeaders)) {
793 base::ListValue args;
794 base::DictionaryValue* dict = new base::DictionaryValue();
795 ExtractRequestInfo(request, dict);
796 if (extra_info_spec & ExtraInfoSpec::REQUEST_HEADERS)
797 dict->Set(keys::kRequestHeadersKey, GetRequestHeadersList(*headers));
798 args.Append(dict);
800 initialize_blocked_requests |=
801 DispatchEvent(browser_context, request, listeners, args);
804 if (!initialize_blocked_requests)
805 return net::OK; // Nobody saw a reason for modifying the request.
807 blocked_requests_[request->identifier()].event = kOnBeforeSendHeaders;
808 blocked_requests_[request->identifier()].is_incognito |=
809 IsIncognitoBrowserContext(browser_context);
810 blocked_requests_[request->identifier()].request = request;
811 blocked_requests_[request->identifier()].callback = callback;
812 blocked_requests_[request->identifier()].request_headers = headers;
813 blocked_requests_[request->identifier()].net_log = &request->net_log();
815 if (blocked_requests_[request->identifier()].num_handlers_blocking == 0) {
816 // If there are no blocking handlers, only the declarative rules tried
817 // to modify the request and we can respond synchronously.
818 return ExecuteDeltas(browser_context, request->identifier(),
819 false /* call_callback*/);
820 } else {
821 return net::ERR_IO_PENDING;
825 void ExtensionWebRequestEventRouter::OnSendHeaders(
826 void* browser_context,
827 InfoMap* extension_info_map,
828 net::URLRequest* request,
829 const net::HttpRequestHeaders& headers) {
830 // We hide events from the system context as well as sensitive requests.
831 if (!browser_context ||
832 WebRequestPermissions::HideRequest(extension_info_map, request))
833 return;
835 if (GetAndSetSignaled(request->identifier(), kOnSendHeaders))
836 return;
838 ClearSignaled(request->identifier(), kOnBeforeRedirect);
840 int extra_info_spec = 0;
841 std::vector<const EventListener*> listeners =
842 GetMatchingListeners(browser_context, extension_info_map,
843 keys::kOnSendHeadersEvent, request,
844 &extra_info_spec);
845 if (listeners.empty())
846 return;
848 base::ListValue args;
849 base::DictionaryValue* dict = new base::DictionaryValue();
850 ExtractRequestInfo(request, dict);
851 if (extra_info_spec & ExtraInfoSpec::REQUEST_HEADERS)
852 dict->Set(keys::kRequestHeadersKey, GetRequestHeadersList(headers));
853 args.Append(dict);
855 DispatchEvent(browser_context, request, listeners, args);
858 int ExtensionWebRequestEventRouter::OnHeadersReceived(
859 void* browser_context,
860 InfoMap* extension_info_map,
861 net::URLRequest* request,
862 const net::CompletionCallback& callback,
863 const net::HttpResponseHeaders* original_response_headers,
864 scoped_refptr<net::HttpResponseHeaders>* override_response_headers,
865 GURL* allowed_unsafe_redirect_url) {
866 // We hide events from the system context as well as sensitive requests.
867 if (!browser_context ||
868 WebRequestPermissions::HideRequest(extension_info_map, request))
869 return net::OK;
871 bool initialize_blocked_requests = false;
873 initialize_blocked_requests |=
874 ProcessDeclarativeRules(browser_context, extension_info_map,
875 keys::kOnHeadersReceivedEvent, request,
876 extensions::ON_HEADERS_RECEIVED,
877 original_response_headers);
879 int extra_info_spec = 0;
880 std::vector<const EventListener*> listeners =
881 GetMatchingListeners(browser_context, extension_info_map,
882 keys::kOnHeadersReceivedEvent, request,
883 &extra_info_spec);
885 if (!listeners.empty() &&
886 !GetAndSetSignaled(request->identifier(), kOnHeadersReceived)) {
887 base::ListValue args;
888 base::DictionaryValue* dict = new base::DictionaryValue();
889 ExtractRequestInfo(request, dict);
890 dict->SetString(keys::kStatusLineKey,
891 original_response_headers->GetStatusLine());
892 dict->SetInteger(keys::kStatusCodeKey,
893 original_response_headers->response_code());
894 if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
895 dict->Set(keys::kResponseHeadersKey,
896 GetResponseHeadersList(original_response_headers));
898 args.Append(dict);
900 initialize_blocked_requests |=
901 DispatchEvent(browser_context, request, listeners, args);
904 if (!initialize_blocked_requests)
905 return net::OK; // Nobody saw a reason for modifying the request.
907 blocked_requests_[request->identifier()].event = kOnHeadersReceived;
908 blocked_requests_[request->identifier()].is_incognito |=
909 IsIncognitoBrowserContext(browser_context);
910 blocked_requests_[request->identifier()].request = request;
911 blocked_requests_[request->identifier()].callback = callback;
912 blocked_requests_[request->identifier()].net_log = &request->net_log();
913 blocked_requests_[request->identifier()].override_response_headers =
914 override_response_headers;
915 blocked_requests_[request->identifier()].original_response_headers =
916 original_response_headers;
917 blocked_requests_[request->identifier()].new_url =
918 allowed_unsafe_redirect_url;
920 if (blocked_requests_[request->identifier()].num_handlers_blocking == 0) {
921 // If there are no blocking handlers, only the declarative rules tried
922 // to modify the request and we can respond synchronously.
923 return ExecuteDeltas(browser_context, request->identifier(),
924 false /* call_callback*/);
925 } else {
926 return net::ERR_IO_PENDING;
930 net::NetworkDelegate::AuthRequiredResponse
931 ExtensionWebRequestEventRouter::OnAuthRequired(
932 void* browser_context,
933 InfoMap* extension_info_map,
934 net::URLRequest* request,
935 const net::AuthChallengeInfo& auth_info,
936 const net::NetworkDelegate::AuthCallback& callback,
937 net::AuthCredentials* credentials) {
938 // No browser_context means that this is for authentication challenges in the
939 // system context. Skip in that case. Also skip sensitive requests.
940 if (!browser_context ||
941 WebRequestPermissions::HideRequest(extension_info_map, request))
942 return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION;
944 int extra_info_spec = 0;
945 std::vector<const EventListener*> listeners =
946 GetMatchingListeners(browser_context, extension_info_map,
947 keys::kOnAuthRequiredEvent, request,
948 &extra_info_spec);
949 if (listeners.empty())
950 return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION;
952 base::ListValue args;
953 base::DictionaryValue* dict = new base::DictionaryValue();
954 ExtractRequestInfo(request, dict);
955 dict->SetBoolean(keys::kIsProxyKey, auth_info.is_proxy);
956 if (!auth_info.scheme.empty())
957 dict->SetString(keys::kSchemeKey, auth_info.scheme);
958 if (!auth_info.realm.empty())
959 dict->SetString(keys::kRealmKey, auth_info.realm);
960 base::DictionaryValue* challenger = new base::DictionaryValue();
961 challenger->SetString(keys::kHostKey, auth_info.challenger.host());
962 challenger->SetInteger(keys::kPortKey, auth_info.challenger.port());
963 dict->Set(keys::kChallengerKey, challenger);
964 dict->Set(keys::kStatusLineKey, GetStatusLine(request->response_headers()));
965 dict->SetInteger(keys::kStatusCodeKey,
966 request->response_headers()->response_code());
967 if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
968 dict->Set(keys::kResponseHeadersKey,
969 GetResponseHeadersList(request->response_headers()));
971 args.Append(dict);
973 if (DispatchEvent(browser_context, request, listeners, args)) {
974 blocked_requests_[request->identifier()].event = kOnAuthRequired;
975 blocked_requests_[request->identifier()].is_incognito |=
976 IsIncognitoBrowserContext(browser_context);
977 blocked_requests_[request->identifier()].request = request;
978 blocked_requests_[request->identifier()].auth_callback = callback;
979 blocked_requests_[request->identifier()].auth_credentials = credentials;
980 blocked_requests_[request->identifier()].net_log = &request->net_log();
981 return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_IO_PENDING;
983 return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION;
986 void ExtensionWebRequestEventRouter::OnBeforeRedirect(
987 void* browser_context,
988 InfoMap* extension_info_map,
989 net::URLRequest* request,
990 const GURL& new_location) {
991 // We hide events from the system context as well as sensitive requests.
992 if (!browser_context ||
993 WebRequestPermissions::HideRequest(extension_info_map, request))
994 return;
996 if (GetAndSetSignaled(request->identifier(), kOnBeforeRedirect))
997 return;
999 ClearSignaled(request->identifier(), kOnBeforeRequest);
1000 ClearSignaled(request->identifier(), kOnBeforeSendHeaders);
1001 ClearSignaled(request->identifier(), kOnSendHeaders);
1002 ClearSignaled(request->identifier(), kOnHeadersReceived);
1004 int extra_info_spec = 0;
1005 std::vector<const EventListener*> listeners =
1006 GetMatchingListeners(browser_context, extension_info_map,
1007 keys::kOnBeforeRedirectEvent, request,
1008 &extra_info_spec);
1009 if (listeners.empty())
1010 return;
1012 int http_status_code = request->GetResponseCode();
1014 std::string response_ip = request->GetSocketAddress().host();
1016 base::ListValue args;
1017 base::DictionaryValue* dict = new base::DictionaryValue();
1018 ExtractRequestInfo(request, dict);
1019 dict->SetString(keys::kRedirectUrlKey, new_location.spec());
1020 dict->SetInteger(keys::kStatusCodeKey, http_status_code);
1021 if (!response_ip.empty())
1022 dict->SetString(keys::kIpKey, response_ip);
1023 dict->SetBoolean(keys::kFromCache, request->was_cached());
1024 dict->Set(keys::kStatusLineKey, GetStatusLine(request->response_headers()));
1025 if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
1026 dict->Set(keys::kResponseHeadersKey,
1027 GetResponseHeadersList(request->response_headers()));
1029 args.Append(dict);
1031 DispatchEvent(browser_context, request, listeners, args);
1034 void ExtensionWebRequestEventRouter::OnResponseStarted(
1035 void* browser_context,
1036 InfoMap* extension_info_map,
1037 net::URLRequest* request) {
1038 // We hide events from the system context as well as sensitive requests.
1039 if (!browser_context ||
1040 WebRequestPermissions::HideRequest(extension_info_map, request))
1041 return;
1043 // OnResponseStarted is even triggered, when the request was cancelled.
1044 if (request->status().status() != net::URLRequestStatus::SUCCESS)
1045 return;
1047 int extra_info_spec = 0;
1048 std::vector<const EventListener*> listeners =
1049 GetMatchingListeners(browser_context, extension_info_map,
1050 keys::kOnResponseStartedEvent, request,
1051 &extra_info_spec);
1052 if (listeners.empty())
1053 return;
1055 // UrlRequestFileJobs do not send headers, so we simulate their behavior.
1056 int response_code = 200;
1057 if (request->response_headers())
1058 response_code = request->response_headers()->response_code();
1060 std::string response_ip = request->GetSocketAddress().host();
1062 base::ListValue args;
1063 base::DictionaryValue* dict = new base::DictionaryValue();
1064 ExtractRequestInfo(request, dict);
1065 if (!response_ip.empty())
1066 dict->SetString(keys::kIpKey, response_ip);
1067 dict->SetBoolean(keys::kFromCache, request->was_cached());
1068 dict->SetInteger(keys::kStatusCodeKey, response_code);
1069 dict->Set(keys::kStatusLineKey, GetStatusLine(request->response_headers()));
1070 if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
1071 dict->Set(keys::kResponseHeadersKey,
1072 GetResponseHeadersList(request->response_headers()));
1074 args.Append(dict);
1076 DispatchEvent(browser_context, request, listeners, args);
1079 void ExtensionWebRequestEventRouter::OnCompleted(void* browser_context,
1080 InfoMap* extension_info_map,
1081 net::URLRequest* request) {
1082 // We hide events from the system context as well as sensitive requests.
1083 // However, if the request first became sensitive after redirecting we have
1084 // already signaled it and thus we have to signal the end of it. This is
1085 // risk-free because the handler cannot modify the request now.
1086 if (!browser_context ||
1087 (WebRequestPermissions::HideRequest(extension_info_map, request) &&
1088 !WasSignaled(*request)))
1089 return;
1091 request_time_tracker_->LogRequestEndTime(request->identifier(),
1092 base::Time::Now());
1094 DCHECK(request->status().status() == net::URLRequestStatus::SUCCESS);
1096 DCHECK(!GetAndSetSignaled(request->identifier(), kOnCompleted));
1098 ClearPendingCallbacks(request);
1100 int extra_info_spec = 0;
1101 std::vector<const EventListener*> listeners =
1102 GetMatchingListeners(browser_context, extension_info_map,
1103 keys::kOnCompletedEvent, request, &extra_info_spec);
1104 if (listeners.empty())
1105 return;
1107 // UrlRequestFileJobs do not send headers, so we simulate their behavior.
1108 int response_code = 200;
1109 if (request->response_headers())
1110 response_code = request->response_headers()->response_code();
1112 std::string response_ip = request->GetSocketAddress().host();
1114 base::ListValue args;
1115 base::DictionaryValue* dict = new base::DictionaryValue();
1116 ExtractRequestInfo(request, dict);
1117 dict->SetInteger(keys::kStatusCodeKey, response_code);
1118 if (!response_ip.empty())
1119 dict->SetString(keys::kIpKey, response_ip);
1120 dict->SetBoolean(keys::kFromCache, request->was_cached());
1121 dict->Set(keys::kStatusLineKey, GetStatusLine(request->response_headers()));
1122 if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
1123 dict->Set(keys::kResponseHeadersKey,
1124 GetResponseHeadersList(request->response_headers()));
1126 args.Append(dict);
1128 DispatchEvent(browser_context, request, listeners, args);
1131 void ExtensionWebRequestEventRouter::OnErrorOccurred(
1132 void* browser_context,
1133 InfoMap* extension_info_map,
1134 net::URLRequest* request,
1135 bool started) {
1136 // We hide events from the system context as well as sensitive requests.
1137 // However, if the request first became sensitive after redirecting we have
1138 // already signaled it and thus we have to signal the end of it. This is
1139 // risk-free because the handler cannot modify the request now.
1140 if (!browser_context ||
1141 (WebRequestPermissions::HideRequest(extension_info_map, request) &&
1142 !WasSignaled(*request)))
1143 return;
1145 request_time_tracker_->LogRequestEndTime(request->identifier(),
1146 base::Time::Now());
1148 DCHECK(request->status().status() == net::URLRequestStatus::FAILED ||
1149 request->status().status() == net::URLRequestStatus::CANCELED);
1151 DCHECK(!GetAndSetSignaled(request->identifier(), kOnErrorOccurred));
1153 ClearPendingCallbacks(request);
1155 int extra_info_spec = 0;
1156 std::vector<const EventListener*> listeners =
1157 GetMatchingListeners(browser_context, extension_info_map,
1158 web_request::OnErrorOccurred::kEventName, request,
1159 &extra_info_spec);
1160 if (listeners.empty())
1161 return;
1163 base::ListValue args;
1164 base::DictionaryValue* dict = new base::DictionaryValue();
1165 ExtractRequestInfo(request, dict);
1166 if (started) {
1167 std::string response_ip = request->GetSocketAddress().host();
1168 if (!response_ip.empty())
1169 dict->SetString(keys::kIpKey, response_ip);
1171 dict->SetBoolean(keys::kFromCache, request->was_cached());
1172 dict->SetString(keys::kErrorKey,
1173 net::ErrorToString(request->status().error()));
1174 args.Append(dict);
1176 DispatchEvent(browser_context, request, listeners, args);
1179 void ExtensionWebRequestEventRouter::OnURLRequestDestroyed(
1180 void* browser_context, net::URLRequest* request) {
1181 ClearPendingCallbacks(request);
1183 signaled_requests_.erase(request->identifier());
1185 request_time_tracker_->LogRequestEndTime(request->identifier(),
1186 base::Time::Now());
1189 void ExtensionWebRequestEventRouter::ClearPendingCallbacks(
1190 net::URLRequest* request) {
1191 blocked_requests_.erase(request->identifier());
1194 bool ExtensionWebRequestEventRouter::DispatchEvent(
1195 void* browser_context,
1196 net::URLRequest* request,
1197 const std::vector<const EventListener*>& listeners,
1198 const base::ListValue& args) {
1199 // TODO(mpcomplete): Consider consolidating common (extension_id,json_args)
1200 // pairs into a single message sent to a list of sub_event_names.
1201 int num_handlers_blocking = 0;
1202 for (std::vector<const EventListener*>::const_iterator it = listeners.begin();
1203 it != listeners.end(); ++it) {
1204 // Filter out the optional keys that this listener didn't request.
1205 scoped_ptr<base::ListValue> args_filtered(args.DeepCopy());
1206 base::DictionaryValue* dict = NULL;
1207 CHECK(args_filtered->GetDictionary(0, &dict) && dict);
1208 if (!((*it)->extra_info_spec & ExtraInfoSpec::REQUEST_HEADERS))
1209 dict->Remove(keys::kRequestHeadersKey, NULL);
1210 if (!((*it)->extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS))
1211 dict->Remove(keys::kResponseHeadersKey, NULL);
1213 extensions::EventRouter::DispatchEvent(
1214 (*it)->ipc_sender.get(), browser_context,
1215 (*it)->extension_id, (*it)->sub_event_name,
1216 args_filtered.Pass(),
1217 extensions::EventRouter::USER_GESTURE_UNKNOWN,
1218 extensions::EventFilteringInfo());
1219 if ((*it)->extra_info_spec &
1220 (ExtraInfoSpec::BLOCKING | ExtraInfoSpec::ASYNC_BLOCKING)) {
1221 (*it)->blocked_requests.insert(request->identifier());
1222 // If this is the first delegate blocking the request, go ahead and log
1223 // it.
1224 if (num_handlers_blocking == 0) {
1225 std::string delegate_info =
1226 l10n_util::GetStringFUTF8(IDS_LOAD_STATE_PARAMETER_EXTENSION,
1227 base::UTF8ToUTF16((*it)->extension_name));
1228 // LobAndReport allows extensions that block requests to be displayed in
1229 // the load status bar.
1230 request->LogAndReportBlockedBy(delegate_info.c_str());
1232 ++num_handlers_blocking;
1236 if (num_handlers_blocking > 0) {
1237 blocked_requests_[request->identifier()].request = request;
1238 blocked_requests_[request->identifier()].is_incognito |=
1239 IsIncognitoBrowserContext(browser_context);
1240 blocked_requests_[request->identifier()].num_handlers_blocking +=
1241 num_handlers_blocking;
1242 blocked_requests_[request->identifier()].blocking_time = base::Time::Now();
1244 return true;
1247 return false;
1250 void ExtensionWebRequestEventRouter::OnEventHandled(
1251 void* browser_context,
1252 const std::string& extension_id,
1253 const std::string& event_name,
1254 const std::string& sub_event_name,
1255 uint64 request_id,
1256 EventResponse* response) {
1257 EventListener listener;
1258 listener.extension_id = extension_id;
1259 listener.sub_event_name = sub_event_name;
1261 // The listener may have been removed (e.g. due to the process going away)
1262 // before we got here.
1263 std::set<EventListener>::iterator found =
1264 listeners_[browser_context][event_name].find(listener);
1265 if (found != listeners_[browser_context][event_name].end())
1266 found->blocked_requests.erase(request_id);
1268 DecrementBlockCount(
1269 browser_context, extension_id, event_name, request_id, response);
1272 bool ExtensionWebRequestEventRouter::AddEventListener(
1273 void* browser_context,
1274 const std::string& extension_id,
1275 const std::string& extension_name,
1276 const std::string& event_name,
1277 const std::string& sub_event_name,
1278 const RequestFilter& filter,
1279 int extra_info_spec,
1280 int embedder_process_id,
1281 int web_view_instance_id,
1282 base::WeakPtr<IPC::Sender> ipc_sender) {
1283 if (!IsWebRequestEvent(event_name))
1284 return false;
1286 EventListener listener;
1287 listener.extension_id = extension_id;
1288 listener.extension_name = extension_name;
1289 listener.sub_event_name = sub_event_name;
1290 listener.filter = filter;
1291 listener.extra_info_spec = extra_info_spec;
1292 listener.ipc_sender = ipc_sender;
1293 listener.embedder_process_id = embedder_process_id;
1294 listener.web_view_instance_id = web_view_instance_id;
1295 if (listener.web_view_instance_id) {
1296 content::RecordAction(
1297 base::UserMetricsAction("WebView.WebRequest.AddListener"));
1300 if (listeners_[browser_context][event_name].count(listener) != 0u) {
1301 // This is likely an abuse of the API by a malicious extension.
1302 return false;
1304 listeners_[browser_context][event_name].insert(listener);
1305 return true;
1308 void ExtensionWebRequestEventRouter::RemoveEventListener(
1309 void* browser_context,
1310 const std::string& extension_id,
1311 const std::string& sub_event_name,
1312 int embedder_process_id,
1313 int web_view_instance_id) {
1314 std::string event_name =
1315 extensions::EventRouter::GetBaseEventName(sub_event_name);
1316 DCHECK(IsWebRequestEvent(event_name));
1318 EventListener listener;
1319 listener.extension_id = extension_id;
1320 listener.sub_event_name = sub_event_name;
1321 listener.embedder_process_id = embedder_process_id;
1322 listener.web_view_instance_id = web_view_instance_id;
1324 std::set<EventListener>& event_listeners =
1325 listeners_[browser_context][event_name];
1326 // It's possible for AddEventListener to fail asynchronously. In that case,
1327 // the renderer believes the listener exists, while the browser does not.
1328 // Ignore a RemoveEventListener in that case.
1329 std::set<EventListener>::iterator found = event_listeners.find(listener);
1330 if (found == event_listeners.end())
1331 return;
1333 CHECK_EQ(event_listeners.count(listener), 1u) <<
1334 "extension=" << extension_id << " event=" << event_name;
1336 // Unblock any request that this event listener may have been blocking.
1337 for (std::set<uint64>::iterator it = found->blocked_requests.begin();
1338 it != found->blocked_requests.end(); ++it) {
1339 DecrementBlockCount(browser_context, extension_id, event_name, *it, NULL);
1342 event_listeners.erase(listener);
1344 helpers::ClearCacheOnNavigation();
1347 void ExtensionWebRequestEventRouter::RemoveWebViewEventListeners(
1348 void* browser_context,
1349 const std::string& extension_id,
1350 int embedder_process_id,
1351 int web_view_instance_id) {
1352 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1354 // Iterate over all listeners of all WebRequest events to delete
1355 // any listeners that belong to the provided <webview>.
1356 ListenerMapForBrowserContext& map_for_browser_context =
1357 listeners_[browser_context];
1358 for (const auto& event_iter : map_for_browser_context) {
1359 // Construct a listeners_to_delete vector so that we don't modify the set of
1360 // listeners as we iterate through it.
1361 std::vector<EventListener> listeners_to_delete;
1362 const std::set<EventListener>& listeners = event_iter.second;
1363 for (const auto& listener : listeners) {
1364 if (listener.embedder_process_id == embedder_process_id &&
1365 listener.web_view_instance_id == web_view_instance_id) {
1366 listeners_to_delete.push_back(listener);
1369 // Remove the listeners selected for deletion.
1370 for (const auto& listener : listeners_to_delete) {
1371 RemoveEventListenerOnIOThread(
1372 browser_context,
1373 extension_id,
1374 listener.sub_event_name,
1375 listener.embedder_process_id,
1376 listener.web_view_instance_id);
1381 void ExtensionWebRequestEventRouter::OnOTRBrowserContextCreated(
1382 void* original_browser_context, void* otr_browser_context) {
1383 cross_browser_context_map_[original_browser_context] =
1384 std::make_pair(false, otr_browser_context);
1385 cross_browser_context_map_[otr_browser_context] =
1386 std::make_pair(true, original_browser_context);
1389 void ExtensionWebRequestEventRouter::OnOTRBrowserContextDestroyed(
1390 void* original_browser_context, void* otr_browser_context) {
1391 cross_browser_context_map_.erase(otr_browser_context);
1392 cross_browser_context_map_.erase(original_browser_context);
1395 void ExtensionWebRequestEventRouter::AddCallbackForPageLoad(
1396 const base::Closure& callback) {
1397 callbacks_for_page_load_.push_back(callback);
1400 bool ExtensionWebRequestEventRouter::IsPageLoad(
1401 net::URLRequest* request) const {
1402 bool is_main_frame = false;
1403 int frame_id = -1;
1404 bool parent_is_main_frame = false;
1405 int parent_frame_id = -1;
1406 int render_process_host_id = -1;
1407 int routing_id = -1;
1408 ResourceType resource_type = content::RESOURCE_TYPE_LAST_TYPE;
1410 ExtractRequestInfoDetails(request, &is_main_frame, &frame_id,
1411 &parent_is_main_frame, &parent_frame_id,
1412 &render_process_host_id,
1413 &routing_id, &resource_type);
1415 return resource_type == content::RESOURCE_TYPE_MAIN_FRAME;
1418 void ExtensionWebRequestEventRouter::NotifyPageLoad() {
1419 for (CallbacksForPageLoad::const_iterator i =
1420 callbacks_for_page_load_.begin();
1421 i != callbacks_for_page_load_.end(); ++i) {
1422 i->Run();
1424 callbacks_for_page_load_.clear();
1427 void* ExtensionWebRequestEventRouter::GetCrossBrowserContext(
1428 void* browser_context) const {
1429 CrossBrowserContextMap::const_iterator cross_browser_context =
1430 cross_browser_context_map_.find(browser_context);
1431 if (cross_browser_context == cross_browser_context_map_.end())
1432 return NULL;
1433 return cross_browser_context->second.second;
1436 bool ExtensionWebRequestEventRouter::IsIncognitoBrowserContext(
1437 void* browser_context) const {
1438 CrossBrowserContextMap::const_iterator cross_browser_context =
1439 cross_browser_context_map_.find(browser_context);
1440 if (cross_browser_context == cross_browser_context_map_.end())
1441 return false;
1442 return cross_browser_context->second.first;
1445 bool ExtensionWebRequestEventRouter::WasSignaled(
1446 const net::URLRequest& request) const {
1447 SignaledRequestMap::const_iterator flag =
1448 signaled_requests_.find(request.identifier());
1449 return (flag != signaled_requests_.end()) && (flag->second != 0);
1452 void ExtensionWebRequestEventRouter::GetMatchingListenersImpl(
1453 void* browser_context,
1454 net::URLRequest* request,
1455 InfoMap* extension_info_map,
1456 bool crosses_incognito,
1457 const std::string& event_name,
1458 const GURL& url,
1459 int render_process_host_id,
1460 int routing_id,
1461 ResourceType resource_type,
1462 bool is_async_request,
1463 bool is_request_from_extension,
1464 int* extra_info_spec,
1465 std::vector<const ExtensionWebRequestEventRouter::EventListener*>*
1466 matching_listeners) {
1467 std::string web_request_event_name(event_name);
1468 extensions::WebViewRendererState::WebViewInfo web_view_info;
1469 bool is_web_view_guest = extensions::WebViewRendererState::GetInstance()->
1470 GetInfo(render_process_host_id, routing_id, &web_view_info);
1471 if (is_web_view_guest) {
1472 web_request_event_name.replace(
1473 0, sizeof(kWebRequestEventPrefix) - 1, webview::kWebViewEventPrefix);
1476 std::set<EventListener>& listeners =
1477 listeners_[browser_context][web_request_event_name];
1478 for (std::set<EventListener>::iterator it = listeners.begin();
1479 it != listeners.end(); ++it) {
1480 if (!it->ipc_sender.get()) {
1481 // The IPC sender has been deleted. This listener will be removed soon
1482 // via a call to RemoveEventListener. For now, just skip it.
1483 continue;
1486 if (is_web_view_guest &&
1487 (it->embedder_process_id != web_view_info.embedder_process_id ||
1488 it->web_view_instance_id != web_view_info.instance_id))
1489 continue;
1491 if (!it->filter.urls.is_empty() && !it->filter.urls.MatchesURL(url))
1492 continue;
1493 if (web_request_event_router_delegate_ &&
1494 web_request_event_router_delegate_->OnGetMatchingListenersImplCheck(
1495 it->filter.tab_id, it->filter.window_id, request))
1496 continue;
1497 if (!it->filter.types.empty() &&
1498 std::find(it->filter.types.begin(), it->filter.types.end(),
1499 resource_type) == it->filter.types.end())
1500 continue;
1502 if (!is_web_view_guest && !WebRequestPermissions::CanExtensionAccessURL(
1503 extension_info_map, it->extension_id, url, crosses_incognito,
1504 WebRequestPermissions::REQUIRE_HOST_PERMISSION))
1505 continue;
1507 bool blocking_listener =
1508 (it->extra_info_spec &
1509 (ExtraInfoSpec::BLOCKING | ExtraInfoSpec::ASYNC_BLOCKING)) != 0;
1511 // We do not want to notify extensions about XHR requests that are
1512 // triggered by themselves. This is a workaround to prevent deadlocks
1513 // in case of synchronous XHR requests that block the extension renderer
1514 // and therefore prevent the extension from processing the request
1515 // handler. This is only a problem for blocking listeners.
1516 // http://crbug.com/105656
1517 bool synchronous_xhr_from_extension =
1518 !is_async_request && is_request_from_extension &&
1519 resource_type == content::RESOURCE_TYPE_XHR;
1521 // Only send webRequest events for URLs the extension has access to.
1522 if (blocking_listener && synchronous_xhr_from_extension)
1523 continue;
1525 matching_listeners->push_back(&(*it));
1526 *extra_info_spec |= it->extra_info_spec;
1530 std::vector<const ExtensionWebRequestEventRouter::EventListener*>
1531 ExtensionWebRequestEventRouter::GetMatchingListeners(
1532 void* browser_context,
1533 InfoMap* extension_info_map,
1534 const std::string& event_name,
1535 net::URLRequest* request,
1536 int* extra_info_spec) {
1537 // TODO(mpcomplete): handle browser_context == NULL (should collect all
1538 // listeners).
1539 *extra_info_spec = 0;
1541 bool is_main_frame = false;
1542 int frame_id = -1;
1543 bool parent_is_main_frame = false;
1544 int parent_frame_id = -1;
1545 int render_process_host_id = -1;
1546 int routing_id = -1;
1547 ResourceType resource_type = content::RESOURCE_TYPE_LAST_TYPE;
1548 const GURL& url = request->url();
1550 ExtractRequestInfoDetails(request, &is_main_frame, &frame_id,
1551 &parent_is_main_frame, &parent_frame_id,
1552 &render_process_host_id,
1553 &routing_id, &resource_type);
1555 std::vector<const ExtensionWebRequestEventRouter::EventListener*>
1556 matching_listeners;
1558 bool is_request_from_extension =
1559 IsRequestFromExtension(request, extension_info_map);
1561 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
1562 // We are conservative here and assume requests are asynchronous in case
1563 // we don't have an info object. We don't want to risk a deadlock.
1564 bool is_async_request = !info || info->IsAsync();
1566 GetMatchingListenersImpl(
1567 browser_context, request, extension_info_map, false, event_name,
1568 url, render_process_host_id, routing_id, resource_type,
1569 is_async_request, is_request_from_extension, extra_info_spec,
1570 &matching_listeners);
1571 void* cross_browser_context = GetCrossBrowserContext(browser_context);
1572 if (cross_browser_context) {
1573 GetMatchingListenersImpl(
1574 cross_browser_context, request, extension_info_map, true, event_name,
1575 url, render_process_host_id, routing_id, resource_type,
1576 is_async_request, is_request_from_extension, extra_info_spec,
1577 &matching_listeners);
1580 return matching_listeners;
1583 namespace {
1585 helpers::EventResponseDelta* CalculateDelta(
1586 ExtensionWebRequestEventRouter::BlockedRequest* blocked_request,
1587 ExtensionWebRequestEventRouter::EventResponse* response) {
1588 switch (blocked_request->event) {
1589 case ExtensionWebRequestEventRouter::kOnBeforeRequest:
1590 return helpers::CalculateOnBeforeRequestDelta(
1591 response->extension_id, response->extension_install_time,
1592 response->cancel, response->new_url);
1593 case ExtensionWebRequestEventRouter::kOnBeforeSendHeaders: {
1594 net::HttpRequestHeaders* old_headers = blocked_request->request_headers;
1595 net::HttpRequestHeaders* new_headers = response->request_headers.get();
1596 return helpers::CalculateOnBeforeSendHeadersDelta(
1597 response->extension_id, response->extension_install_time,
1598 response->cancel, old_headers, new_headers);
1600 case ExtensionWebRequestEventRouter::kOnHeadersReceived: {
1601 const net::HttpResponseHeaders* old_headers =
1602 blocked_request->original_response_headers.get();
1603 helpers::ResponseHeaders* new_headers =
1604 response->response_headers.get();
1605 return helpers::CalculateOnHeadersReceivedDelta(
1606 response->extension_id,
1607 response->extension_install_time,
1608 response->cancel,
1609 response->new_url,
1610 old_headers,
1611 new_headers);
1613 case ExtensionWebRequestEventRouter::kOnAuthRequired:
1614 return helpers::CalculateOnAuthRequiredDelta(
1615 response->extension_id, response->extension_install_time,
1616 response->cancel, &response->auth_credentials);
1617 default:
1618 NOTREACHED();
1619 break;
1621 return NULL;
1624 base::Value* SerializeResponseHeaders(const helpers::ResponseHeaders& headers) {
1625 scoped_ptr<base::ListValue> serialized_headers(new base::ListValue());
1626 for (helpers::ResponseHeaders::const_iterator i = headers.begin();
1627 i != headers.end(); ++i) {
1628 serialized_headers->Append(
1629 helpers::CreateHeaderDictionary(i->first, i->second));
1631 return serialized_headers.release();
1634 // Convert a RequestCookieModifications/ResponseCookieModifications object to a
1635 // base::ListValue which summarizes the changes made. This is templated since
1636 // the two types (request/response) are different but contain essentially the
1637 // same fields.
1638 template<typename CookieType>
1639 base::ListValue* SummarizeCookieModifications(
1640 const std::vector<linked_ptr<CookieType> >& modifications) {
1641 scoped_ptr<base::ListValue> cookie_modifications(new base::ListValue());
1642 for (typename std::vector<linked_ptr<CookieType> >::const_iterator i =
1643 modifications.begin();
1644 i != modifications.end(); ++i) {
1645 scoped_ptr<base::DictionaryValue> summary(new base::DictionaryValue());
1646 const CookieType& mod = *i->get();
1647 switch (mod.type) {
1648 case helpers::ADD:
1649 summary->SetString(activitylog::kCookieModificationTypeKey,
1650 activitylog::kCookieModificationAdd);
1651 break;
1652 case helpers::EDIT:
1653 summary->SetString(activitylog::kCookieModificationTypeKey,
1654 activitylog::kCookieModificationEdit);
1655 break;
1656 case helpers::REMOVE:
1657 summary->SetString(activitylog::kCookieModificationTypeKey,
1658 activitylog::kCookieModificationRemove);
1659 break;
1661 if (mod.filter) {
1662 if (mod.filter->name)
1663 summary->SetString(activitylog::kCookieFilterNameKey,
1664 *mod.modification->name);
1665 if (mod.filter->domain)
1666 summary->SetString(activitylog::kCookieFilterDomainKey,
1667 *mod.modification->name);
1669 if (mod.modification) {
1670 if (mod.modification->name)
1671 summary->SetString(activitylog::kCookieModDomainKey,
1672 *mod.modification->name);
1673 if (mod.modification->domain)
1674 summary->SetString(activitylog::kCookieModDomainKey,
1675 *mod.modification->name);
1677 cookie_modifications->Append(summary.release());
1679 return cookie_modifications.release();
1682 // Converts an EventResponseDelta object to a dictionary value suitable for the
1683 // activity log.
1684 scoped_ptr<base::DictionaryValue> SummarizeResponseDelta(
1685 const std::string& event_name,
1686 const helpers::EventResponseDelta& delta) {
1687 scoped_ptr<base::DictionaryValue> details(new base::DictionaryValue());
1688 if (delta.cancel) {
1689 details->SetBoolean(activitylog::kCancelKey, true);
1691 if (!delta.new_url.is_empty()) {
1692 details->SetString(activitylog::kNewUrlKey, delta.new_url.spec());
1695 scoped_ptr<base::ListValue> modified_headers(new base::ListValue());
1696 net::HttpRequestHeaders::Iterator iter(delta.modified_request_headers);
1697 while (iter.GetNext()) {
1698 modified_headers->Append(
1699 helpers::CreateHeaderDictionary(iter.name(), iter.value()));
1701 if (!modified_headers->empty()) {
1702 details->Set(activitylog::kModifiedRequestHeadersKey,
1703 modified_headers.release());
1706 scoped_ptr<base::ListValue> deleted_headers(new base::ListValue());
1707 deleted_headers->AppendStrings(delta.deleted_request_headers);
1708 if (!deleted_headers->empty()) {
1709 details->Set(activitylog::kDeletedRequestHeadersKey,
1710 deleted_headers.release());
1713 if (!delta.added_response_headers.empty()) {
1714 details->Set(activitylog::kAddedRequestHeadersKey,
1715 SerializeResponseHeaders(delta.added_response_headers));
1717 if (!delta.deleted_response_headers.empty()) {
1718 details->Set(activitylog::kDeletedResponseHeadersKey,
1719 SerializeResponseHeaders(delta.deleted_response_headers));
1721 if (delta.auth_credentials) {
1722 details->SetString(activitylog::kAuthCredentialsKey,
1723 base::UTF16ToUTF8(
1724 delta.auth_credentials->username()) + ":*");
1727 if (!delta.response_cookie_modifications.empty()) {
1728 details->Set(
1729 activitylog::kResponseCookieModificationsKey,
1730 SummarizeCookieModifications(delta.response_cookie_modifications));
1733 return details.Pass();
1736 } // namespace
1738 void ExtensionWebRequestEventRouter::LogExtensionActivity(
1739 void* browser_context_id,
1740 bool is_incognito,
1741 const std::string& extension_id,
1742 const GURL& url,
1743 const std::string& api_call,
1744 scoped_ptr<base::DictionaryValue> details) {
1745 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
1746 BrowserThread::PostTask(
1747 BrowserThread::UI,
1748 FROM_HERE,
1749 base::Bind(&ExtensionWebRequestEventRouter::LogExtensionActivity,
1750 base::Unretained(this),
1751 browser_context_id,
1752 is_incognito,
1753 extension_id,
1754 url,
1755 api_call,
1756 base::Passed(&details)));
1757 } else {
1758 if (web_request_event_router_delegate_) {
1759 web_request_event_router_delegate_->LogExtensionActivity(
1760 reinterpret_cast<content::BrowserContext*>(browser_context_id),
1761 is_incognito, extension_id, url, api_call, details.Pass());
1766 void ExtensionWebRequestEventRouter::DecrementBlockCount(
1767 void* browser_context,
1768 const std::string& extension_id,
1769 const std::string& event_name,
1770 uint64 request_id,
1771 EventResponse* response) {
1772 scoped_ptr<EventResponse> response_scoped(response);
1774 // It's possible that this request was deleted, or cancelled by a previous
1775 // event handler. If so, ignore this response.
1776 if (blocked_requests_.find(request_id) == blocked_requests_.end())
1777 return;
1779 BlockedRequest& blocked_request = blocked_requests_[request_id];
1780 int num_handlers_blocking = --blocked_request.num_handlers_blocking;
1781 CHECK_GE(num_handlers_blocking, 0);
1783 if (response) {
1784 helpers::EventResponseDelta* delta =
1785 CalculateDelta(&blocked_request, response);
1787 LogExtensionActivity(browser_context,
1788 blocked_request.is_incognito,
1789 extension_id,
1790 blocked_request.request->url(),
1791 event_name,
1792 SummarizeResponseDelta(event_name, *delta));
1794 blocked_request.response_deltas.push_back(
1795 linked_ptr<helpers::EventResponseDelta>(delta));
1798 base::TimeDelta block_time =
1799 base::Time::Now() - blocked_request.blocking_time;
1800 if (!extension_id.empty()) {
1801 request_time_tracker_->IncrementExtensionBlockTime(
1802 extension_id, request_id, block_time);
1803 } else {
1804 // |extension_id| is empty for requests blocked on startup waiting for the
1805 // declarative rules to be read from disk.
1806 UMA_HISTOGRAM_TIMES("Extensions.NetworkDelayStartup", block_time);
1809 if (num_handlers_blocking == 0) {
1810 blocked_request.request->LogUnblocked();
1811 ExecuteDeltas(browser_context, request_id, true);
1812 } else {
1813 // Update the URLRequest to make sure it's tagged with an extension that's
1814 // still blocking it. This may end up being the same extension as before.
1815 std::set<EventListener>& listeners =
1816 listeners_[browser_context][event_name];
1818 for (std::set<EventListener>::iterator it = listeners.begin();
1819 it != listeners.end(); ++it) {
1820 if (it->blocked_requests.count(request_id) == 0)
1821 continue;
1822 std::string delegate_info =
1823 l10n_util::GetStringFUTF8(IDS_LOAD_STATE_PARAMETER_EXTENSION,
1824 base::UTF8ToUTF16(it->extension_name));
1825 blocked_request.request->LogAndReportBlockedBy(delegate_info.c_str());
1826 break;
1831 void ExtensionWebRequestEventRouter::SendMessages(
1832 void* browser_context,
1833 const BlockedRequest& blocked_request) {
1834 const helpers::EventResponseDeltas& deltas = blocked_request.response_deltas;
1835 for (helpers::EventResponseDeltas::const_iterator delta = deltas.begin();
1836 delta != deltas.end(); ++delta) {
1837 const std::set<std::string>& messages = (*delta)->messages_to_extension;
1838 for (std::set<std::string>::const_iterator message = messages.begin();
1839 message != messages.end(); ++message) {
1840 scoped_ptr<base::DictionaryValue> argument(new base::DictionaryValue);
1841 ExtractRequestInfo(blocked_request.request, argument.get());
1842 extensions::WebViewRendererState::WebViewInfo web_view_info;
1843 bool is_web_view_guest = GetWebViewInfo(blocked_request.request,
1844 &web_view_info);
1845 argument->SetString(keys::kMessageKey, *message);
1846 argument->SetString(keys::kStageKey,
1847 GetRequestStageAsString(blocked_request.event));
1849 BrowserThread::PostTask(
1850 BrowserThread::UI,
1851 FROM_HERE,
1852 base::Bind(&SendOnMessageEventOnUI,
1853 browser_context,
1854 (*delta)->extension_id,
1855 is_web_view_guest,
1856 web_view_info,
1857 base::Passed(&argument)));
1862 int ExtensionWebRequestEventRouter::ExecuteDeltas(
1863 void* browser_context,
1864 uint64 request_id,
1865 bool call_callback) {
1866 BlockedRequest& blocked_request = blocked_requests_[request_id];
1867 CHECK(blocked_request.num_handlers_blocking == 0);
1868 helpers::EventResponseDeltas& deltas = blocked_request.response_deltas;
1869 base::TimeDelta block_time =
1870 base::Time::Now() - blocked_request.blocking_time;
1871 request_time_tracker_->IncrementTotalBlockTime(request_id, block_time);
1873 bool credentials_set = false;
1875 deltas.sort(&helpers::InDecreasingExtensionInstallationTimeOrder);
1876 WarningSet warnings;
1878 bool canceled = false;
1879 helpers::MergeCancelOfResponses(
1880 blocked_request.response_deltas,
1881 &canceled,
1882 blocked_request.net_log);
1884 if (blocked_request.event == kOnBeforeRequest) {
1885 CHECK(!blocked_request.callback.is_null());
1886 helpers::MergeOnBeforeRequestResponses(
1887 blocked_request.response_deltas,
1888 blocked_request.new_url,
1889 &warnings,
1890 blocked_request.net_log);
1891 } else if (blocked_request.event == kOnBeforeSendHeaders) {
1892 CHECK(!blocked_request.callback.is_null());
1893 helpers::MergeOnBeforeSendHeadersResponses(
1894 blocked_request.response_deltas,
1895 blocked_request.request_headers,
1896 &warnings,
1897 blocked_request.net_log);
1898 } else if (blocked_request.event == kOnHeadersReceived) {
1899 CHECK(!blocked_request.callback.is_null());
1900 helpers::MergeOnHeadersReceivedResponses(
1901 blocked_request.response_deltas,
1902 blocked_request.original_response_headers.get(),
1903 blocked_request.override_response_headers,
1904 blocked_request.new_url,
1905 &warnings,
1906 blocked_request.net_log);
1907 } else if (blocked_request.event == kOnAuthRequired) {
1908 CHECK(blocked_request.callback.is_null());
1909 CHECK(!blocked_request.auth_callback.is_null());
1910 credentials_set = helpers::MergeOnAuthRequiredResponses(
1911 blocked_request.response_deltas,
1912 blocked_request.auth_credentials,
1913 &warnings,
1914 blocked_request.net_log);
1915 } else {
1916 NOTREACHED();
1919 SendMessages(browser_context, blocked_request);
1921 if (!warnings.empty()) {
1922 BrowserThread::PostTask(
1923 BrowserThread::UI,
1924 FROM_HERE,
1925 base::Bind(&WarningService::NotifyWarningsOnUI,
1926 browser_context, warnings));
1929 if (canceled) {
1930 request_time_tracker_->SetRequestCanceled(request_id);
1931 } else if (blocked_request.new_url &&
1932 !blocked_request.new_url->is_empty()) {
1933 request_time_tracker_->SetRequestRedirected(request_id);
1936 // This triggers onErrorOccurred if canceled is true.
1937 int rv = canceled ? net::ERR_BLOCKED_BY_CLIENT : net::OK;
1939 if (!blocked_request.callback.is_null()) {
1940 net::CompletionCallback callback = blocked_request.callback;
1941 // Ensure that request is removed before callback because the callback
1942 // might trigger the next event.
1943 blocked_requests_.erase(request_id);
1944 if (call_callback)
1945 callback.Run(rv);
1946 } else if (!blocked_request.auth_callback.is_null()) {
1947 net::NetworkDelegate::AuthRequiredResponse response =
1948 net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION;
1949 if (canceled) {
1950 response = net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_CANCEL_AUTH;
1951 } else if (credentials_set) {
1952 response = net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_SET_AUTH;
1954 net::NetworkDelegate::AuthCallback callback = blocked_request.auth_callback;
1955 blocked_requests_.erase(request_id);
1956 if (call_callback)
1957 callback.Run(response);
1958 } else {
1959 blocked_requests_.erase(request_id);
1961 return rv;
1964 bool ExtensionWebRequestEventRouter::ProcessDeclarativeRules(
1965 void* browser_context,
1966 InfoMap* extension_info_map,
1967 const std::string& event_name,
1968 net::URLRequest* request,
1969 extensions::RequestStage request_stage,
1970 const net::HttpResponseHeaders* original_response_headers) {
1971 extensions::WebViewRendererState::WebViewInfo web_view_info;
1972 bool is_web_view_guest = GetWebViewInfo(request, &web_view_info);
1973 int rules_registry_id = is_web_view_guest
1974 ? web_view_info.rules_registry_id
1975 : RulesRegistryService::kDefaultRulesRegistryID;
1977 RulesRegistryKey rules_key(browser_context, rules_registry_id);
1978 // If this check fails, check that the active stages are up-to-date in
1979 // extensions/browser/api/declarative_webrequest/request_stage.h .
1980 DCHECK(request_stage & extensions::kActiveStages);
1982 // Rules of the current |browser_context| may apply but we need to check also
1983 // whether there are applicable rules from extensions whose background page
1984 // spans from regular to incognito mode.
1986 // First parameter identifies the registry, the second indicates whether the
1987 // registry belongs to the cross browser_context.
1988 typedef std::pair<extensions::WebRequestRulesRegistry*, bool>
1989 RelevantRegistry;
1990 typedef std::vector<RelevantRegistry> RelevantRegistries;
1991 RelevantRegistries relevant_registries;
1993 if (rules_registries_.find(rules_key) != rules_registries_.end()) {
1994 relevant_registries.push_back(
1995 std::make_pair(rules_registries_[rules_key].get(), false));
1998 void* cross_browser_context = GetCrossBrowserContext(browser_context);
1999 RulesRegistryKey cross_browser_context_rules_key(cross_browser_context,
2000 rules_registry_id);
2001 if (cross_browser_context &&
2002 rules_registries_.find(cross_browser_context_rules_key) !=
2003 rules_registries_.end()) {
2004 relevant_registries.push_back(
2005 std::make_pair(
2006 rules_registries_[cross_browser_context_rules_key].get(), true));
2009 // The following block is experimentally enabled and its impact on load time
2010 // logged with UMA Extensions.NetworkDelayRegistryLoad. crbug.com/175961
2011 for (RelevantRegistries::iterator i = relevant_registries.begin();
2012 i != relevant_registries.end(); ++i) {
2013 extensions::WebRequestRulesRegistry* rules_registry = i->first;
2014 if (!rules_registry->ready().is_signaled()) {
2015 // The rules registry is still loading. Block this request until it
2016 // finishes.
2017 rules_registry->ready().Post(
2018 FROM_HERE,
2019 base::Bind(&ExtensionWebRequestEventRouter::OnRulesRegistryReady,
2020 AsWeakPtr(),
2021 browser_context,
2022 event_name,
2023 request->identifier(),
2024 request_stage));
2025 blocked_requests_[request->identifier()].num_handlers_blocking++;
2026 blocked_requests_[request->identifier()].request = request;
2027 blocked_requests_[request->identifier()].is_incognito |=
2028 IsIncognitoBrowserContext(browser_context);
2029 blocked_requests_[request->identifier()].blocking_time =
2030 base::Time::Now();
2031 blocked_requests_[request->identifier()].original_response_headers =
2032 original_response_headers;
2033 blocked_requests_[request->identifier()].extension_info_map =
2034 extension_info_map;
2035 return true;
2039 base::Time start = base::Time::Now();
2041 bool deltas_created = false;
2042 for (RelevantRegistries::iterator i = relevant_registries.begin();
2043 i != relevant_registries.end(); ++i) {
2044 extensions::WebRequestRulesRegistry* rules_registry =
2045 i->first;
2046 helpers::EventResponseDeltas result =
2047 rules_registry->CreateDeltas(
2048 extension_info_map,
2049 extensions::WebRequestData(
2050 request, request_stage, original_response_headers),
2051 i->second);
2053 if (!result.empty()) {
2054 helpers::EventResponseDeltas& deltas =
2055 blocked_requests_[request->identifier()].response_deltas;
2056 deltas.insert(deltas.end(), result.begin(), result.end());
2057 deltas_created = true;
2061 base::TimeDelta elapsed_time = start - base::Time::Now();
2062 UMA_HISTOGRAM_TIMES("Extensions.DeclarativeWebRequestNetworkDelay",
2063 elapsed_time);
2065 return deltas_created;
2068 void ExtensionWebRequestEventRouter::OnRulesRegistryReady(
2069 void* browser_context,
2070 const std::string& event_name,
2071 uint64 request_id,
2072 extensions::RequestStage request_stage) {
2073 // It's possible that this request was deleted, or cancelled by a previous
2074 // event handler. If so, ignore this response.
2075 if (blocked_requests_.find(request_id) == blocked_requests_.end())
2076 return;
2078 BlockedRequest& blocked_request = blocked_requests_[request_id];
2079 base::TimeDelta block_time =
2080 base::Time::Now() - blocked_request.blocking_time;
2081 UMA_HISTOGRAM_TIMES("Extensions.NetworkDelayRegistryLoad", block_time);
2083 ProcessDeclarativeRules(browser_context,
2084 blocked_request.extension_info_map,
2085 event_name,
2086 blocked_request.request,
2087 request_stage,
2088 blocked_request.original_response_headers.get());
2089 // Reset to NULL so that nobody relies on this being set.
2090 blocked_request.extension_info_map = NULL;
2091 DecrementBlockCount(
2092 browser_context, std::string(), event_name, request_id, NULL);
2095 bool ExtensionWebRequestEventRouter::GetAndSetSignaled(uint64 request_id,
2096 EventTypes event_type) {
2097 SignaledRequestMap::iterator iter = signaled_requests_.find(request_id);
2098 if (iter == signaled_requests_.end()) {
2099 signaled_requests_[request_id] = event_type;
2100 return false;
2102 bool was_signaled_before = (iter->second & event_type) != 0;
2103 iter->second |= event_type;
2104 return was_signaled_before;
2107 void ExtensionWebRequestEventRouter::ClearSignaled(uint64 request_id,
2108 EventTypes event_type) {
2109 SignaledRequestMap::iterator iter = signaled_requests_.find(request_id);
2110 if (iter == signaled_requests_.end())
2111 return;
2112 iter->second &= ~event_type;
2115 // Special QuotaLimitHeuristic for WebRequestHandlerBehaviorChangedFunction.
2117 // Each call of webRequest.handlerBehaviorChanged() clears the in-memory cache
2118 // of WebKit at the time of the next page load (top level navigation event).
2119 // This quota heuristic is intended to limit the number of times the cache is
2120 // cleared by an extension.
2122 // As we want to account for the number of times the cache is really cleared
2123 // (opposed to the number of times webRequest.handlerBehaviorChanged() is
2124 // called), we cannot decide whether a call of
2125 // webRequest.handlerBehaviorChanged() should trigger a quota violation at the
2126 // time it is called. Instead we only decrement the bucket counter at the time
2127 // when the cache is cleared (when page loads happen).
2128 class ClearCacheQuotaHeuristic : public extensions::QuotaLimitHeuristic {
2129 public:
2130 ClearCacheQuotaHeuristic(const Config& config, BucketMapper* map)
2131 : QuotaLimitHeuristic(
2132 config,
2133 map,
2134 "MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES"),
2135 callback_registered_(false),
2136 weak_ptr_factory_(this) {}
2137 ~ClearCacheQuotaHeuristic() override {}
2138 bool Apply(Bucket* bucket, const base::TimeTicks& event_time) override;
2140 private:
2141 // Callback that is triggered by the ExtensionWebRequestEventRouter on a page
2142 // load.
2144 // We don't need to take care of the life time of |bucket|: It is owned by the
2145 // BucketMapper of our base class in |QuotaLimitHeuristic::bucket_mapper_|. As
2146 // long as |this| exists, the respective BucketMapper and its bucket will
2147 // exist as well.
2148 void OnPageLoad(Bucket* bucket);
2150 // Flag to prevent that we register more than one call back in-between
2151 // clearing the cache.
2152 bool callback_registered_;
2154 base::WeakPtrFactory<ClearCacheQuotaHeuristic> weak_ptr_factory_;
2156 DISALLOW_COPY_AND_ASSIGN(ClearCacheQuotaHeuristic);
2159 bool ClearCacheQuotaHeuristic::Apply(Bucket* bucket,
2160 const base::TimeTicks& event_time) {
2161 if (event_time > bucket->expiration())
2162 bucket->Reset(config(), event_time);
2164 // Call bucket->DeductToken() on a new page load, this is when
2165 // webRequest.handlerBehaviorChanged() clears the cache.
2166 if (!callback_registered_) {
2167 ExtensionWebRequestEventRouter::GetInstance()->AddCallbackForPageLoad(
2168 base::Bind(&ClearCacheQuotaHeuristic::OnPageLoad,
2169 weak_ptr_factory_.GetWeakPtr(),
2170 bucket));
2171 callback_registered_ = true;
2174 // We only check whether tokens are left here. Deducting a token happens in
2175 // OnPageLoad().
2176 return bucket->has_tokens();
2179 void ClearCacheQuotaHeuristic::OnPageLoad(Bucket* bucket) {
2180 callback_registered_ = false;
2181 bucket->DeductToken();
2184 bool WebRequestInternalAddEventListenerFunction::RunSync() {
2185 // Argument 0 is the callback, which we don't use here.
2186 ExtensionWebRequestEventRouter::RequestFilter filter;
2187 base::DictionaryValue* value = NULL;
2188 error_.clear();
2189 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &value));
2190 // Failure + an empty error string means a fatal error.
2191 EXTENSION_FUNCTION_VALIDATE(filter.InitFromValue(*value, &error_) ||
2192 !error_.empty());
2193 if (!error_.empty())
2194 return false;
2196 int extra_info_spec = 0;
2197 if (HasOptionalArgument(2)) {
2198 base::ListValue* value = NULL;
2199 EXTENSION_FUNCTION_VALIDATE(args_->GetList(2, &value));
2200 EXTENSION_FUNCTION_VALIDATE(
2201 ExtensionWebRequestEventRouter::ExtraInfoSpec::InitFromValue(
2202 *value, &extra_info_spec));
2205 std::string event_name;
2206 EXTENSION_FUNCTION_VALIDATE(args_->GetString(3, &event_name));
2208 std::string sub_event_name;
2209 EXTENSION_FUNCTION_VALIDATE(args_->GetString(4, &sub_event_name));
2211 int web_view_instance_id = 0;
2212 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(5, &web_view_instance_id));
2214 base::WeakPtr<extensions::IOThreadExtensionMessageFilter> ipc_sender =
2215 ipc_sender_weak();
2216 int embedder_process_id =
2217 ipc_sender.get() && web_view_instance_id > 0 ?
2218 ipc_sender->render_process_id() : 0;
2220 const Extension* extension =
2221 extension_info_map()->extensions().GetByID(extension_id_safe());
2222 std::string extension_name =
2223 extension ? extension->name() : extension_id_safe();
2225 if (!web_view_instance_id) {
2226 // We check automatically whether the extension has the 'webRequest'
2227 // permission. For blocking calls we require the additional permission
2228 // 'webRequestBlocking'.
2229 if ((extra_info_spec &
2230 (ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING |
2231 ExtensionWebRequestEventRouter::ExtraInfoSpec::ASYNC_BLOCKING)) &&
2232 !extension->permissions_data()->HasAPIPermission(
2233 extensions::APIPermission::kWebRequestBlocking)) {
2234 error_ = keys::kBlockingPermissionRequired;
2235 return false;
2238 // We allow to subscribe to patterns that are broader than the host
2239 // permissions. E.g., we could subscribe to http://www.example.com/*
2240 // while having host permissions for http://www.example.com/foo/* and
2241 // http://www.example.com/bar/*.
2242 // For this reason we do only a coarse check here to warn the extension
2243 // developer if he does something obviously wrong.
2244 if (extension->permissions_data()
2245 ->GetEffectiveHostPermissions()
2246 .is_empty()) {
2247 error_ = keys::kHostPermissionsRequired;
2248 return false;
2252 bool success =
2253 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
2254 profile_id(), extension_id_safe(), extension_name,
2255 event_name, sub_event_name, filter, extra_info_spec,
2256 embedder_process_id, web_view_instance_id, ipc_sender_weak());
2257 EXTENSION_FUNCTION_VALIDATE(success);
2259 helpers::ClearCacheOnNavigation();
2261 if (!extension_id_safe().empty()) {
2262 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
2263 base::Bind(&helpers::NotifyWebRequestAPIUsed,
2264 profile_id(), extension_id_safe()));
2267 return true;
2270 void WebRequestInternalEventHandledFunction::RespondWithError(
2271 const std::string& event_name,
2272 const std::string& sub_event_name,
2273 uint64 request_id,
2274 scoped_ptr<ExtensionWebRequestEventRouter::EventResponse> response,
2275 const std::string& error) {
2276 error_ = error;
2277 ExtensionWebRequestEventRouter::GetInstance()->OnEventHandled(
2278 profile_id(),
2279 extension_id_safe(),
2280 event_name,
2281 sub_event_name,
2282 request_id,
2283 response.release());
2286 bool WebRequestInternalEventHandledFunction::RunSync() {
2287 std::string event_name;
2288 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &event_name));
2290 std::string sub_event_name;
2291 EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &sub_event_name));
2293 std::string request_id_str;
2294 EXTENSION_FUNCTION_VALIDATE(args_->GetString(2, &request_id_str));
2295 uint64 request_id;
2296 EXTENSION_FUNCTION_VALIDATE(base::StringToUint64(request_id_str,
2297 &request_id));
2299 scoped_ptr<ExtensionWebRequestEventRouter::EventResponse> response;
2300 if (HasOptionalArgument(3)) {
2301 base::DictionaryValue* value = NULL;
2302 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(3, &value));
2304 if (!value->empty()) {
2305 base::Time install_time =
2306 extension_info_map()->GetInstallTime(extension_id_safe());
2307 response.reset(new ExtensionWebRequestEventRouter::EventResponse(
2308 extension_id_safe(), install_time));
2311 if (value->HasKey("cancel")) {
2312 // Don't allow cancel mixed with other keys.
2313 if (value->size() != 1) {
2314 RespondWithError(event_name,
2315 sub_event_name,
2316 request_id,
2317 response.Pass(),
2318 keys::kInvalidBlockingResponse);
2319 return false;
2322 bool cancel = false;
2323 EXTENSION_FUNCTION_VALIDATE(value->GetBoolean("cancel", &cancel));
2324 response->cancel = cancel;
2327 if (value->HasKey("redirectUrl")) {
2328 std::string new_url_str;
2329 EXTENSION_FUNCTION_VALIDATE(value->GetString("redirectUrl",
2330 &new_url_str));
2331 response->new_url = GURL(new_url_str);
2332 if (!response->new_url.is_valid()) {
2333 RespondWithError(event_name,
2334 sub_event_name,
2335 request_id,
2336 response.Pass(),
2337 ErrorUtils::FormatErrorMessage(
2338 keys::kInvalidRedirectUrl, new_url_str));
2339 return false;
2343 const bool hasRequestHeaders = value->HasKey("requestHeaders");
2344 const bool hasResponseHeaders = value->HasKey("responseHeaders");
2345 if (hasRequestHeaders || hasResponseHeaders) {
2346 if (hasRequestHeaders && hasResponseHeaders) {
2347 // Allow only one of the keys, not both.
2348 RespondWithError(event_name,
2349 sub_event_name,
2350 request_id,
2351 response.Pass(),
2352 keys::kInvalidHeaderKeyCombination);
2353 return false;
2356 base::ListValue* headers_value = NULL;
2357 scoped_ptr<net::HttpRequestHeaders> request_headers;
2358 scoped_ptr<helpers::ResponseHeaders> response_headers;
2359 if (hasRequestHeaders) {
2360 request_headers.reset(new net::HttpRequestHeaders());
2361 EXTENSION_FUNCTION_VALIDATE(value->GetList(keys::kRequestHeadersKey,
2362 &headers_value));
2363 } else {
2364 response_headers.reset(new helpers::ResponseHeaders());
2365 EXTENSION_FUNCTION_VALIDATE(value->GetList(keys::kResponseHeadersKey,
2366 &headers_value));
2369 for (size_t i = 0; i < headers_value->GetSize(); ++i) {
2370 base::DictionaryValue* header_value = NULL;
2371 std::string name;
2372 std::string value;
2373 EXTENSION_FUNCTION_VALIDATE(
2374 headers_value->GetDictionary(i, &header_value));
2375 if (!FromHeaderDictionary(header_value, &name, &value)) {
2376 std::string serialized_header;
2377 base::JSONWriter::Write(*header_value, &serialized_header);
2378 RespondWithError(event_name,
2379 sub_event_name,
2380 request_id,
2381 response.Pass(),
2382 ErrorUtils::FormatErrorMessage(keys::kInvalidHeader,
2383 serialized_header));
2384 return false;
2386 if (!net::HttpUtil::IsValidHeaderName(name)) {
2387 RespondWithError(event_name,
2388 sub_event_name,
2389 request_id,
2390 response.Pass(),
2391 keys::kInvalidHeaderName);
2392 return false;
2394 if (!net::HttpUtil::IsValidHeaderValue(value)) {
2395 RespondWithError(event_name,
2396 sub_event_name,
2397 request_id,
2398 response.Pass(),
2399 ErrorUtils::FormatErrorMessage(
2400 keys::kInvalidHeaderValue, name));
2401 return false;
2403 if (hasRequestHeaders)
2404 request_headers->SetHeader(name, value);
2405 else
2406 response_headers->push_back(helpers::ResponseHeader(name, value));
2408 if (hasRequestHeaders)
2409 response->request_headers.reset(request_headers.release());
2410 else
2411 response->response_headers.reset(response_headers.release());
2414 if (value->HasKey(keys::kAuthCredentialsKey)) {
2415 base::DictionaryValue* credentials_value = NULL;
2416 EXTENSION_FUNCTION_VALIDATE(value->GetDictionary(
2417 keys::kAuthCredentialsKey,
2418 &credentials_value));
2419 base::string16 username;
2420 base::string16 password;
2421 EXTENSION_FUNCTION_VALIDATE(
2422 credentials_value->GetString(keys::kUsernameKey, &username));
2423 EXTENSION_FUNCTION_VALIDATE(
2424 credentials_value->GetString(keys::kPasswordKey, &password));
2425 response->auth_credentials.reset(
2426 new net::AuthCredentials(username, password));
2430 ExtensionWebRequestEventRouter::GetInstance()->OnEventHandled(
2431 profile_id(), extension_id_safe(), event_name, sub_event_name, request_id,
2432 response.release());
2434 return true;
2437 void WebRequestHandlerBehaviorChangedFunction::GetQuotaLimitHeuristics(
2438 extensions::QuotaLimitHeuristics* heuristics) const {
2439 extensions::QuotaLimitHeuristic::Config config = {
2440 // See web_request.json for current value.
2441 web_request::MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES,
2442 base::TimeDelta::FromMinutes(10)};
2443 extensions::QuotaLimitHeuristic::BucketMapper* bucket_mapper =
2444 new extensions::QuotaLimitHeuristic::SingletonBucketMapper();
2445 ClearCacheQuotaHeuristic* heuristic =
2446 new ClearCacheQuotaHeuristic(config, bucket_mapper);
2447 heuristics->push_back(heuristic);
2450 void WebRequestHandlerBehaviorChangedFunction::OnQuotaExceeded(
2451 const std::string& violation_error) {
2452 // Post warning message.
2453 WarningSet warnings;
2454 warnings.insert(
2455 Warning::CreateRepeatedCacheFlushesWarning(extension_id_safe()));
2456 BrowserThread::PostTask(
2457 BrowserThread::UI,
2458 FROM_HERE,
2459 base::Bind(&WarningService::NotifyWarningsOnUI, profile_id(), warnings));
2461 // Continue gracefully.
2462 RunSync();
2465 bool WebRequestHandlerBehaviorChangedFunction::RunSync() {
2466 helpers::ClearCacheOnNavigation();
2467 return true;