Update {virtual,override,final} to follow C++11 style.
[chromium-blink-merge.git] / extensions / browser / api / web_request / web_request_api.cc
blob87da356ebce5602f6072deb5f7d75d62d8983b65
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_message_filter.h"
38 #include "extensions/browser/extension_prefs.h"
39 #include "extensions/browser/extension_registry.h"
40 #include "extensions/browser/extension_system.h"
41 #include "extensions/browser/extensions_browser_client.h"
42 #include "extensions/browser/guest_view/web_view/web_view_constants.h"
43 #include "extensions/browser/guest_view/web_view/web_view_renderer_state.h"
44 #include "extensions/browser/info_map.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 void RemoveEventListenerOnUI(
321 void* browser_context_id,
322 const std::string& event_name,
323 int process_id,
324 const std::string& extension_id) {
325 DCHECK_CURRENTLY_ON(BrowserThread::UI);
327 content::BrowserContext* browser_context =
328 reinterpret_cast<content::BrowserContext*>(browser_context_id);
329 if (!extensions::ExtensionsBrowserClient::Get()->IsValidContext(
330 browser_context))
331 return;
333 extensions::EventRouter* event_router =
334 extensions::EventRouter::Get(browser_context);
335 if (!event_router)
336 return;
338 content::RenderProcessHost* process =
339 content::RenderProcessHost::FromID(process_id);
340 if (!process)
341 return;
343 event_router->RemoveEventListener(event_name, process, extension_id);
346 // Sends an event to subscribers of chrome.declarativeWebRequest.onMessage or
347 // to subscribers of webview.onMessage if the action is being operated upon
348 // a <webview> guest renderer.
349 // |extension_id| identifies the extension that sends and receives the event.
350 // |is_web_view_guest| indicates whether the action is for a <webview>.
351 // |web_view_info| is a struct containing information about the <webview>
352 // embedder.
353 // |event_argument| is passed to the event listener.
354 void SendOnMessageEventOnUI(
355 void* browser_context_id,
356 const std::string& extension_id,
357 bool is_web_view_guest,
358 const extensions::WebViewRendererState::WebViewInfo& web_view_info,
359 scoped_ptr<base::DictionaryValue> event_argument) {
360 DCHECK_CURRENTLY_ON(BrowserThread::UI);
362 content::BrowserContext* browser_context =
363 reinterpret_cast<content::BrowserContext*>(browser_context_id);
364 if (!extensions::ExtensionsBrowserClient::Get()->IsValidContext(
365 browser_context))
366 return;
368 scoped_ptr<base::ListValue> event_args(new base::ListValue);
369 event_args->Append(event_argument.release());
371 extensions::EventRouter* event_router =
372 extensions::EventRouter::Get(browser_context);
374 extensions::EventFilteringInfo event_filtering_info;
376 std::string event_name;
377 // The instance ID uniquely identifies a <webview> instance within an embedder
378 // process. We use a filter here so that only event listeners for a particular
379 // <webview> will fire.
380 if (is_web_view_guest) {
381 event_filtering_info.SetInstanceID(web_view_info.instance_id);
382 event_name = webview::kEventMessage;
383 } else {
384 event_name = declarative_keys::kOnMessage;
387 scoped_ptr<extensions::Event> event(new extensions::Event(
388 event_name,
389 event_args.Pass(), browser_context, GURL(),
390 extensions::EventRouter::USER_GESTURE_UNKNOWN,
391 event_filtering_info));
392 event_router->DispatchEventToExtension(extension_id, event.Pass());
395 void RemoveEventListenerOnIOThread(
396 content::BrowserContext* browser_context,
397 const std::string& extension_id,
398 const std::string& sub_event_name) {
399 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(
400 browser_context, extension_id, sub_event_name);
403 } // namespace
405 namespace extensions {
407 WebRequestAPI::WebRequestAPI(content::BrowserContext* context)
408 : browser_context_(context) {
409 EventRouter* event_router = EventRouter::Get(browser_context_);
410 for (size_t i = 0; i < arraysize(kWebRequestEvents); ++i) {
411 // Observe the webRequest event.
412 std::string event_name = kWebRequestEvents[i];
413 event_router->RegisterObserver(this, event_name);
415 // Also observe the corresponding webview event.
416 event_name.replace(
417 0, sizeof(kWebRequestEventPrefix) - 1, webview::kWebViewEventPrefix);
418 event_router->RegisterObserver(this, event_name);
422 WebRequestAPI::~WebRequestAPI() {
423 EventRouter::Get(browser_context_)->UnregisterObserver(this);
426 static base::LazyInstance<BrowserContextKeyedAPIFactory<WebRequestAPI> >
427 g_factory = LAZY_INSTANCE_INITIALIZER;
429 // static
430 BrowserContextKeyedAPIFactory<WebRequestAPI>*
431 WebRequestAPI::GetFactoryInstance() {
432 return g_factory.Pointer();
435 void WebRequestAPI::OnListenerRemoved(const EventListenerInfo& details) {
436 DCHECK_CURRENTLY_ON(BrowserThread::UI);
437 // Note that details.event_name includes the sub-event details (e.g. "/123").
438 BrowserThread::PostTask(BrowserThread::IO,
439 FROM_HERE,
440 base::Bind(&RemoveEventListenerOnIOThread,
441 details.browser_context,
442 details.extension_id,
443 details.event_name));
446 } // namespace extensions
448 // Represents a single unique listener to an event, along with whatever filter
449 // parameters and extra_info_spec were specified at the time the listener was
450 // added.
451 // NOTE(benjhayden) New APIs should not use this sub_event_name trick! It does
452 // not play well with event pages. See downloads.onDeterminingFilename and
453 // ExtensionDownloadsEventRouter for an alternative approach.
454 struct ExtensionWebRequestEventRouter::EventListener {
455 std::string extension_id;
456 std::string extension_name;
457 std::string sub_event_name;
458 RequestFilter filter;
459 int extra_info_spec;
460 int embedder_process_id;
461 int web_view_instance_id;
462 base::WeakPtr<IPC::Sender> ipc_sender;
463 mutable std::set<uint64> blocked_requests;
465 // Comparator to work with std::set.
466 bool operator<(const EventListener& that) const {
467 if (extension_id != that.extension_id)
468 return extension_id < that.extension_id;
470 if (sub_event_name != that.sub_event_name)
471 return sub_event_name < that.sub_event_name;
473 if (embedder_process_id != that.embedder_process_id)
474 return embedder_process_id < that.embedder_process_id;
476 if (web_view_instance_id != that.web_view_instance_id)
477 return web_view_instance_id < that.web_view_instance_id;
479 return false;
482 EventListener() :
483 extra_info_spec(0),
484 embedder_process_id(0),
485 web_view_instance_id(0) {}
488 // Contains info about requests that are blocked waiting for a response from
489 // an extension.
490 struct ExtensionWebRequestEventRouter::BlockedRequest {
491 // The request that is being blocked.
492 net::URLRequest* request;
494 // Whether the request originates from an incognito tab.
495 bool is_incognito;
497 // The event that we're currently blocked on.
498 EventTypes event;
500 // The number of event handlers that we are awaiting a response from.
501 int num_handlers_blocking;
503 // Pointer to NetLog to report significant changes to the request for
504 // debugging.
505 const net::BoundNetLog* net_log;
507 // The callback to call when we get a response from all event handlers.
508 net::CompletionCallback callback;
510 // If non-empty, this contains the new URL that the request will redirect to.
511 // Only valid for OnBeforeRequest and OnHeadersReceived.
512 GURL* new_url;
514 // The request headers that will be issued along with this request. Only valid
515 // for OnBeforeSendHeaders.
516 net::HttpRequestHeaders* request_headers;
518 // The response headers that were received from the server. Only valid for
519 // OnHeadersReceived.
520 scoped_refptr<const net::HttpResponseHeaders> original_response_headers;
522 // Location where to override response headers. Only valid for
523 // OnHeadersReceived.
524 scoped_refptr<net::HttpResponseHeaders>* override_response_headers;
526 // If non-empty, this contains the auth credentials that may be filled in.
527 // Only valid for OnAuthRequired.
528 net::AuthCredentials* auth_credentials;
530 // The callback to invoke for auth. If |auth_callback.is_null()| is false,
531 // |callback| must be NULL.
532 // Only valid for OnAuthRequired.
533 net::NetworkDelegate::AuthCallback auth_callback;
535 // Time the request was paused. Used for logging purposes.
536 base::Time blocking_time;
538 // Changes requested by extensions.
539 helpers::EventResponseDeltas response_deltas;
541 // Provider of meta data about extensions, only used and non-NULL for events
542 // that are delayed until the rules registry is ready.
543 InfoMap* extension_info_map;
545 BlockedRequest()
546 : request(NULL),
547 is_incognito(false),
548 event(kInvalidEvent),
549 num_handlers_blocking(0),
550 net_log(NULL),
551 new_url(NULL),
552 request_headers(NULL),
553 override_response_headers(NULL),
554 auth_credentials(NULL),
555 extension_info_map(NULL) {}
558 bool ExtensionWebRequestEventRouter::RequestFilter::InitFromValue(
559 const base::DictionaryValue& value, std::string* error) {
560 if (!value.HasKey("urls"))
561 return false;
563 for (base::DictionaryValue::Iterator it(value); !it.IsAtEnd(); it.Advance()) {
564 if (it.key() == "urls") {
565 const base::ListValue* urls_value = NULL;
566 if (!it.value().GetAsList(&urls_value))
567 return false;
568 for (size_t i = 0; i < urls_value->GetSize(); ++i) {
569 std::string url;
570 URLPattern pattern(
571 URLPattern::SCHEME_HTTP | URLPattern::SCHEME_HTTPS |
572 URLPattern::SCHEME_FTP | URLPattern::SCHEME_FILE |
573 URLPattern::SCHEME_EXTENSION);
574 if (!urls_value->GetString(i, &url) ||
575 pattern.Parse(url) != URLPattern::PARSE_SUCCESS) {
576 *error = ErrorUtils::FormatErrorMessage(
577 keys::kInvalidRequestFilterUrl, url);
578 return false;
580 urls.AddPattern(pattern);
582 } else if (it.key() == "types") {
583 const base::ListValue* types_value = NULL;
584 if (!it.value().GetAsList(&types_value))
585 return false;
586 for (size_t i = 0; i < types_value->GetSize(); ++i) {
587 std::string type_str;
588 ResourceType type;
589 if (!types_value->GetString(i, &type_str) ||
590 !helpers::ParseResourceType(type_str, &type))
591 return false;
592 types.push_back(type);
594 } else if (it.key() == "tabId") {
595 if (!it.value().GetAsInteger(&tab_id))
596 return false;
597 } else if (it.key() == "windowId") {
598 if (!it.value().GetAsInteger(&window_id))
599 return false;
600 } else {
601 return false;
604 return true;
607 // static
608 bool ExtensionWebRequestEventRouter::ExtraInfoSpec::InitFromValue(
609 const base::ListValue& value, int* extra_info_spec) {
610 *extra_info_spec = 0;
611 for (size_t i = 0; i < value.GetSize(); ++i) {
612 std::string str;
613 if (!value.GetString(i, &str))
614 return false;
616 if (str == "requestHeaders")
617 *extra_info_spec |= REQUEST_HEADERS;
618 else if (str == "responseHeaders")
619 *extra_info_spec |= RESPONSE_HEADERS;
620 else if (str == "blocking")
621 *extra_info_spec |= BLOCKING;
622 else if (str == "asyncBlocking")
623 *extra_info_spec |= ASYNC_BLOCKING;
624 else if (str == "requestBody")
625 *extra_info_spec |= REQUEST_BODY;
626 else
627 return false;
629 // BLOCKING and ASYNC_BLOCKING are mutually exclusive.
630 if ((*extra_info_spec & BLOCKING) && (*extra_info_spec & ASYNC_BLOCKING))
631 return false;
633 return true;
637 ExtensionWebRequestEventRouter::EventResponse::EventResponse(
638 const std::string& extension_id, const base::Time& extension_install_time)
639 : extension_id(extension_id),
640 extension_install_time(extension_install_time),
641 cancel(false) {
644 ExtensionWebRequestEventRouter::EventResponse::~EventResponse() {
647 ExtensionWebRequestEventRouter::RequestFilter::RequestFilter()
648 : tab_id(-1), window_id(-1) {
651 ExtensionWebRequestEventRouter::RequestFilter::~RequestFilter() {
655 // ExtensionWebRequestEventRouter
658 // static
659 ExtensionWebRequestEventRouter* ExtensionWebRequestEventRouter::GetInstance() {
660 return Singleton<ExtensionWebRequestEventRouter>::get();
663 ExtensionWebRequestEventRouter::ExtensionWebRequestEventRouter()
664 : request_time_tracker_(new ExtensionWebRequestTimeTracker) {
665 web_request_event_router_delegate_.reset(
666 extensions::ExtensionsAPIClient::Get()->
667 CreateWebRequestEventRouterDelegate());
670 ExtensionWebRequestEventRouter::~ExtensionWebRequestEventRouter() {
673 void ExtensionWebRequestEventRouter::RegisterRulesRegistry(
674 void* browser_context,
675 int rules_registry_id,
676 scoped_refptr<extensions::WebRequestRulesRegistry> rules_registry) {
677 RulesRegistryKey key(browser_context, rules_registry_id);
678 if (rules_registry.get())
679 rules_registries_[key] = rules_registry;
680 else
681 rules_registries_.erase(key);
684 void ExtensionWebRequestEventRouter::ExtractRequestInfo(
685 net::URLRequest* request, base::DictionaryValue* out) {
686 bool is_main_frame = false;
687 int frame_id = -1;
688 bool parent_is_main_frame = false;
689 int parent_frame_id = -1;
690 int frame_id_for_extension = -1;
691 int parent_frame_id_for_extension = -1;
692 int render_process_host_id = -1;
693 int routing_id = -1;
694 ResourceType resource_type = content::RESOURCE_TYPE_LAST_TYPE;
695 ExtractRequestInfoDetails(request, &is_main_frame, &frame_id,
696 &parent_is_main_frame, &parent_frame_id,
697 &render_process_host_id, &routing_id,
698 &resource_type);
699 frame_id_for_extension = GetFrameId(is_main_frame, frame_id);
700 parent_frame_id_for_extension = GetFrameId(parent_is_main_frame,
701 parent_frame_id);
703 out->SetString(keys::kRequestIdKey,
704 base::Uint64ToString(request->identifier()));
705 out->SetString(keys::kUrlKey, request->url().spec());
706 out->SetString(keys::kMethodKey, request->method());
707 out->SetInteger(keys::kFrameIdKey, frame_id_for_extension);
708 out->SetInteger(keys::kParentFrameIdKey, parent_frame_id_for_extension);
709 out->SetString(keys::kTypeKey, helpers::ResourceTypeToString(resource_type));
710 out->SetDouble(keys::kTimeStampKey, base::Time::Now().ToDoubleT() * 1000);
711 if (web_request_event_router_delegate_) {
712 web_request_event_router_delegate_->ExtractExtraRequestDetails(
713 request, out);
717 int ExtensionWebRequestEventRouter::OnBeforeRequest(
718 void* browser_context,
719 InfoMap* extension_info_map,
720 net::URLRequest* request,
721 const net::CompletionCallback& callback,
722 GURL* new_url) {
723 // We hide events from the system context as well as sensitive requests.
724 if (!browser_context ||
725 WebRequestPermissions::HideRequest(extension_info_map, request))
726 return net::OK;
728 if (IsPageLoad(request))
729 NotifyPageLoad();
731 request_time_tracker_->LogRequestStartTime(request->identifier(),
732 base::Time::Now(),
733 request->url(),
734 browser_context);
736 // Whether to initialized blocked_requests_.
737 bool initialize_blocked_requests = false;
739 initialize_blocked_requests |=
740 ProcessDeclarativeRules(browser_context, extension_info_map,
741 web_request::OnBeforeRequest::kEventName, request,
742 extensions::ON_BEFORE_REQUEST, NULL);
744 int extra_info_spec = 0;
745 std::vector<const EventListener*> listeners =
746 GetMatchingListeners(browser_context, extension_info_map,
747 web_request::OnBeforeRequest::kEventName, request,
748 &extra_info_spec);
749 if (!listeners.empty() &&
750 !GetAndSetSignaled(request->identifier(), kOnBeforeRequest)) {
751 base::ListValue args;
752 base::DictionaryValue* dict = new base::DictionaryValue();
753 ExtractRequestInfo(request, dict);
754 if (extra_info_spec & ExtraInfoSpec::REQUEST_BODY)
755 ExtractRequestInfoBody(request, dict);
756 args.Append(dict);
758 initialize_blocked_requests |=
759 DispatchEvent(browser_context, request, listeners, args);
762 if (!initialize_blocked_requests)
763 return net::OK; // Nobody saw a reason for modifying the request.
765 blocked_requests_[request->identifier()].event = kOnBeforeRequest;
766 blocked_requests_[request->identifier()].is_incognito |=
767 IsIncognitoBrowserContext(browser_context);
768 blocked_requests_[request->identifier()].request = request;
769 blocked_requests_[request->identifier()].callback = callback;
770 blocked_requests_[request->identifier()].new_url = new_url;
771 blocked_requests_[request->identifier()].net_log = &request->net_log();
773 if (blocked_requests_[request->identifier()].num_handlers_blocking == 0) {
774 // If there are no blocking handlers, only the declarative rules tried
775 // to modify the request and we can respond synchronously.
776 return ExecuteDeltas(browser_context, request->identifier(),
777 false /* call_callback*/);
778 } else {
779 return net::ERR_IO_PENDING;
783 int ExtensionWebRequestEventRouter::OnBeforeSendHeaders(
784 void* browser_context,
785 InfoMap* extension_info_map,
786 net::URLRequest* request,
787 const net::CompletionCallback& callback,
788 net::HttpRequestHeaders* headers) {
789 // We hide events from the system context as well as sensitive requests.
790 if (!browser_context ||
791 WebRequestPermissions::HideRequest(extension_info_map, request))
792 return net::OK;
794 bool initialize_blocked_requests = false;
796 initialize_blocked_requests |=
797 ProcessDeclarativeRules(browser_context, extension_info_map,
798 keys::kOnBeforeSendHeadersEvent, request,
799 extensions::ON_BEFORE_SEND_HEADERS, NULL);
801 int extra_info_spec = 0;
802 std::vector<const EventListener*> listeners =
803 GetMatchingListeners(browser_context, extension_info_map,
804 keys::kOnBeforeSendHeadersEvent, request,
805 &extra_info_spec);
806 if (!listeners.empty() &&
807 !GetAndSetSignaled(request->identifier(), kOnBeforeSendHeaders)) {
808 base::ListValue args;
809 base::DictionaryValue* dict = new base::DictionaryValue();
810 ExtractRequestInfo(request, dict);
811 if (extra_info_spec & ExtraInfoSpec::REQUEST_HEADERS)
812 dict->Set(keys::kRequestHeadersKey, GetRequestHeadersList(*headers));
813 args.Append(dict);
815 initialize_blocked_requests |=
816 DispatchEvent(browser_context, request, listeners, args);
819 if (!initialize_blocked_requests)
820 return net::OK; // Nobody saw a reason for modifying the request.
822 blocked_requests_[request->identifier()].event = kOnBeforeSendHeaders;
823 blocked_requests_[request->identifier()].is_incognito |=
824 IsIncognitoBrowserContext(browser_context);
825 blocked_requests_[request->identifier()].request = request;
826 blocked_requests_[request->identifier()].callback = callback;
827 blocked_requests_[request->identifier()].request_headers = headers;
828 blocked_requests_[request->identifier()].net_log = &request->net_log();
830 if (blocked_requests_[request->identifier()].num_handlers_blocking == 0) {
831 // If there are no blocking handlers, only the declarative rules tried
832 // to modify the request and we can respond synchronously.
833 return ExecuteDeltas(browser_context, request->identifier(),
834 false /* call_callback*/);
835 } else {
836 return net::ERR_IO_PENDING;
840 void ExtensionWebRequestEventRouter::OnSendHeaders(
841 void* browser_context,
842 InfoMap* extension_info_map,
843 net::URLRequest* request,
844 const net::HttpRequestHeaders& headers) {
845 // We hide events from the system context as well as sensitive requests.
846 if (!browser_context ||
847 WebRequestPermissions::HideRequest(extension_info_map, request))
848 return;
850 if (GetAndSetSignaled(request->identifier(), kOnSendHeaders))
851 return;
853 ClearSignaled(request->identifier(), kOnBeforeRedirect);
855 int extra_info_spec = 0;
856 std::vector<const EventListener*> listeners =
857 GetMatchingListeners(browser_context, extension_info_map,
858 keys::kOnSendHeadersEvent, request,
859 &extra_info_spec);
860 if (listeners.empty())
861 return;
863 base::ListValue args;
864 base::DictionaryValue* dict = new base::DictionaryValue();
865 ExtractRequestInfo(request, dict);
866 if (extra_info_spec & ExtraInfoSpec::REQUEST_HEADERS)
867 dict->Set(keys::kRequestHeadersKey, GetRequestHeadersList(headers));
868 args.Append(dict);
870 DispatchEvent(browser_context, request, listeners, args);
873 int ExtensionWebRequestEventRouter::OnHeadersReceived(
874 void* browser_context,
875 InfoMap* extension_info_map,
876 net::URLRequest* request,
877 const net::CompletionCallback& callback,
878 const net::HttpResponseHeaders* original_response_headers,
879 scoped_refptr<net::HttpResponseHeaders>* override_response_headers,
880 GURL* allowed_unsafe_redirect_url) {
881 // We hide events from the system context as well as sensitive requests.
882 if (!browser_context ||
883 WebRequestPermissions::HideRequest(extension_info_map, request))
884 return net::OK;
886 bool initialize_blocked_requests = false;
888 initialize_blocked_requests |=
889 ProcessDeclarativeRules(browser_context, extension_info_map,
890 keys::kOnHeadersReceivedEvent, request,
891 extensions::ON_HEADERS_RECEIVED,
892 original_response_headers);
894 int extra_info_spec = 0;
895 std::vector<const EventListener*> listeners =
896 GetMatchingListeners(browser_context, extension_info_map,
897 keys::kOnHeadersReceivedEvent, request,
898 &extra_info_spec);
900 if (!listeners.empty() &&
901 !GetAndSetSignaled(request->identifier(), kOnHeadersReceived)) {
902 base::ListValue args;
903 base::DictionaryValue* dict = new base::DictionaryValue();
904 ExtractRequestInfo(request, dict);
905 dict->SetString(keys::kStatusLineKey,
906 original_response_headers->GetStatusLine());
907 if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
908 dict->Set(keys::kResponseHeadersKey,
909 GetResponseHeadersList(original_response_headers));
911 args.Append(dict);
913 initialize_blocked_requests |=
914 DispatchEvent(browser_context, request, listeners, args);
917 if (!initialize_blocked_requests)
918 return net::OK; // Nobody saw a reason for modifying the request.
920 blocked_requests_[request->identifier()].event = kOnHeadersReceived;
921 blocked_requests_[request->identifier()].is_incognito |=
922 IsIncognitoBrowserContext(browser_context);
923 blocked_requests_[request->identifier()].request = request;
924 blocked_requests_[request->identifier()].callback = callback;
925 blocked_requests_[request->identifier()].net_log = &request->net_log();
926 blocked_requests_[request->identifier()].override_response_headers =
927 override_response_headers;
928 blocked_requests_[request->identifier()].original_response_headers =
929 original_response_headers;
930 blocked_requests_[request->identifier()].new_url =
931 allowed_unsafe_redirect_url;
933 if (blocked_requests_[request->identifier()].num_handlers_blocking == 0) {
934 // If there are no blocking handlers, only the declarative rules tried
935 // to modify the request and we can respond synchronously.
936 return ExecuteDeltas(browser_context, request->identifier(),
937 false /* call_callback*/);
938 } else {
939 return net::ERR_IO_PENDING;
943 net::NetworkDelegate::AuthRequiredResponse
944 ExtensionWebRequestEventRouter::OnAuthRequired(
945 void* browser_context,
946 InfoMap* extension_info_map,
947 net::URLRequest* request,
948 const net::AuthChallengeInfo& auth_info,
949 const net::NetworkDelegate::AuthCallback& callback,
950 net::AuthCredentials* credentials) {
951 // No browser_context means that this is for authentication challenges in the
952 // system context. Skip in that case. Also skip sensitive requests.
953 if (!browser_context ||
954 WebRequestPermissions::HideRequest(extension_info_map, request))
955 return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION;
957 int extra_info_spec = 0;
958 std::vector<const EventListener*> listeners =
959 GetMatchingListeners(browser_context, extension_info_map,
960 keys::kOnAuthRequiredEvent, request,
961 &extra_info_spec);
962 if (listeners.empty())
963 return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION;
965 base::ListValue args;
966 base::DictionaryValue* dict = new base::DictionaryValue();
967 ExtractRequestInfo(request, dict);
968 dict->SetBoolean(keys::kIsProxyKey, auth_info.is_proxy);
969 if (!auth_info.scheme.empty())
970 dict->SetString(keys::kSchemeKey, auth_info.scheme);
971 if (!auth_info.realm.empty())
972 dict->SetString(keys::kRealmKey, auth_info.realm);
973 base::DictionaryValue* challenger = new base::DictionaryValue();
974 challenger->SetString(keys::kHostKey, auth_info.challenger.host());
975 challenger->SetInteger(keys::kPortKey, auth_info.challenger.port());
976 dict->Set(keys::kChallengerKey, challenger);
977 dict->Set(keys::kStatusLineKey, GetStatusLine(request->response_headers()));
978 if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
979 dict->Set(keys::kResponseHeadersKey,
980 GetResponseHeadersList(request->response_headers()));
982 args.Append(dict);
984 if (DispatchEvent(browser_context, request, listeners, args)) {
985 blocked_requests_[request->identifier()].event = kOnAuthRequired;
986 blocked_requests_[request->identifier()].is_incognito |=
987 IsIncognitoBrowserContext(browser_context);
988 blocked_requests_[request->identifier()].request = request;
989 blocked_requests_[request->identifier()].auth_callback = callback;
990 blocked_requests_[request->identifier()].auth_credentials = credentials;
991 blocked_requests_[request->identifier()].net_log = &request->net_log();
992 return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_IO_PENDING;
994 return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION;
997 void ExtensionWebRequestEventRouter::OnBeforeRedirect(
998 void* browser_context,
999 InfoMap* extension_info_map,
1000 net::URLRequest* request,
1001 const GURL& new_location) {
1002 // We hide events from the system context as well as sensitive requests.
1003 if (!browser_context ||
1004 WebRequestPermissions::HideRequest(extension_info_map, request))
1005 return;
1007 if (GetAndSetSignaled(request->identifier(), kOnBeforeRedirect))
1008 return;
1010 ClearSignaled(request->identifier(), kOnBeforeRequest);
1011 ClearSignaled(request->identifier(), kOnBeforeSendHeaders);
1012 ClearSignaled(request->identifier(), kOnSendHeaders);
1013 ClearSignaled(request->identifier(), kOnHeadersReceived);
1015 int extra_info_spec = 0;
1016 std::vector<const EventListener*> listeners =
1017 GetMatchingListeners(browser_context, extension_info_map,
1018 keys::kOnBeforeRedirectEvent, request,
1019 &extra_info_spec);
1020 if (listeners.empty())
1021 return;
1023 int http_status_code = request->GetResponseCode();
1025 std::string response_ip = request->GetSocketAddress().host();
1027 base::ListValue args;
1028 base::DictionaryValue* dict = new base::DictionaryValue();
1029 ExtractRequestInfo(request, dict);
1030 dict->SetString(keys::kRedirectUrlKey, new_location.spec());
1031 dict->SetInteger(keys::kStatusCodeKey, http_status_code);
1032 if (!response_ip.empty())
1033 dict->SetString(keys::kIpKey, response_ip);
1034 dict->SetBoolean(keys::kFromCache, request->was_cached());
1035 dict->Set(keys::kStatusLineKey, GetStatusLine(request->response_headers()));
1036 if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
1037 dict->Set(keys::kResponseHeadersKey,
1038 GetResponseHeadersList(request->response_headers()));
1040 args.Append(dict);
1042 DispatchEvent(browser_context, request, listeners, args);
1045 void ExtensionWebRequestEventRouter::OnResponseStarted(
1046 void* browser_context,
1047 InfoMap* extension_info_map,
1048 net::URLRequest* request) {
1049 // We hide events from the system context as well as sensitive requests.
1050 if (!browser_context ||
1051 WebRequestPermissions::HideRequest(extension_info_map, request))
1052 return;
1054 // OnResponseStarted is even triggered, when the request was cancelled.
1055 if (request->status().status() != net::URLRequestStatus::SUCCESS)
1056 return;
1058 int extra_info_spec = 0;
1059 std::vector<const EventListener*> listeners =
1060 GetMatchingListeners(browser_context, extension_info_map,
1061 keys::kOnResponseStartedEvent, request,
1062 &extra_info_spec);
1063 if (listeners.empty())
1064 return;
1066 // UrlRequestFileJobs do not send headers, so we simulate their behavior.
1067 int response_code = 200;
1068 if (request->response_headers())
1069 response_code = request->response_headers()->response_code();
1071 std::string response_ip = request->GetSocketAddress().host();
1073 base::ListValue args;
1074 base::DictionaryValue* dict = new base::DictionaryValue();
1075 ExtractRequestInfo(request, dict);
1076 if (!response_ip.empty())
1077 dict->SetString(keys::kIpKey, response_ip);
1078 dict->SetBoolean(keys::kFromCache, request->was_cached());
1079 dict->SetInteger(keys::kStatusCodeKey, response_code);
1080 dict->Set(keys::kStatusLineKey, GetStatusLine(request->response_headers()));
1081 if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
1082 dict->Set(keys::kResponseHeadersKey,
1083 GetResponseHeadersList(request->response_headers()));
1085 args.Append(dict);
1087 DispatchEvent(browser_context, request, listeners, args);
1090 void ExtensionWebRequestEventRouter::OnCompleted(void* browser_context,
1091 InfoMap* extension_info_map,
1092 net::URLRequest* request) {
1093 // We hide events from the system context as well as sensitive requests.
1094 // However, if the request first became sensitive after redirecting we have
1095 // already signaled it and thus we have to signal the end of it. This is
1096 // risk-free because the handler cannot modify the request now.
1097 if (!browser_context ||
1098 (WebRequestPermissions::HideRequest(extension_info_map, request) &&
1099 !WasSignaled(*request)))
1100 return;
1102 request_time_tracker_->LogRequestEndTime(request->identifier(),
1103 base::Time::Now());
1105 DCHECK(request->status().status() == net::URLRequestStatus::SUCCESS);
1107 DCHECK(!GetAndSetSignaled(request->identifier(), kOnCompleted));
1109 ClearPendingCallbacks(request);
1111 int extra_info_spec = 0;
1112 std::vector<const EventListener*> listeners =
1113 GetMatchingListeners(browser_context, extension_info_map,
1114 keys::kOnCompletedEvent, request, &extra_info_spec);
1115 if (listeners.empty())
1116 return;
1118 // UrlRequestFileJobs do not send headers, so we simulate their behavior.
1119 int response_code = 200;
1120 if (request->response_headers())
1121 response_code = request->response_headers()->response_code();
1123 std::string response_ip = request->GetSocketAddress().host();
1125 base::ListValue args;
1126 base::DictionaryValue* dict = new base::DictionaryValue();
1127 ExtractRequestInfo(request, dict);
1128 dict->SetInteger(keys::kStatusCodeKey, response_code);
1129 if (!response_ip.empty())
1130 dict->SetString(keys::kIpKey, response_ip);
1131 dict->SetBoolean(keys::kFromCache, request->was_cached());
1132 dict->Set(keys::kStatusLineKey, GetStatusLine(request->response_headers()));
1133 if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
1134 dict->Set(keys::kResponseHeadersKey,
1135 GetResponseHeadersList(request->response_headers()));
1137 args.Append(dict);
1139 DispatchEvent(browser_context, request, listeners, args);
1142 void ExtensionWebRequestEventRouter::OnErrorOccurred(
1143 void* browser_context,
1144 InfoMap* extension_info_map,
1145 net::URLRequest* request,
1146 bool started) {
1147 // We hide events from the system context as well as sensitive requests.
1148 // However, if the request first became sensitive after redirecting we have
1149 // already signaled it and thus we have to signal the end of it. This is
1150 // risk-free because the handler cannot modify the request now.
1151 if (!browser_context ||
1152 (WebRequestPermissions::HideRequest(extension_info_map, request) &&
1153 !WasSignaled(*request)))
1154 return;
1156 request_time_tracker_->LogRequestEndTime(request->identifier(),
1157 base::Time::Now());
1159 DCHECK(request->status().status() == net::URLRequestStatus::FAILED ||
1160 request->status().status() == net::URLRequestStatus::CANCELED);
1162 DCHECK(!GetAndSetSignaled(request->identifier(), kOnErrorOccurred));
1164 ClearPendingCallbacks(request);
1166 int extra_info_spec = 0;
1167 std::vector<const EventListener*> listeners =
1168 GetMatchingListeners(browser_context, extension_info_map,
1169 web_request::OnErrorOccurred::kEventName, request,
1170 &extra_info_spec);
1171 if (listeners.empty())
1172 return;
1174 base::ListValue args;
1175 base::DictionaryValue* dict = new base::DictionaryValue();
1176 ExtractRequestInfo(request, dict);
1177 if (started) {
1178 std::string response_ip = request->GetSocketAddress().host();
1179 if (!response_ip.empty())
1180 dict->SetString(keys::kIpKey, response_ip);
1182 dict->SetBoolean(keys::kFromCache, request->was_cached());
1183 dict->SetString(keys::kErrorKey,
1184 net::ErrorToString(request->status().error()));
1185 args.Append(dict);
1187 DispatchEvent(browser_context, request, listeners, args);
1190 void ExtensionWebRequestEventRouter::OnURLRequestDestroyed(
1191 void* browser_context, net::URLRequest* request) {
1192 ClearPendingCallbacks(request);
1194 signaled_requests_.erase(request->identifier());
1196 request_time_tracker_->LogRequestEndTime(request->identifier(),
1197 base::Time::Now());
1200 void ExtensionWebRequestEventRouter::ClearPendingCallbacks(
1201 net::URLRequest* request) {
1202 blocked_requests_.erase(request->identifier());
1205 bool ExtensionWebRequestEventRouter::DispatchEvent(
1206 void* browser_context,
1207 net::URLRequest* request,
1208 const std::vector<const EventListener*>& listeners,
1209 const base::ListValue& args) {
1210 // TODO(mpcomplete): Consider consolidating common (extension_id,json_args)
1211 // pairs into a single message sent to a list of sub_event_names.
1212 int num_handlers_blocking = 0;
1213 for (std::vector<const EventListener*>::const_iterator it = listeners.begin();
1214 it != listeners.end(); ++it) {
1215 // Filter out the optional keys that this listener didn't request.
1216 scoped_ptr<base::ListValue> args_filtered(args.DeepCopy());
1217 base::DictionaryValue* dict = NULL;
1218 CHECK(args_filtered->GetDictionary(0, &dict) && dict);
1219 if (!((*it)->extra_info_spec & ExtraInfoSpec::REQUEST_HEADERS))
1220 dict->Remove(keys::kRequestHeadersKey, NULL);
1221 if (!((*it)->extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS))
1222 dict->Remove(keys::kResponseHeadersKey, NULL);
1224 extensions::EventRouter::DispatchEvent(
1225 (*it)->ipc_sender.get(), browser_context,
1226 (*it)->extension_id, (*it)->sub_event_name,
1227 args_filtered.Pass(),
1228 extensions::EventRouter::USER_GESTURE_UNKNOWN,
1229 extensions::EventFilteringInfo());
1230 if ((*it)->extra_info_spec &
1231 (ExtraInfoSpec::BLOCKING | ExtraInfoSpec::ASYNC_BLOCKING)) {
1232 (*it)->blocked_requests.insert(request->identifier());
1233 // If this is the first delegate blocking the request, go ahead and log
1234 // it.
1235 if (num_handlers_blocking == 0) {
1236 std::string delegate_info =
1237 l10n_util::GetStringFUTF8(IDS_LOAD_STATE_PARAMETER_EXTENSION,
1238 base::UTF8ToUTF16((*it)->extension_name));
1239 // LobAndReport allows extensions that block requests to be displayed in
1240 // the load status bar.
1241 request->LogAndReportBlockedBy(delegate_info.c_str());
1243 ++num_handlers_blocking;
1247 if (num_handlers_blocking > 0) {
1248 blocked_requests_[request->identifier()].request = request;
1249 blocked_requests_[request->identifier()].is_incognito |=
1250 IsIncognitoBrowserContext(browser_context);
1251 blocked_requests_[request->identifier()].num_handlers_blocking +=
1252 num_handlers_blocking;
1253 blocked_requests_[request->identifier()].blocking_time = base::Time::Now();
1255 return true;
1258 return false;
1261 void ExtensionWebRequestEventRouter::OnEventHandled(
1262 void* browser_context,
1263 const std::string& extension_id,
1264 const std::string& event_name,
1265 const std::string& sub_event_name,
1266 uint64 request_id,
1267 EventResponse* response) {
1268 EventListener listener;
1269 listener.extension_id = extension_id;
1270 listener.sub_event_name = sub_event_name;
1272 // The listener may have been removed (e.g. due to the process going away)
1273 // before we got here.
1274 std::set<EventListener>::iterator found =
1275 listeners_[browser_context][event_name].find(listener);
1276 if (found != listeners_[browser_context][event_name].end())
1277 found->blocked_requests.erase(request_id);
1279 DecrementBlockCount(
1280 browser_context, extension_id, event_name, request_id, response);
1283 bool ExtensionWebRequestEventRouter::AddEventListener(
1284 void* browser_context,
1285 const std::string& extension_id,
1286 const std::string& extension_name,
1287 const std::string& event_name,
1288 const std::string& sub_event_name,
1289 const RequestFilter& filter,
1290 int extra_info_spec,
1291 int embedder_process_id,
1292 int web_view_instance_id,
1293 base::WeakPtr<IPC::Sender> ipc_sender) {
1294 if (!IsWebRequestEvent(event_name))
1295 return false;
1297 EventListener listener;
1298 listener.extension_id = extension_id;
1299 listener.extension_name = extension_name;
1300 listener.sub_event_name = sub_event_name;
1301 listener.filter = filter;
1302 listener.extra_info_spec = extra_info_spec;
1303 listener.ipc_sender = ipc_sender;
1304 listener.embedder_process_id = embedder_process_id;
1305 listener.web_view_instance_id = web_view_instance_id;
1306 if (listener.web_view_instance_id) {
1307 content::RecordAction(
1308 base::UserMetricsAction("WebView.WebRequest.AddListener"));
1311 if (listeners_[browser_context][event_name].count(listener) != 0u) {
1312 // This is likely an abuse of the API by a malicious extension.
1313 return false;
1315 listeners_[browser_context][event_name].insert(listener);
1316 return true;
1319 void ExtensionWebRequestEventRouter::RemoveEventListener(
1320 void* browser_context,
1321 const std::string& extension_id,
1322 const std::string& sub_event_name) {
1323 std::string event_name =
1324 extensions::EventRouter::GetBaseEventName(sub_event_name);
1325 DCHECK(IsWebRequestEvent(event_name));
1327 EventListener listener;
1328 listener.extension_id = extension_id;
1329 listener.sub_event_name = sub_event_name;
1331 // It's possible for AddEventListener to fail asynchronously. In that case,
1332 // the renderer believes the listener exists, while the browser does not.
1333 // Ignore a RemoveEventListener in that case.
1334 std::set<EventListener>::iterator found =
1335 listeners_[browser_context][event_name].find(listener);
1336 if (found == listeners_[browser_context][event_name].end())
1337 return;
1339 CHECK_EQ(listeners_[browser_context][event_name].count(listener), 1u) <<
1340 "extension=" << extension_id << " event=" << event_name;
1342 // Unblock any request that this event listener may have been blocking.
1343 for (std::set<uint64>::iterator it = found->blocked_requests.begin();
1344 it != found->blocked_requests.end(); ++it) {
1345 DecrementBlockCount(browser_context, extension_id, event_name, *it, NULL);
1348 listeners_[browser_context][event_name].erase(listener);
1350 helpers::ClearCacheOnNavigation();
1353 void ExtensionWebRequestEventRouter::RemoveWebViewEventListeners(
1354 void* browser_context,
1355 const std::string& extension_id,
1356 int embedder_process_id,
1357 int web_view_instance_id) {
1358 // Iterate over all listeners of all WebRequest events to delete
1359 // any listeners that belong to the provided <webview>.
1360 ListenerMapForBrowserContext& map_for_browser_context =
1361 listeners_[browser_context];
1362 for (ListenerMapForBrowserContext::iterator event_iter =
1363 map_for_browser_context.begin();
1364 event_iter != map_for_browser_context.end(); ++event_iter) {
1365 std::vector<EventListener> listeners_to_delete;
1366 std::set<EventListener>& listeners = event_iter->second;
1367 for (std::set<EventListener>::iterator listener_iter = listeners.begin();
1368 listener_iter != listeners.end(); ++listener_iter) {
1369 const EventListener& listener = *listener_iter;
1370 if (listener.embedder_process_id == embedder_process_id &&
1371 listener.web_view_instance_id == web_view_instance_id)
1372 listeners_to_delete.push_back(listener);
1374 for (size_t i = 0; i < listeners_to_delete.size(); ++i) {
1375 EventListener& listener = listeners_to_delete[i];
1376 content::BrowserThread::PostTask(
1377 content::BrowserThread::UI,
1378 FROM_HERE,
1379 base::Bind(&RemoveEventListenerOnUI,
1380 browser_context,
1381 listener.sub_event_name,
1382 embedder_process_id,
1383 extension_id));
1388 void ExtensionWebRequestEventRouter::OnOTRBrowserContextCreated(
1389 void* original_browser_context, void* otr_browser_context) {
1390 cross_browser_context_map_[original_browser_context] =
1391 std::make_pair(false, otr_browser_context);
1392 cross_browser_context_map_[otr_browser_context] =
1393 std::make_pair(true, original_browser_context);
1396 void ExtensionWebRequestEventRouter::OnOTRBrowserContextDestroyed(
1397 void* original_browser_context, void* otr_browser_context) {
1398 cross_browser_context_map_.erase(otr_browser_context);
1399 cross_browser_context_map_.erase(original_browser_context);
1402 void ExtensionWebRequestEventRouter::AddCallbackForPageLoad(
1403 const base::Closure& callback) {
1404 callbacks_for_page_load_.push_back(callback);
1407 bool ExtensionWebRequestEventRouter::IsPageLoad(
1408 net::URLRequest* request) const {
1409 bool is_main_frame = false;
1410 int frame_id = -1;
1411 bool parent_is_main_frame = false;
1412 int parent_frame_id = -1;
1413 int render_process_host_id = -1;
1414 int routing_id = -1;
1415 ResourceType resource_type = content::RESOURCE_TYPE_LAST_TYPE;
1417 ExtractRequestInfoDetails(request, &is_main_frame, &frame_id,
1418 &parent_is_main_frame, &parent_frame_id,
1419 &render_process_host_id,
1420 &routing_id, &resource_type);
1422 return resource_type == content::RESOURCE_TYPE_MAIN_FRAME;
1425 void ExtensionWebRequestEventRouter::NotifyPageLoad() {
1426 for (CallbacksForPageLoad::const_iterator i =
1427 callbacks_for_page_load_.begin();
1428 i != callbacks_for_page_load_.end(); ++i) {
1429 i->Run();
1431 callbacks_for_page_load_.clear();
1434 void* ExtensionWebRequestEventRouter::GetCrossBrowserContext(
1435 void* browser_context) const {
1436 CrossBrowserContextMap::const_iterator cross_browser_context =
1437 cross_browser_context_map_.find(browser_context);
1438 if (cross_browser_context == cross_browser_context_map_.end())
1439 return NULL;
1440 return cross_browser_context->second.second;
1443 bool ExtensionWebRequestEventRouter::IsIncognitoBrowserContext(
1444 void* browser_context) const {
1445 CrossBrowserContextMap::const_iterator cross_browser_context =
1446 cross_browser_context_map_.find(browser_context);
1447 if (cross_browser_context == cross_browser_context_map_.end())
1448 return false;
1449 return cross_browser_context->second.first;
1452 bool ExtensionWebRequestEventRouter::WasSignaled(
1453 const net::URLRequest& request) const {
1454 SignaledRequestMap::const_iterator flag =
1455 signaled_requests_.find(request.identifier());
1456 return (flag != signaled_requests_.end()) && (flag->second != 0);
1459 void ExtensionWebRequestEventRouter::GetMatchingListenersImpl(
1460 void* browser_context,
1461 net::URLRequest* request,
1462 InfoMap* extension_info_map,
1463 bool crosses_incognito,
1464 const std::string& event_name,
1465 const GURL& url,
1466 int render_process_host_id,
1467 int routing_id,
1468 ResourceType resource_type,
1469 bool is_async_request,
1470 bool is_request_from_extension,
1471 int* extra_info_spec,
1472 std::vector<const ExtensionWebRequestEventRouter::EventListener*>*
1473 matching_listeners) {
1474 std::string web_request_event_name(event_name);
1475 extensions::WebViewRendererState::WebViewInfo web_view_info;
1476 bool is_web_view_guest = extensions::WebViewRendererState::GetInstance()->
1477 GetInfo(render_process_host_id, routing_id, &web_view_info);
1478 if (is_web_view_guest) {
1479 web_request_event_name.replace(
1480 0, sizeof(kWebRequestEventPrefix) - 1, webview::kWebViewEventPrefix);
1483 std::set<EventListener>& listeners =
1484 listeners_[browser_context][web_request_event_name];
1485 for (std::set<EventListener>::iterator it = listeners.begin();
1486 it != listeners.end(); ++it) {
1487 if (!it->ipc_sender.get()) {
1488 // The IPC sender has been deleted. This listener will be removed soon
1489 // via a call to RemoveEventListener. For now, just skip it.
1490 continue;
1493 if (is_web_view_guest &&
1494 (it->embedder_process_id != web_view_info.embedder_process_id ||
1495 it->web_view_instance_id != web_view_info.instance_id))
1496 continue;
1498 if (!it->filter.urls.is_empty() && !it->filter.urls.MatchesURL(url))
1499 continue;
1500 if (web_request_event_router_delegate_ &&
1501 web_request_event_router_delegate_->OnGetMatchingListenersImplCheck(
1502 it->filter.tab_id, it->filter.window_id, request))
1503 continue;
1504 if (!it->filter.types.empty() &&
1505 std::find(it->filter.types.begin(), it->filter.types.end(),
1506 resource_type) == it->filter.types.end())
1507 continue;
1509 if (!is_web_view_guest && !WebRequestPermissions::CanExtensionAccessURL(
1510 extension_info_map, it->extension_id, url, crosses_incognito,
1511 WebRequestPermissions::REQUIRE_HOST_PERMISSION))
1512 continue;
1514 bool blocking_listener =
1515 (it->extra_info_spec &
1516 (ExtraInfoSpec::BLOCKING | ExtraInfoSpec::ASYNC_BLOCKING)) != 0;
1518 // We do not want to notify extensions about XHR requests that are
1519 // triggered by themselves. This is a workaround to prevent deadlocks
1520 // in case of synchronous XHR requests that block the extension renderer
1521 // and therefore prevent the extension from processing the request
1522 // handler. This is only a problem for blocking listeners.
1523 // http://crbug.com/105656
1524 bool synchronous_xhr_from_extension =
1525 !is_async_request && is_request_from_extension &&
1526 resource_type == content::RESOURCE_TYPE_XHR;
1528 // Only send webRequest events for URLs the extension has access to.
1529 if (blocking_listener && synchronous_xhr_from_extension)
1530 continue;
1532 matching_listeners->push_back(&(*it));
1533 *extra_info_spec |= it->extra_info_spec;
1537 std::vector<const ExtensionWebRequestEventRouter::EventListener*>
1538 ExtensionWebRequestEventRouter::GetMatchingListeners(
1539 void* browser_context,
1540 InfoMap* extension_info_map,
1541 const std::string& event_name,
1542 net::URLRequest* request,
1543 int* extra_info_spec) {
1544 // TODO(mpcomplete): handle browser_context == NULL (should collect all
1545 // listeners).
1546 *extra_info_spec = 0;
1548 bool is_main_frame = false;
1549 int frame_id = -1;
1550 bool parent_is_main_frame = false;
1551 int parent_frame_id = -1;
1552 int render_process_host_id = -1;
1553 int routing_id = -1;
1554 ResourceType resource_type = content::RESOURCE_TYPE_LAST_TYPE;
1555 const GURL& url = request->url();
1557 ExtractRequestInfoDetails(request, &is_main_frame, &frame_id,
1558 &parent_is_main_frame, &parent_frame_id,
1559 &render_process_host_id,
1560 &routing_id, &resource_type);
1562 std::vector<const ExtensionWebRequestEventRouter::EventListener*>
1563 matching_listeners;
1565 bool is_request_from_extension =
1566 IsRequestFromExtension(request, extension_info_map);
1568 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
1569 // We are conservative here and assume requests are asynchronous in case
1570 // we don't have an info object. We don't want to risk a deadlock.
1571 bool is_async_request = !info || info->IsAsync();
1573 GetMatchingListenersImpl(
1574 browser_context, request, extension_info_map, false, 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);
1578 void* cross_browser_context = GetCrossBrowserContext(browser_context);
1579 if (cross_browser_context) {
1580 GetMatchingListenersImpl(
1581 cross_browser_context, request, extension_info_map, true, event_name,
1582 url, render_process_host_id, routing_id, resource_type,
1583 is_async_request, is_request_from_extension, extra_info_spec,
1584 &matching_listeners);
1587 return matching_listeners;
1590 namespace {
1592 helpers::EventResponseDelta* CalculateDelta(
1593 ExtensionWebRequestEventRouter::BlockedRequest* blocked_request,
1594 ExtensionWebRequestEventRouter::EventResponse* response) {
1595 switch (blocked_request->event) {
1596 case ExtensionWebRequestEventRouter::kOnBeforeRequest:
1597 return helpers::CalculateOnBeforeRequestDelta(
1598 response->extension_id, response->extension_install_time,
1599 response->cancel, response->new_url);
1600 case ExtensionWebRequestEventRouter::kOnBeforeSendHeaders: {
1601 net::HttpRequestHeaders* old_headers = blocked_request->request_headers;
1602 net::HttpRequestHeaders* new_headers = response->request_headers.get();
1603 return helpers::CalculateOnBeforeSendHeadersDelta(
1604 response->extension_id, response->extension_install_time,
1605 response->cancel, old_headers, new_headers);
1607 case ExtensionWebRequestEventRouter::kOnHeadersReceived: {
1608 const net::HttpResponseHeaders* old_headers =
1609 blocked_request->original_response_headers.get();
1610 helpers::ResponseHeaders* new_headers =
1611 response->response_headers.get();
1612 return helpers::CalculateOnHeadersReceivedDelta(
1613 response->extension_id,
1614 response->extension_install_time,
1615 response->cancel,
1616 response->new_url,
1617 old_headers,
1618 new_headers);
1620 case ExtensionWebRequestEventRouter::kOnAuthRequired:
1621 return helpers::CalculateOnAuthRequiredDelta(
1622 response->extension_id, response->extension_install_time,
1623 response->cancel, &response->auth_credentials);
1624 default:
1625 NOTREACHED();
1626 break;
1628 return NULL;
1631 base::Value* SerializeResponseHeaders(const helpers::ResponseHeaders& headers) {
1632 scoped_ptr<base::ListValue> serialized_headers(new base::ListValue());
1633 for (helpers::ResponseHeaders::const_iterator i = headers.begin();
1634 i != headers.end(); ++i) {
1635 serialized_headers->Append(
1636 helpers::CreateHeaderDictionary(i->first, i->second));
1638 return serialized_headers.release();
1641 // Convert a RequestCookieModifications/ResponseCookieModifications object to a
1642 // base::ListValue which summarizes the changes made. This is templated since
1643 // the two types (request/response) are different but contain essentially the
1644 // same fields.
1645 template<typename CookieType>
1646 base::ListValue* SummarizeCookieModifications(
1647 const std::vector<linked_ptr<CookieType> >& modifications) {
1648 scoped_ptr<base::ListValue> cookie_modifications(new base::ListValue());
1649 for (typename std::vector<linked_ptr<CookieType> >::const_iterator i =
1650 modifications.begin();
1651 i != modifications.end(); ++i) {
1652 scoped_ptr<base::DictionaryValue> summary(new base::DictionaryValue());
1653 const CookieType& mod = *i->get();
1654 switch (mod.type) {
1655 case helpers::ADD:
1656 summary->SetString(activitylog::kCookieModificationTypeKey,
1657 activitylog::kCookieModificationAdd);
1658 break;
1659 case helpers::EDIT:
1660 summary->SetString(activitylog::kCookieModificationTypeKey,
1661 activitylog::kCookieModificationEdit);
1662 break;
1663 case helpers::REMOVE:
1664 summary->SetString(activitylog::kCookieModificationTypeKey,
1665 activitylog::kCookieModificationRemove);
1666 break;
1668 if (mod.filter) {
1669 if (mod.filter->name)
1670 summary->SetString(activitylog::kCookieFilterNameKey,
1671 *mod.modification->name);
1672 if (mod.filter->domain)
1673 summary->SetString(activitylog::kCookieFilterDomainKey,
1674 *mod.modification->name);
1676 if (mod.modification) {
1677 if (mod.modification->name)
1678 summary->SetString(activitylog::kCookieModDomainKey,
1679 *mod.modification->name);
1680 if (mod.modification->domain)
1681 summary->SetString(activitylog::kCookieModDomainKey,
1682 *mod.modification->name);
1684 cookie_modifications->Append(summary.release());
1686 return cookie_modifications.release();
1689 // Converts an EventResponseDelta object to a dictionary value suitable for the
1690 // activity log.
1691 scoped_ptr<base::DictionaryValue> SummarizeResponseDelta(
1692 const std::string& event_name,
1693 const helpers::EventResponseDelta& delta) {
1694 scoped_ptr<base::DictionaryValue> details(new base::DictionaryValue());
1695 if (delta.cancel) {
1696 details->SetBoolean(activitylog::kCancelKey, true);
1698 if (!delta.new_url.is_empty()) {
1699 details->SetString(activitylog::kNewUrlKey, delta.new_url.spec());
1702 scoped_ptr<base::ListValue> modified_headers(new base::ListValue());
1703 net::HttpRequestHeaders::Iterator iter(delta.modified_request_headers);
1704 while (iter.GetNext()) {
1705 modified_headers->Append(
1706 helpers::CreateHeaderDictionary(iter.name(), iter.value()));
1708 if (!modified_headers->empty()) {
1709 details->Set(activitylog::kModifiedRequestHeadersKey,
1710 modified_headers.release());
1713 scoped_ptr<base::ListValue> deleted_headers(new base::ListValue());
1714 deleted_headers->AppendStrings(delta.deleted_request_headers);
1715 if (!deleted_headers->empty()) {
1716 details->Set(activitylog::kDeletedRequestHeadersKey,
1717 deleted_headers.release());
1720 if (!delta.added_response_headers.empty()) {
1721 details->Set(activitylog::kAddedRequestHeadersKey,
1722 SerializeResponseHeaders(delta.added_response_headers));
1724 if (!delta.deleted_response_headers.empty()) {
1725 details->Set(activitylog::kDeletedResponseHeadersKey,
1726 SerializeResponseHeaders(delta.deleted_response_headers));
1728 if (delta.auth_credentials) {
1729 details->SetString(activitylog::kAuthCredentialsKey,
1730 base::UTF16ToUTF8(
1731 delta.auth_credentials->username()) + ":*");
1734 if (!delta.response_cookie_modifications.empty()) {
1735 details->Set(
1736 activitylog::kResponseCookieModificationsKey,
1737 SummarizeCookieModifications(delta.response_cookie_modifications));
1740 return details.Pass();
1743 } // namespace
1745 void ExtensionWebRequestEventRouter::LogExtensionActivity(
1746 void* browser_context_id,
1747 bool is_incognito,
1748 const std::string& extension_id,
1749 const GURL& url,
1750 const std::string& api_call,
1751 scoped_ptr<base::DictionaryValue> details) {
1752 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
1753 BrowserThread::PostTask(
1754 BrowserThread::UI,
1755 FROM_HERE,
1756 base::Bind(&ExtensionWebRequestEventRouter::LogExtensionActivity,
1757 base::Unretained(this),
1758 browser_context_id,
1759 is_incognito,
1760 extension_id,
1761 url,
1762 api_call,
1763 base::Passed(&details)));
1764 } else {
1765 if (web_request_event_router_delegate_) {
1766 web_request_event_router_delegate_->LogExtensionActivity(
1767 reinterpret_cast<content::BrowserContext*>(browser_context_id),
1768 is_incognito, extension_id, url, api_call, details.Pass());
1773 void ExtensionWebRequestEventRouter::DecrementBlockCount(
1774 void* browser_context,
1775 const std::string& extension_id,
1776 const std::string& event_name,
1777 uint64 request_id,
1778 EventResponse* response) {
1779 scoped_ptr<EventResponse> response_scoped(response);
1781 // It's possible that this request was deleted, or cancelled by a previous
1782 // event handler. If so, ignore this response.
1783 if (blocked_requests_.find(request_id) == blocked_requests_.end())
1784 return;
1786 BlockedRequest& blocked_request = blocked_requests_[request_id];
1787 int num_handlers_blocking = --blocked_request.num_handlers_blocking;
1788 CHECK_GE(num_handlers_blocking, 0);
1790 if (response) {
1791 helpers::EventResponseDelta* delta =
1792 CalculateDelta(&blocked_request, response);
1794 LogExtensionActivity(browser_context,
1795 blocked_request.is_incognito,
1796 extension_id,
1797 blocked_request.request->url(),
1798 event_name,
1799 SummarizeResponseDelta(event_name, *delta));
1801 blocked_request.response_deltas.push_back(
1802 linked_ptr<helpers::EventResponseDelta>(delta));
1805 base::TimeDelta block_time =
1806 base::Time::Now() - blocked_request.blocking_time;
1807 if (!extension_id.empty()) {
1808 request_time_tracker_->IncrementExtensionBlockTime(
1809 extension_id, request_id, block_time);
1810 } else {
1811 // |extension_id| is empty for requests blocked on startup waiting for the
1812 // declarative rules to be read from disk.
1813 UMA_HISTOGRAM_TIMES("Extensions.NetworkDelayStartup", block_time);
1816 if (num_handlers_blocking == 0) {
1817 blocked_request.request->LogUnblocked();
1818 ExecuteDeltas(browser_context, request_id, true);
1819 } else {
1820 // Update the URLRequest to make sure it's tagged with an extension that's
1821 // still blocking it. This may end up being the same extension as before.
1822 std::set<EventListener>& listeners =
1823 listeners_[browser_context][event_name];
1825 for (std::set<EventListener>::iterator it = listeners.begin();
1826 it != listeners.end(); ++it) {
1827 if (it->blocked_requests.count(request_id) == 0)
1828 continue;
1829 std::string delegate_info =
1830 l10n_util::GetStringFUTF8(IDS_LOAD_STATE_PARAMETER_EXTENSION,
1831 base::UTF8ToUTF16(it->extension_name));
1832 blocked_request.request->LogAndReportBlockedBy(delegate_info.c_str());
1833 break;
1838 void ExtensionWebRequestEventRouter::SendMessages(
1839 void* browser_context,
1840 const BlockedRequest& blocked_request) {
1841 const helpers::EventResponseDeltas& deltas = blocked_request.response_deltas;
1842 for (helpers::EventResponseDeltas::const_iterator delta = deltas.begin();
1843 delta != deltas.end(); ++delta) {
1844 const std::set<std::string>& messages = (*delta)->messages_to_extension;
1845 for (std::set<std::string>::const_iterator message = messages.begin();
1846 message != messages.end(); ++message) {
1847 scoped_ptr<base::DictionaryValue> argument(new base::DictionaryValue);
1848 ExtractRequestInfo(blocked_request.request, argument.get());
1849 extensions::WebViewRendererState::WebViewInfo web_view_info;
1850 bool is_web_view_guest = GetWebViewInfo(blocked_request.request,
1851 &web_view_info);
1852 argument->SetString(keys::kMessageKey, *message);
1853 argument->SetString(keys::kStageKey,
1854 GetRequestStageAsString(blocked_request.event));
1856 BrowserThread::PostTask(
1857 BrowserThread::UI,
1858 FROM_HERE,
1859 base::Bind(&SendOnMessageEventOnUI,
1860 browser_context,
1861 (*delta)->extension_id,
1862 is_web_view_guest,
1863 web_view_info,
1864 base::Passed(&argument)));
1869 int ExtensionWebRequestEventRouter::ExecuteDeltas(
1870 void* browser_context,
1871 uint64 request_id,
1872 bool call_callback) {
1873 BlockedRequest& blocked_request = blocked_requests_[request_id];
1874 CHECK(blocked_request.num_handlers_blocking == 0);
1875 helpers::EventResponseDeltas& deltas = blocked_request.response_deltas;
1876 base::TimeDelta block_time =
1877 base::Time::Now() - blocked_request.blocking_time;
1878 request_time_tracker_->IncrementTotalBlockTime(request_id, block_time);
1880 bool credentials_set = false;
1882 deltas.sort(&helpers::InDecreasingExtensionInstallationTimeOrder);
1883 WarningSet warnings;
1885 bool canceled = false;
1886 helpers::MergeCancelOfResponses(
1887 blocked_request.response_deltas,
1888 &canceled,
1889 blocked_request.net_log);
1891 if (blocked_request.event == kOnBeforeRequest) {
1892 CHECK(!blocked_request.callback.is_null());
1893 helpers::MergeOnBeforeRequestResponses(
1894 blocked_request.response_deltas,
1895 blocked_request.new_url,
1896 &warnings,
1897 blocked_request.net_log);
1898 } else if (blocked_request.event == kOnBeforeSendHeaders) {
1899 CHECK(!blocked_request.callback.is_null());
1900 helpers::MergeOnBeforeSendHeadersResponses(
1901 blocked_request.response_deltas,
1902 blocked_request.request_headers,
1903 &warnings,
1904 blocked_request.net_log);
1905 } else if (blocked_request.event == kOnHeadersReceived) {
1906 CHECK(!blocked_request.callback.is_null());
1907 helpers::MergeOnHeadersReceivedResponses(
1908 blocked_request.response_deltas,
1909 blocked_request.original_response_headers.get(),
1910 blocked_request.override_response_headers,
1911 blocked_request.new_url,
1912 &warnings,
1913 blocked_request.net_log);
1914 } else if (blocked_request.event == kOnAuthRequired) {
1915 CHECK(blocked_request.callback.is_null());
1916 CHECK(!blocked_request.auth_callback.is_null());
1917 credentials_set = helpers::MergeOnAuthRequiredResponses(
1918 blocked_request.response_deltas,
1919 blocked_request.auth_credentials,
1920 &warnings,
1921 blocked_request.net_log);
1922 } else {
1923 NOTREACHED();
1926 SendMessages(browser_context, blocked_request);
1928 if (!warnings.empty()) {
1929 BrowserThread::PostTask(
1930 BrowserThread::UI,
1931 FROM_HERE,
1932 base::Bind(&WarningService::NotifyWarningsOnUI,
1933 browser_context, warnings));
1936 if (canceled) {
1937 request_time_tracker_->SetRequestCanceled(request_id);
1938 } else if (blocked_request.new_url &&
1939 !blocked_request.new_url->is_empty()) {
1940 request_time_tracker_->SetRequestRedirected(request_id);
1943 // This triggers onErrorOccurred if canceled is true.
1944 int rv = canceled ? net::ERR_BLOCKED_BY_CLIENT : net::OK;
1946 if (!blocked_request.callback.is_null()) {
1947 net::CompletionCallback callback = blocked_request.callback;
1948 // Ensure that request is removed before callback because the callback
1949 // might trigger the next event.
1950 blocked_requests_.erase(request_id);
1951 if (call_callback)
1952 callback.Run(rv);
1953 } else if (!blocked_request.auth_callback.is_null()) {
1954 net::NetworkDelegate::AuthRequiredResponse response =
1955 net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION;
1956 if (canceled) {
1957 response = net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_CANCEL_AUTH;
1958 } else if (credentials_set) {
1959 response = net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_SET_AUTH;
1961 net::NetworkDelegate::AuthCallback callback = blocked_request.auth_callback;
1962 blocked_requests_.erase(request_id);
1963 if (call_callback)
1964 callback.Run(response);
1965 } else {
1966 blocked_requests_.erase(request_id);
1968 return rv;
1971 bool ExtensionWebRequestEventRouter::ProcessDeclarativeRules(
1972 void* browser_context,
1973 InfoMap* extension_info_map,
1974 const std::string& event_name,
1975 net::URLRequest* request,
1976 extensions::RequestStage request_stage,
1977 const net::HttpResponseHeaders* original_response_headers) {
1978 extensions::WebViewRendererState::WebViewInfo web_view_info;
1979 bool is_web_view_guest = GetWebViewInfo(request, &web_view_info);
1980 int rules_registry_id = is_web_view_guest
1981 ? web_view_info.rules_registry_id
1982 : RulesRegistryService::kDefaultRulesRegistryID;
1984 RulesRegistryKey rules_key(browser_context, rules_registry_id);
1985 // If this check fails, check that the active stages are up-to-date in
1986 // extensions/browser/api/declarative_webrequest/request_stage.h .
1987 DCHECK(request_stage & extensions::kActiveStages);
1989 // Rules of the current |browser_context| may apply but we need to check also
1990 // whether there are applicable rules from extensions whose background page
1991 // spans from regular to incognito mode.
1993 // First parameter identifies the registry, the second indicates whether the
1994 // registry belongs to the cross browser_context.
1995 typedef std::pair<extensions::WebRequestRulesRegistry*, bool>
1996 RelevantRegistry;
1997 typedef std::vector<RelevantRegistry> RelevantRegistries;
1998 RelevantRegistries relevant_registries;
2000 if (rules_registries_.find(rules_key) != rules_registries_.end()) {
2001 relevant_registries.push_back(
2002 std::make_pair(rules_registries_[rules_key].get(), false));
2005 void* cross_browser_context = GetCrossBrowserContext(browser_context);
2006 RulesRegistryKey cross_browser_context_rules_key(cross_browser_context,
2007 rules_registry_id);
2008 if (cross_browser_context &&
2009 rules_registries_.find(cross_browser_context_rules_key) !=
2010 rules_registries_.end()) {
2011 relevant_registries.push_back(
2012 std::make_pair(
2013 rules_registries_[cross_browser_context_rules_key].get(), true));
2016 // The following block is experimentally enabled and its impact on load time
2017 // logged with UMA Extensions.NetworkDelayRegistryLoad. crbug.com/175961
2018 for (RelevantRegistries::iterator i = relevant_registries.begin();
2019 i != relevant_registries.end(); ++i) {
2020 extensions::WebRequestRulesRegistry* rules_registry = i->first;
2021 if (!rules_registry->ready().is_signaled()) {
2022 // The rules registry is still loading. Block this request until it
2023 // finishes.
2024 rules_registry->ready().Post(
2025 FROM_HERE,
2026 base::Bind(&ExtensionWebRequestEventRouter::OnRulesRegistryReady,
2027 AsWeakPtr(),
2028 browser_context,
2029 event_name,
2030 request->identifier(),
2031 request_stage));
2032 blocked_requests_[request->identifier()].num_handlers_blocking++;
2033 blocked_requests_[request->identifier()].request = request;
2034 blocked_requests_[request->identifier()].is_incognito |=
2035 IsIncognitoBrowserContext(browser_context);
2036 blocked_requests_[request->identifier()].blocking_time =
2037 base::Time::Now();
2038 blocked_requests_[request->identifier()].original_response_headers =
2039 original_response_headers;
2040 blocked_requests_[request->identifier()].extension_info_map =
2041 extension_info_map;
2042 return true;
2046 base::Time start = base::Time::Now();
2048 bool deltas_created = false;
2049 for (RelevantRegistries::iterator i = relevant_registries.begin();
2050 i != relevant_registries.end(); ++i) {
2051 extensions::WebRequestRulesRegistry* rules_registry =
2052 i->first;
2053 helpers::EventResponseDeltas result =
2054 rules_registry->CreateDeltas(
2055 extension_info_map,
2056 extensions::WebRequestData(
2057 request, request_stage, original_response_headers),
2058 i->second);
2060 if (!result.empty()) {
2061 helpers::EventResponseDeltas& deltas =
2062 blocked_requests_[request->identifier()].response_deltas;
2063 deltas.insert(deltas.end(), result.begin(), result.end());
2064 deltas_created = true;
2068 base::TimeDelta elapsed_time = start - base::Time::Now();
2069 UMA_HISTOGRAM_TIMES("Extensions.DeclarativeWebRequestNetworkDelay",
2070 elapsed_time);
2072 return deltas_created;
2075 void ExtensionWebRequestEventRouter::OnRulesRegistryReady(
2076 void* browser_context,
2077 const std::string& event_name,
2078 uint64 request_id,
2079 extensions::RequestStage request_stage) {
2080 // It's possible that this request was deleted, or cancelled by a previous
2081 // event handler. If so, ignore this response.
2082 if (blocked_requests_.find(request_id) == blocked_requests_.end())
2083 return;
2085 BlockedRequest& blocked_request = blocked_requests_[request_id];
2086 base::TimeDelta block_time =
2087 base::Time::Now() - blocked_request.blocking_time;
2088 UMA_HISTOGRAM_TIMES("Extensions.NetworkDelayRegistryLoad", block_time);
2090 ProcessDeclarativeRules(browser_context,
2091 blocked_request.extension_info_map,
2092 event_name,
2093 blocked_request.request,
2094 request_stage,
2095 blocked_request.original_response_headers.get());
2096 // Reset to NULL so that nobody relies on this being set.
2097 blocked_request.extension_info_map = NULL;
2098 DecrementBlockCount(
2099 browser_context, std::string(), event_name, request_id, NULL);
2102 bool ExtensionWebRequestEventRouter::GetAndSetSignaled(uint64 request_id,
2103 EventTypes event_type) {
2104 SignaledRequestMap::iterator iter = signaled_requests_.find(request_id);
2105 if (iter == signaled_requests_.end()) {
2106 signaled_requests_[request_id] = event_type;
2107 return false;
2109 bool was_signaled_before = (iter->second & event_type) != 0;
2110 iter->second |= event_type;
2111 return was_signaled_before;
2114 void ExtensionWebRequestEventRouter::ClearSignaled(uint64 request_id,
2115 EventTypes event_type) {
2116 SignaledRequestMap::iterator iter = signaled_requests_.find(request_id);
2117 if (iter == signaled_requests_.end())
2118 return;
2119 iter->second &= ~event_type;
2122 // Special QuotaLimitHeuristic for WebRequestHandlerBehaviorChangedFunction.
2124 // Each call of webRequest.handlerBehaviorChanged() clears the in-memory cache
2125 // of WebKit at the time of the next page load (top level navigation event).
2126 // This quota heuristic is intended to limit the number of times the cache is
2127 // cleared by an extension.
2129 // As we want to account for the number of times the cache is really cleared
2130 // (opposed to the number of times webRequest.handlerBehaviorChanged() is
2131 // called), we cannot decide whether a call of
2132 // webRequest.handlerBehaviorChanged() should trigger a quota violation at the
2133 // time it is called. Instead we only decrement the bucket counter at the time
2134 // when the cache is cleared (when page loads happen).
2135 class ClearCacheQuotaHeuristic : public extensions::QuotaLimitHeuristic {
2136 public:
2137 ClearCacheQuotaHeuristic(const Config& config, BucketMapper* map)
2138 : QuotaLimitHeuristic(
2139 config,
2140 map,
2141 "MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES"),
2142 callback_registered_(false),
2143 weak_ptr_factory_(this) {}
2144 ~ClearCacheQuotaHeuristic() override {}
2145 bool Apply(Bucket* bucket, const base::TimeTicks& event_time) override;
2147 private:
2148 // Callback that is triggered by the ExtensionWebRequestEventRouter on a page
2149 // load.
2151 // We don't need to take care of the life time of |bucket|: It is owned by the
2152 // BucketMapper of our base class in |QuotaLimitHeuristic::bucket_mapper_|. As
2153 // long as |this| exists, the respective BucketMapper and its bucket will
2154 // exist as well.
2155 void OnPageLoad(Bucket* bucket);
2157 // Flag to prevent that we register more than one call back in-between
2158 // clearing the cache.
2159 bool callback_registered_;
2161 base::WeakPtrFactory<ClearCacheQuotaHeuristic> weak_ptr_factory_;
2163 DISALLOW_COPY_AND_ASSIGN(ClearCacheQuotaHeuristic);
2166 bool ClearCacheQuotaHeuristic::Apply(Bucket* bucket,
2167 const base::TimeTicks& event_time) {
2168 if (event_time > bucket->expiration())
2169 bucket->Reset(config(), event_time);
2171 // Call bucket->DeductToken() on a new page load, this is when
2172 // webRequest.handlerBehaviorChanged() clears the cache.
2173 if (!callback_registered_) {
2174 ExtensionWebRequestEventRouter::GetInstance()->AddCallbackForPageLoad(
2175 base::Bind(&ClearCacheQuotaHeuristic::OnPageLoad,
2176 weak_ptr_factory_.GetWeakPtr(),
2177 bucket));
2178 callback_registered_ = true;
2181 // We only check whether tokens are left here. Deducting a token happens in
2182 // OnPageLoad().
2183 return bucket->has_tokens();
2186 void ClearCacheQuotaHeuristic::OnPageLoad(Bucket* bucket) {
2187 callback_registered_ = false;
2188 bucket->DeductToken();
2191 bool WebRequestInternalAddEventListenerFunction::RunSync() {
2192 // Argument 0 is the callback, which we don't use here.
2193 ExtensionWebRequestEventRouter::RequestFilter filter;
2194 base::DictionaryValue* value = NULL;
2195 error_.clear();
2196 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &value));
2197 // Failure + an empty error string means a fatal error.
2198 EXTENSION_FUNCTION_VALIDATE(filter.InitFromValue(*value, &error_) ||
2199 !error_.empty());
2200 if (!error_.empty())
2201 return false;
2203 int extra_info_spec = 0;
2204 if (HasOptionalArgument(2)) {
2205 base::ListValue* value = NULL;
2206 EXTENSION_FUNCTION_VALIDATE(args_->GetList(2, &value));
2207 EXTENSION_FUNCTION_VALIDATE(
2208 ExtensionWebRequestEventRouter::ExtraInfoSpec::InitFromValue(
2209 *value, &extra_info_spec));
2212 std::string event_name;
2213 EXTENSION_FUNCTION_VALIDATE(args_->GetString(3, &event_name));
2215 std::string sub_event_name;
2216 EXTENSION_FUNCTION_VALIDATE(args_->GetString(4, &sub_event_name));
2218 int web_view_instance_id = 0;
2219 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(5, &web_view_instance_id));
2221 base::WeakPtr<extensions::ExtensionMessageFilter> ipc_sender =
2222 ipc_sender_weak();
2223 int embedder_process_id =
2224 ipc_sender.get() && web_view_instance_id > 0 ?
2225 ipc_sender->render_process_id() : 0;
2227 const Extension* extension =
2228 extension_info_map()->extensions().GetByID(extension_id_safe());
2229 std::string extension_name =
2230 extension ? extension->name() : extension_id_safe();
2232 if (!web_view_instance_id) {
2233 // We check automatically whether the extension has the 'webRequest'
2234 // permission. For blocking calls we require the additional permission
2235 // 'webRequestBlocking'.
2236 if ((extra_info_spec &
2237 (ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING |
2238 ExtensionWebRequestEventRouter::ExtraInfoSpec::ASYNC_BLOCKING)) &&
2239 !extension->permissions_data()->HasAPIPermission(
2240 extensions::APIPermission::kWebRequestBlocking)) {
2241 error_ = keys::kBlockingPermissionRequired;
2242 return false;
2245 // We allow to subscribe to patterns that are broader than the host
2246 // permissions. E.g., we could subscribe to http://www.example.com/*
2247 // while having host permissions for http://www.example.com/foo/* and
2248 // http://www.example.com/bar/*.
2249 // For this reason we do only a coarse check here to warn the extension
2250 // developer if he does something obviously wrong.
2251 if (extension->permissions_data()
2252 ->GetEffectiveHostPermissions()
2253 .is_empty()) {
2254 error_ = keys::kHostPermissionsRequired;
2255 return false;
2259 bool success =
2260 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
2261 profile_id(), extension_id_safe(), extension_name,
2262 event_name, sub_event_name, filter, extra_info_spec,
2263 embedder_process_id, web_view_instance_id, ipc_sender_weak());
2264 EXTENSION_FUNCTION_VALIDATE(success);
2266 helpers::ClearCacheOnNavigation();
2268 if (!extension_id_safe().empty()) {
2269 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
2270 base::Bind(&helpers::NotifyWebRequestAPIUsed,
2271 profile_id(), extension_id_safe()));
2274 return true;
2277 void WebRequestInternalEventHandledFunction::RespondWithError(
2278 const std::string& event_name,
2279 const std::string& sub_event_name,
2280 uint64 request_id,
2281 scoped_ptr<ExtensionWebRequestEventRouter::EventResponse> response,
2282 const std::string& error) {
2283 error_ = error;
2284 ExtensionWebRequestEventRouter::GetInstance()->OnEventHandled(
2285 profile_id(),
2286 extension_id_safe(),
2287 event_name,
2288 sub_event_name,
2289 request_id,
2290 response.release());
2293 bool WebRequestInternalEventHandledFunction::RunSync() {
2294 std::string event_name;
2295 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &event_name));
2297 std::string sub_event_name;
2298 EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &sub_event_name));
2300 std::string request_id_str;
2301 EXTENSION_FUNCTION_VALIDATE(args_->GetString(2, &request_id_str));
2302 uint64 request_id;
2303 EXTENSION_FUNCTION_VALIDATE(base::StringToUint64(request_id_str,
2304 &request_id));
2306 scoped_ptr<ExtensionWebRequestEventRouter::EventResponse> response;
2307 if (HasOptionalArgument(3)) {
2308 base::DictionaryValue* value = NULL;
2309 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(3, &value));
2311 if (!value->empty()) {
2312 base::Time install_time =
2313 extension_info_map()->GetInstallTime(extension_id_safe());
2314 response.reset(new ExtensionWebRequestEventRouter::EventResponse(
2315 extension_id_safe(), install_time));
2318 if (value->HasKey("cancel")) {
2319 // Don't allow cancel mixed with other keys.
2320 if (value->size() != 1) {
2321 RespondWithError(event_name,
2322 sub_event_name,
2323 request_id,
2324 response.Pass(),
2325 keys::kInvalidBlockingResponse);
2326 return false;
2329 bool cancel = false;
2330 EXTENSION_FUNCTION_VALIDATE(value->GetBoolean("cancel", &cancel));
2331 response->cancel = cancel;
2334 if (value->HasKey("redirectUrl")) {
2335 std::string new_url_str;
2336 EXTENSION_FUNCTION_VALIDATE(value->GetString("redirectUrl",
2337 &new_url_str));
2338 response->new_url = GURL(new_url_str);
2339 if (!response->new_url.is_valid()) {
2340 RespondWithError(event_name,
2341 sub_event_name,
2342 request_id,
2343 response.Pass(),
2344 ErrorUtils::FormatErrorMessage(
2345 keys::kInvalidRedirectUrl, new_url_str));
2346 return false;
2350 const bool hasRequestHeaders = value->HasKey("requestHeaders");
2351 const bool hasResponseHeaders = value->HasKey("responseHeaders");
2352 if (hasRequestHeaders || hasResponseHeaders) {
2353 if (hasRequestHeaders && hasResponseHeaders) {
2354 // Allow only one of the keys, not both.
2355 RespondWithError(event_name,
2356 sub_event_name,
2357 request_id,
2358 response.Pass(),
2359 keys::kInvalidHeaderKeyCombination);
2360 return false;
2363 base::ListValue* headers_value = NULL;
2364 scoped_ptr<net::HttpRequestHeaders> request_headers;
2365 scoped_ptr<helpers::ResponseHeaders> response_headers;
2366 if (hasRequestHeaders) {
2367 request_headers.reset(new net::HttpRequestHeaders());
2368 EXTENSION_FUNCTION_VALIDATE(value->GetList(keys::kRequestHeadersKey,
2369 &headers_value));
2370 } else {
2371 response_headers.reset(new helpers::ResponseHeaders());
2372 EXTENSION_FUNCTION_VALIDATE(value->GetList(keys::kResponseHeadersKey,
2373 &headers_value));
2376 for (size_t i = 0; i < headers_value->GetSize(); ++i) {
2377 base::DictionaryValue* header_value = NULL;
2378 std::string name;
2379 std::string value;
2380 EXTENSION_FUNCTION_VALIDATE(
2381 headers_value->GetDictionary(i, &header_value));
2382 if (!FromHeaderDictionary(header_value, &name, &value)) {
2383 std::string serialized_header;
2384 base::JSONWriter::Write(header_value, &serialized_header);
2385 RespondWithError(event_name,
2386 sub_event_name,
2387 request_id,
2388 response.Pass(),
2389 ErrorUtils::FormatErrorMessage(keys::kInvalidHeader,
2390 serialized_header));
2391 return false;
2393 if (!net::HttpUtil::IsValidHeaderName(name)) {
2394 RespondWithError(event_name,
2395 sub_event_name,
2396 request_id,
2397 response.Pass(),
2398 keys::kInvalidHeaderName);
2399 return false;
2401 if (!net::HttpUtil::IsValidHeaderValue(value)) {
2402 RespondWithError(event_name,
2403 sub_event_name,
2404 request_id,
2405 response.Pass(),
2406 ErrorUtils::FormatErrorMessage(
2407 keys::kInvalidHeaderValue, name));
2408 return false;
2410 if (hasRequestHeaders)
2411 request_headers->SetHeader(name, value);
2412 else
2413 response_headers->push_back(helpers::ResponseHeader(name, value));
2415 if (hasRequestHeaders)
2416 response->request_headers.reset(request_headers.release());
2417 else
2418 response->response_headers.reset(response_headers.release());
2421 if (value->HasKey(keys::kAuthCredentialsKey)) {
2422 base::DictionaryValue* credentials_value = NULL;
2423 EXTENSION_FUNCTION_VALIDATE(value->GetDictionary(
2424 keys::kAuthCredentialsKey,
2425 &credentials_value));
2426 base::string16 username;
2427 base::string16 password;
2428 EXTENSION_FUNCTION_VALIDATE(
2429 credentials_value->GetString(keys::kUsernameKey, &username));
2430 EXTENSION_FUNCTION_VALIDATE(
2431 credentials_value->GetString(keys::kPasswordKey, &password));
2432 response->auth_credentials.reset(
2433 new net::AuthCredentials(username, password));
2437 ExtensionWebRequestEventRouter::GetInstance()->OnEventHandled(
2438 profile_id(), extension_id_safe(), event_name, sub_event_name, request_id,
2439 response.release());
2441 return true;
2444 void WebRequestHandlerBehaviorChangedFunction::GetQuotaLimitHeuristics(
2445 extensions::QuotaLimitHeuristics* heuristics) const {
2446 extensions::QuotaLimitHeuristic::Config config = {
2447 // See web_request.json for current value.
2448 web_request::MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES,
2449 base::TimeDelta::FromMinutes(10)};
2450 extensions::QuotaLimitHeuristic::BucketMapper* bucket_mapper =
2451 new extensions::QuotaLimitHeuristic::SingletonBucketMapper();
2452 ClearCacheQuotaHeuristic* heuristic =
2453 new ClearCacheQuotaHeuristic(config, bucket_mapper);
2454 heuristics->push_back(heuristic);
2457 void WebRequestHandlerBehaviorChangedFunction::OnQuotaExceeded(
2458 const std::string& violation_error) {
2459 // Post warning message.
2460 WarningSet warnings;
2461 warnings.insert(
2462 Warning::CreateRepeatedCacheFlushesWarning(extension_id_safe()));
2463 BrowserThread::PostTask(
2464 BrowserThread::UI,
2465 FROM_HERE,
2466 base::Bind(&WarningService::NotifyWarningsOnUI, profile_id(), warnings));
2468 // Continue gracefully.
2469 RunSync();
2472 bool WebRequestHandlerBehaviorChangedFunction::RunSync() {
2473 helpers::ClearCacheOnNavigation();
2474 return true;