Revert "Fix broken channel icon in chrome://help on CrOS" and try again
[chromium-blink-merge.git] / extensions / browser / api / web_request / web_request_api.cc
blob0aaa4fad49fdd99661c424b454038001ed5c9ec3
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/macros.h"
14 #include "base/metrics/histogram.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "base/strings/string_util.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "base/time/time.h"
19 #include "base/values.h"
20 #include "content/public/browser/browser_message_filter.h"
21 #include "content/public/browser/browser_thread.h"
22 #include "content/public/browser/render_frame_host.h"
23 #include "content/public/browser/render_process_host.h"
24 #include "content/public/browser/resource_request_info.h"
25 #include "content/public/browser/user_metrics.h"
26 #include "extensions/browser/api/activity_log/web_request_constants.h"
27 #include "extensions/browser/api/declarative/rules_registry_service.h"
28 #include "extensions/browser/api/declarative_webrequest/request_stage.h"
29 #include "extensions/browser/api/declarative_webrequest/webrequest_constants.h"
30 #include "extensions/browser/api/declarative_webrequest/webrequest_rules_registry.h"
31 #include "extensions/browser/api/extensions_api_client.h"
32 #include "extensions/browser/api/web_request/upload_data_presenter.h"
33 #include "extensions/browser/api/web_request/web_request_api_constants.h"
34 #include "extensions/browser/api/web_request/web_request_api_helpers.h"
35 #include "extensions/browser/api/web_request/web_request_event_router_delegate.h"
36 #include "extensions/browser/api/web_request/web_request_time_tracker.h"
37 #include "extensions/browser/event_router.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/guest_view_events.h"
43 #include "extensions/browser/guest_view/web_view/web_view_constants.h"
44 #include "extensions/browser/guest_view/web_view/web_view_renderer_state.h"
45 #include "extensions/browser/info_map.h"
46 #include "extensions/browser/io_thread_extension_message_filter.h"
47 #include "extensions/browser/runtime_data.h"
48 #include "extensions/browser/warning_service.h"
49 #include "extensions/browser/warning_set.h"
50 #include "extensions/common/api/web_request.h"
51 #include "extensions/common/error_utils.h"
52 #include "extensions/common/event_filtering_info.h"
53 #include "extensions/common/extension.h"
54 #include "extensions/common/features/feature.h"
55 #include "extensions/common/permissions/permissions_data.h"
56 #include "extensions/common/url_pattern.h"
57 #include "extensions/strings/grit/extensions_strings.h"
58 #include "net/base/auth.h"
59 #include "net/base/net_errors.h"
60 #include "net/base/upload_data_stream.h"
61 #include "net/http/http_response_headers.h"
62 #include "net/http/http_util.h"
63 #include "net/url_request/url_request.h"
64 #include "ui/base/l10n/l10n_util.h"
65 #include "url/gurl.h"
67 using base::DictionaryValue;
68 using base::ListValue;
69 using base::StringValue;
70 using content::BrowserMessageFilter;
71 using content::BrowserThread;
72 using content::ResourceRequestInfo;
73 using content::ResourceType;
75 namespace activity_log = activity_log_web_request_constants;
76 namespace helpers = extension_web_request_api_helpers;
77 namespace keys = extension_web_request_api_constants;
79 namespace extensions {
81 namespace declarative_keys = declarative_webrequest_constants;
82 namespace web_request = api::web_request;
84 namespace {
86 const char kWebRequestEventPrefix[] = "webRequest.";
88 // List of all the webRequest events.
89 const char* const kWebRequestEvents[] = {
90 keys::kOnBeforeRedirectEvent,
91 web_request::OnBeforeRequest::kEventName,
92 keys::kOnBeforeSendHeadersEvent,
93 keys::kOnCompletedEvent,
94 web_request::OnErrorOccurred::kEventName,
95 keys::kOnSendHeadersEvent,
96 keys::kOnAuthRequiredEvent,
97 keys::kOnResponseStartedEvent,
98 keys::kOnHeadersReceivedEvent,
101 const char* GetRequestStageAsString(
102 ExtensionWebRequestEventRouter::EventTypes type) {
103 switch (type) {
104 case ExtensionWebRequestEventRouter::kInvalidEvent:
105 return "Invalid";
106 case ExtensionWebRequestEventRouter::kOnBeforeRequest:
107 return keys::kOnBeforeRequest;
108 case ExtensionWebRequestEventRouter::kOnBeforeSendHeaders:
109 return keys::kOnBeforeSendHeaders;
110 case ExtensionWebRequestEventRouter::kOnSendHeaders:
111 return keys::kOnSendHeaders;
112 case ExtensionWebRequestEventRouter::kOnHeadersReceived:
113 return keys::kOnHeadersReceived;
114 case ExtensionWebRequestEventRouter::kOnBeforeRedirect:
115 return keys::kOnBeforeRedirect;
116 case ExtensionWebRequestEventRouter::kOnAuthRequired:
117 return keys::kOnAuthRequired;
118 case ExtensionWebRequestEventRouter::kOnResponseStarted:
119 return keys::kOnResponseStarted;
120 case ExtensionWebRequestEventRouter::kOnErrorOccurred:
121 return keys::kOnErrorOccurred;
122 case ExtensionWebRequestEventRouter::kOnCompleted:
123 return keys::kOnCompleted;
125 NOTREACHED();
126 return "Not reached";
129 int GetFrameId(bool is_main_frame, int frame_id) {
130 return is_main_frame ? 0 : frame_id;
133 bool IsWebRequestEvent(const std::string& event_name) {
134 std::string web_request_event_name(event_name);
135 if (base::StartsWith(web_request_event_name,
136 webview::kWebViewEventPrefix,
137 base::CompareCase::SENSITIVE)) {
138 web_request_event_name.replace(
139 0, strlen(webview::kWebViewEventPrefix), kWebRequestEventPrefix);
141 const auto web_request_events_end =
142 kWebRequestEvents + arraysize(kWebRequestEvents);
143 return std::find(kWebRequestEvents, web_request_events_end,
144 web_request_event_name) != web_request_events_end;
147 // Returns whether |request| has been triggered by an extension in
148 // |extension_info_map|.
149 bool IsRequestFromExtension(const net::URLRequest* request,
150 const InfoMap* extension_info_map) {
151 // |extension_info_map| is NULL for system-level requests.
152 if (!extension_info_map)
153 return false;
155 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
157 // If this request was not created by the ResourceDispatcher, |info| is NULL.
158 // All requests from extensions are created by the ResourceDispatcher.
159 if (!info)
160 return false;
162 return extension_info_map->process_map().Contains(info->GetChildID());
165 void ExtractRequestRoutingInfo(const net::URLRequest* request,
166 int* render_process_host_id,
167 int* routing_id) {
168 if (!request->GetUserData(NULL))
169 return;
170 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
171 *render_process_host_id = info->GetChildID();
172 *routing_id = info->GetRouteID();
175 // Given a |request|, this function determines whether it originated from
176 // a <webview> guest process or not. If it is from a <webview> guest process,
177 // then |web_view_info| is returned with information about the instance ID
178 // that uniquely identifies the <webview> and its embedder.
179 bool GetWebViewInfo(const net::URLRequest* request,
180 WebViewRendererState::WebViewInfo* web_view_info) {
181 int render_process_host_id = -1;
182 int routing_id = -1;
183 ExtractRequestRoutingInfo(request, &render_process_host_id, &routing_id);
184 return WebViewRendererState::GetInstance()->GetInfo(
185 render_process_host_id, routing_id, web_view_info);
188 void ExtractRequestInfoDetails(const net::URLRequest* request,
189 bool* is_main_frame,
190 int* frame_id,
191 bool* parent_is_main_frame,
192 int* parent_frame_id,
193 int* render_process_host_id,
194 int* routing_id,
195 ResourceType* resource_type) {
196 if (!request->GetUserData(NULL))
197 return;
199 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
200 *frame_id = info->GetRenderFrameID();
201 *is_main_frame = info->IsMainFrame();
202 *parent_frame_id = info->GetParentRenderFrameID();
203 *parent_is_main_frame = info->ParentIsMainFrame();
204 *render_process_host_id = info->GetChildID();
205 *routing_id = info->GetRouteID();
207 // Restrict the resource type to the values we care about.
208 if (helpers::IsRelevantResourceType(info->GetResourceType()))
209 *resource_type = info->GetResourceType();
210 else
211 *resource_type = content::RESOURCE_TYPE_LAST_TYPE;
214 // Extracts the body from |request| and writes the data into |out|.
215 void ExtractRequestInfoBody(const net::URLRequest* request,
216 base::DictionaryValue* out) {
217 const net::UploadDataStream* upload_data = request->get_upload();
218 if (!upload_data ||
219 (request->method() != "POST" && request->method() != "PUT")) {
220 return; // Need to exit without "out->Set(keys::kRequestBodyKey, ...);" .
223 base::DictionaryValue* request_body = new base::DictionaryValue();
224 out->Set(keys::kRequestBodyKey, request_body);
226 // Get the data presenters, ordered by how specific they are.
227 ParsedDataPresenter parsed_data_presenter(*request);
228 RawDataPresenter raw_data_presenter;
229 UploadDataPresenter* const presenters[] = {
230 &parsed_data_presenter, // 1: any parseable forms? (Specific to forms.)
231 &raw_data_presenter // 2: any data at all? (Non-specific.)
233 // Keys for the results of the corresponding presenters.
234 static const char* const kKeys[] = {
235 keys::kRequestBodyFormDataKey,
236 keys::kRequestBodyRawKey
239 const ScopedVector<net::UploadElementReader>* readers =
240 upload_data->GetElementReaders();
241 bool some_succeeded = false;
242 if (readers) {
243 for (size_t i = 0; i < arraysize(presenters); ++i) {
244 for (const auto& reader : *readers)
245 presenters[i]->FeedNext(*reader);
246 if (presenters[i]->Succeeded()) {
247 request_body->Set(kKeys[i], presenters[i]->Result().release());
248 some_succeeded = true;
249 break;
253 if (!some_succeeded)
254 request_body->SetString(keys::kRequestBodyErrorKey, "Unknown error.");
257 // Converts a HttpHeaders dictionary to a |name|, |value| pair. Returns
258 // true if successful.
259 bool FromHeaderDictionary(const base::DictionaryValue* header_value,
260 std::string* name,
261 std::string* value) {
262 if (!header_value->GetString(keys::kHeaderNameKey, name))
263 return false;
265 // We require either a "value" or a "binaryValue" entry.
266 if (!(header_value->HasKey(keys::kHeaderValueKey) ^
267 header_value->HasKey(keys::kHeaderBinaryValueKey))) {
268 return false;
271 if (header_value->HasKey(keys::kHeaderValueKey)) {
272 if (!header_value->GetString(keys::kHeaderValueKey, value)) {
273 return false;
275 } else if (header_value->HasKey(keys::kHeaderBinaryValueKey)) {
276 const base::ListValue* list = NULL;
277 if (!header_value->HasKey(keys::kHeaderBinaryValueKey)) {
278 *value = "";
279 } else if (!header_value->GetList(keys::kHeaderBinaryValueKey, &list) ||
280 !helpers::CharListToString(list, value)) {
281 return false;
284 return true;
287 // Creates a list of HttpHeaders (see the extension API JSON). If |headers| is
288 // NULL, the list is empty. Ownership is passed to the caller.
289 base::ListValue* GetResponseHeadersList(
290 const net::HttpResponseHeaders* headers) {
291 base::ListValue* headers_value = new base::ListValue();
292 if (headers) {
293 void* iter = NULL;
294 std::string name;
295 std::string value;
296 while (headers->EnumerateHeaderLines(&iter, &name, &value))
297 headers_value->Append(helpers::CreateHeaderDictionary(name, value));
299 return headers_value;
302 base::ListValue* GetRequestHeadersList(const net::HttpRequestHeaders& headers) {
303 base::ListValue* headers_value = new base::ListValue();
304 for (net::HttpRequestHeaders::Iterator it(headers); it.GetNext(); )
305 headers_value->Append(
306 helpers::CreateHeaderDictionary(it.name(), it.value()));
307 return headers_value;
310 // Creates a base::StringValue with the status line of |headers|. If |headers|
311 // is NULL, an empty string is returned. Ownership is passed to the caller.
312 base::StringValue* GetStatusLine(net::HttpResponseHeaders* headers) {
313 return new base::StringValue(
314 headers ? headers->GetStatusLine() : std::string());
317 // Returns the response code from the response headers, or 200 by default.
318 // |headers| may be NULL, e.g. UrlRequestFileJobs do not send headers, so
319 // simulate their behavior.
320 int GetResponseCodeWithDefault(net::HttpResponseHeaders* headers) {
321 return headers ? headers->response_code() : 200;
324 // Sends an event to subscribers of chrome.declarativeWebRequest.onMessage or
325 // to subscribers of webview.onMessage if the action is being operated upon
326 // a <webview> guest renderer.
327 // |extension_id| identifies the extension that sends and receives the event.
328 // |is_web_view_guest| indicates whether the action is for a <webview>.
329 // |web_view_info| is a struct containing information about the <webview>
330 // embedder.
331 // |event_argument| is passed to the event listener.
332 void SendOnMessageEventOnUI(
333 void* browser_context_id,
334 const std::string& extension_id,
335 bool is_web_view_guest,
336 const WebViewRendererState::WebViewInfo& web_view_info,
337 scoped_ptr<base::DictionaryValue> event_argument) {
338 DCHECK_CURRENTLY_ON(BrowserThread::UI);
340 content::BrowserContext* browser_context =
341 reinterpret_cast<content::BrowserContext*>(browser_context_id);
342 if (!ExtensionsBrowserClient::Get()->IsValidContext(browser_context))
343 return;
345 scoped_ptr<base::ListValue> event_args(new base::ListValue);
346 event_args->Append(event_argument.release());
348 EventRouter* event_router = EventRouter::Get(browser_context);
350 EventFilteringInfo event_filtering_info;
352 events::HistogramValue histogram_value = events::UNKNOWN;
353 std::string event_name;
354 // The instance ID uniquely identifies a <webview> instance within an embedder
355 // process. We use a filter here so that only event listeners for a particular
356 // <webview> will fire.
357 if (is_web_view_guest) {
358 event_filtering_info.SetInstanceID(web_view_info.instance_id);
359 histogram_value = events::WEB_VIEW_INTERNAL_ON_MESSAGE;
360 event_name = webview::kEventMessage;
361 } else {
362 histogram_value = events::DECLARATIVE_WEB_REQUEST_ON_MESSAGE;
363 event_name = declarative_keys::kOnMessage;
366 scoped_ptr<Event> event(new Event(
367 histogram_value, event_name, event_args.Pass(), browser_context, GURL(),
368 EventRouter::USER_GESTURE_UNKNOWN, event_filtering_info));
369 event_router->DispatchEventToExtension(extension_id, event.Pass());
372 void RemoveEventListenerOnIOThread(
373 void* browser_context,
374 const std::string& extension_id,
375 const std::string& sub_event_name,
376 int embedder_process_id,
377 int web_view_instance_id) {
378 DCHECK_CURRENTLY_ON(BrowserThread::IO);
379 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(
380 browser_context, extension_id, sub_event_name,
381 embedder_process_id, web_view_instance_id);
384 events::HistogramValue GetEventHistogramValue(const std::string& event_name) {
385 // Event names will either be webRequest events, or guest view (probably web
386 // view) events that map to webRequest events. Check webRequest first.
387 static struct ValueAndName {
388 events::HistogramValue histogram_value;
389 const char* const event_name;
390 } values_and_names[] = {
391 {events::WEB_REQUEST_ON_BEFORE_REDIRECT, keys::kOnBeforeRedirectEvent},
392 {events::WEB_REQUEST_ON_BEFORE_REQUEST,
393 web_request::OnBeforeRequest::kEventName},
394 {events::WEB_REQUEST_ON_BEFORE_SEND_HEADERS,
395 keys::kOnBeforeSendHeadersEvent},
396 {events::WEB_REQUEST_ON_COMPLETED, keys::kOnCompletedEvent},
397 {events::WEB_REQUEST_ON_ERROR_OCCURRED,
398 web_request::OnErrorOccurred::kEventName},
399 {events::WEB_REQUEST_ON_SEND_HEADERS, keys::kOnSendHeadersEvent},
400 {events::WEB_REQUEST_ON_AUTH_REQUIRED, keys::kOnAuthRequiredEvent},
401 {events::WEB_REQUEST_ON_RESPONSE_STARTED, keys::kOnResponseStartedEvent},
402 {events::WEB_REQUEST_ON_HEADERS_RECEIVED, keys::kOnHeadersReceivedEvent}};
403 COMPILE_ASSERT(arraysize(kWebRequestEvents) == arraysize(values_and_names),
404 "kWebRequestEvents and values_and_names must be the same");
405 for (const ValueAndName& value_and_name : values_and_names) {
406 if (value_and_name.event_name == event_name)
407 return value_and_name.histogram_value;
410 // If there is no webRequest event, it might be a guest view webRequest event.
411 events::HistogramValue guest_view_histogram_value =
412 guest_view_events::GetEventHistogramValue(event_name);
413 if (guest_view_histogram_value != events::UNKNOWN)
414 return guest_view_histogram_value;
416 // There is no histogram value for this event name. It should be added to
417 // either the mapping here, or in guest_view_events.
418 NOTREACHED() << "Event " << event_name << " must have a histogram value";
419 return events::UNKNOWN;
422 // We hide events from the system context as well as sensitive requests.
423 bool ShouldHideEvent(void* browser_context,
424 const InfoMap* extension_info_map,
425 const net::URLRequest* request) {
426 return (!browser_context ||
427 WebRequestPermissions::HideRequest(extension_info_map, request));
430 } // namespace
432 WebRequestAPI::WebRequestAPI(content::BrowserContext* context)
433 : browser_context_(context) {
434 EventRouter* event_router = EventRouter::Get(browser_context_);
435 for (size_t i = 0; i < arraysize(kWebRequestEvents); ++i) {
436 // Observe the webRequest event.
437 std::string event_name = kWebRequestEvents[i];
438 event_router->RegisterObserver(this, event_name);
440 // Also observe the corresponding webview event.
441 event_name.replace(
442 0, sizeof(kWebRequestEventPrefix) - 1, webview::kWebViewEventPrefix);
443 event_router->RegisterObserver(this, event_name);
447 WebRequestAPI::~WebRequestAPI() {
448 EventRouter::Get(browser_context_)->UnregisterObserver(this);
451 static base::LazyInstance<BrowserContextKeyedAPIFactory<WebRequestAPI> >
452 g_factory = LAZY_INSTANCE_INITIALIZER;
454 // static
455 BrowserContextKeyedAPIFactory<WebRequestAPI>*
456 WebRequestAPI::GetFactoryInstance() {
457 return g_factory.Pointer();
460 void WebRequestAPI::OnListenerRemoved(const EventListenerInfo& details) {
461 DCHECK_CURRENTLY_ON(BrowserThread::UI);
462 // Note that details.event_name includes the sub-event details (e.g. "/123").
463 // TODO(fsamuel): <webview> events will not be removed through this code path.
464 // <webview> events will be removed in RemoveWebViewEventListeners. Ideally,
465 // this code should be decoupled from extensions, we should use the host ID
466 // instead, and not have two different code paths. This is a huge undertaking
467 // unfortunately, so we'll resort to two code paths for now.
468 BrowserThread::PostTask(BrowserThread::IO,
469 FROM_HERE,
470 base::Bind(&RemoveEventListenerOnIOThread,
471 details.browser_context,
472 details.extension_id,
473 details.event_name,
474 0 /* embedder_process_id (ignored) */,
475 0 /* web_view_instance_id */));
478 // Represents a single unique listener to an event, along with whatever filter
479 // parameters and extra_info_spec were specified at the time the listener was
480 // added.
481 // NOTE(benjhayden) New APIs should not use this sub_event_name trick! It does
482 // not play well with event pages. See downloads.onDeterminingFilename and
483 // ExtensionDownloadsEventRouter for an alternative approach.
484 struct ExtensionWebRequestEventRouter::EventListener {
485 std::string extension_id;
486 std::string extension_name;
487 events::HistogramValue histogram_value;
488 std::string sub_event_name;
489 RequestFilter filter;
490 int extra_info_spec;
491 int embedder_process_id;
492 int web_view_instance_id;
493 base::WeakPtr<IPC::Sender> ipc_sender;
494 mutable std::set<uint64_t> blocked_requests;
496 // Comparator to work with std::set.
497 bool operator<(const EventListener& that) const {
498 if (extension_id != that.extension_id)
499 return extension_id < that.extension_id;
501 if (sub_event_name != that.sub_event_name)
502 return sub_event_name < that.sub_event_name;
504 if (web_view_instance_id != that.web_view_instance_id)
505 return web_view_instance_id < that.web_view_instance_id;
507 if (web_view_instance_id == 0) {
508 // Do not filter by process ID for non-webviews, because this comparator
509 // is also used to find and remove an event listener when an extension is
510 // unloaded. At this point, the event listener cannot be mapped back to
511 // the original process, so 0 is used instead of the actual process ID.
512 DCHECK(embedder_process_id == 0 || that.embedder_process_id == 0);
513 return false;
516 if (embedder_process_id != that.embedder_process_id)
517 return embedder_process_id < that.embedder_process_id;
519 return false;
522 EventListener()
523 : histogram_value(events::UNKNOWN),
524 extra_info_spec(0),
525 embedder_process_id(0),
526 web_view_instance_id(0) {}
529 // Contains info about requests that are blocked waiting for a response from
530 // an extension.
531 struct ExtensionWebRequestEventRouter::BlockedRequest {
532 // The request that is being blocked.
533 net::URLRequest* request;
535 // Whether the request originates from an incognito tab.
536 bool is_incognito;
538 // The event that we're currently blocked on.
539 EventTypes event;
541 // The number of event handlers that we are awaiting a response from.
542 int num_handlers_blocking;
544 // Pointer to NetLog to report significant changes to the request for
545 // debugging.
546 const net::BoundNetLog* net_log;
548 // The callback to call when we get a response from all event handlers.
549 net::CompletionCallback callback;
551 // If non-empty, this contains the new URL that the request will redirect to.
552 // Only valid for OnBeforeRequest and OnHeadersReceived.
553 GURL* new_url;
555 // The request headers that will be issued along with this request. Only valid
556 // for OnBeforeSendHeaders.
557 net::HttpRequestHeaders* request_headers;
559 // The response headers that were received from the server. Only valid for
560 // OnHeadersReceived.
561 scoped_refptr<const net::HttpResponseHeaders> original_response_headers;
563 // Location where to override response headers. Only valid for
564 // OnHeadersReceived.
565 scoped_refptr<net::HttpResponseHeaders>* override_response_headers;
567 // If non-empty, this contains the auth credentials that may be filled in.
568 // Only valid for OnAuthRequired.
569 net::AuthCredentials* auth_credentials;
571 // The callback to invoke for auth. If |auth_callback.is_null()| is false,
572 // |callback| must be NULL.
573 // Only valid for OnAuthRequired.
574 net::NetworkDelegate::AuthCallback auth_callback;
576 // Time the request was paused. Used for logging purposes.
577 base::Time blocking_time;
579 // Changes requested by extensions.
580 helpers::EventResponseDeltas response_deltas;
582 // Provider of meta data about extensions, only used and non-NULL for events
583 // that are delayed until the rules registry is ready.
584 const InfoMap* extension_info_map;
586 BlockedRequest()
587 : request(NULL),
588 is_incognito(false),
589 event(kInvalidEvent),
590 num_handlers_blocking(0),
591 net_log(NULL),
592 new_url(NULL),
593 request_headers(NULL),
594 override_response_headers(NULL),
595 auth_credentials(NULL),
596 extension_info_map(NULL) {}
599 bool ExtensionWebRequestEventRouter::RequestFilter::InitFromValue(
600 const base::DictionaryValue& value, std::string* error) {
601 if (!value.HasKey("urls"))
602 return false;
604 for (base::DictionaryValue::Iterator it(value); !it.IsAtEnd(); it.Advance()) {
605 if (it.key() == "urls") {
606 const base::ListValue* urls_value = NULL;
607 if (!it.value().GetAsList(&urls_value))
608 return false;
609 for (size_t i = 0; i < urls_value->GetSize(); ++i) {
610 std::string url;
611 URLPattern pattern(
612 URLPattern::SCHEME_HTTP | URLPattern::SCHEME_HTTPS |
613 URLPattern::SCHEME_FTP | URLPattern::SCHEME_FILE |
614 URLPattern::SCHEME_EXTENSION);
615 if (!urls_value->GetString(i, &url) ||
616 pattern.Parse(url) != URLPattern::PARSE_SUCCESS) {
617 *error = ErrorUtils::FormatErrorMessage(
618 keys::kInvalidRequestFilterUrl, url);
619 return false;
621 urls.AddPattern(pattern);
623 } else if (it.key() == "types") {
624 const base::ListValue* types_value = NULL;
625 if (!it.value().GetAsList(&types_value))
626 return false;
627 for (size_t i = 0; i < types_value->GetSize(); ++i) {
628 std::string type_str;
629 ResourceType type;
630 if (!types_value->GetString(i, &type_str) ||
631 !helpers::ParseResourceType(type_str, &type)) {
632 return false;
634 types.push_back(type);
636 } else if (it.key() == "tabId") {
637 if (!it.value().GetAsInteger(&tab_id))
638 return false;
639 } else if (it.key() == "windowId") {
640 if (!it.value().GetAsInteger(&window_id))
641 return false;
642 } else {
643 return false;
646 return true;
649 // static
650 bool ExtensionWebRequestEventRouter::ExtraInfoSpec::InitFromValue(
651 const base::ListValue& value, int* extra_info_spec) {
652 *extra_info_spec = 0;
653 for (size_t i = 0; i < value.GetSize(); ++i) {
654 std::string str;
655 if (!value.GetString(i, &str))
656 return false;
658 if (str == "requestHeaders")
659 *extra_info_spec |= REQUEST_HEADERS;
660 else if (str == "responseHeaders")
661 *extra_info_spec |= RESPONSE_HEADERS;
662 else if (str == "blocking")
663 *extra_info_spec |= BLOCKING;
664 else if (str == "asyncBlocking")
665 *extra_info_spec |= ASYNC_BLOCKING;
666 else if (str == "requestBody")
667 *extra_info_spec |= REQUEST_BODY;
668 else
669 return false;
671 // BLOCKING and ASYNC_BLOCKING are mutually exclusive.
672 if ((*extra_info_spec & BLOCKING) && (*extra_info_spec & ASYNC_BLOCKING))
673 return false;
675 return true;
679 ExtensionWebRequestEventRouter::EventResponse::EventResponse(
680 const std::string& extension_id, const base::Time& extension_install_time)
681 : extension_id(extension_id),
682 extension_install_time(extension_install_time),
683 cancel(false) {
686 ExtensionWebRequestEventRouter::EventResponse::~EventResponse() {
689 ExtensionWebRequestEventRouter::RequestFilter::RequestFilter()
690 : tab_id(-1), window_id(-1) {
693 ExtensionWebRequestEventRouter::RequestFilter::~RequestFilter() {
697 // ExtensionWebRequestEventRouter
700 // static
701 ExtensionWebRequestEventRouter* ExtensionWebRequestEventRouter::GetInstance() {
702 return Singleton<ExtensionWebRequestEventRouter>::get();
705 ExtensionWebRequestEventRouter::ExtensionWebRequestEventRouter()
706 : request_time_tracker_(new ExtensionWebRequestTimeTracker) {
707 web_request_event_router_delegate_.reset(
708 ExtensionsAPIClient::Get()->CreateWebRequestEventRouterDelegate());
711 ExtensionWebRequestEventRouter::~ExtensionWebRequestEventRouter() {
714 void ExtensionWebRequestEventRouter::RegisterRulesRegistry(
715 void* browser_context,
716 int rules_registry_id,
717 scoped_refptr<WebRequestRulesRegistry> rules_registry) {
718 RulesRegistryKey key(browser_context, rules_registry_id);
719 if (rules_registry.get())
720 rules_registries_[key] = rules_registry;
721 else
722 rules_registries_.erase(key);
725 void ExtensionWebRequestEventRouter::ExtractRequestInfo(
726 const net::URLRequest* request,
727 base::DictionaryValue* out) {
728 bool is_main_frame = false;
729 int frame_id = -1;
730 bool parent_is_main_frame = false;
731 int parent_frame_id = -1;
732 int frame_id_for_extension = -1;
733 int parent_frame_id_for_extension = -1;
734 int render_process_host_id = -1;
735 int routing_id = -1;
736 ResourceType resource_type = content::RESOURCE_TYPE_LAST_TYPE;
737 ExtractRequestInfoDetails(request, &is_main_frame, &frame_id,
738 &parent_is_main_frame, &parent_frame_id,
739 &render_process_host_id, &routing_id,
740 &resource_type);
741 frame_id_for_extension = GetFrameId(is_main_frame, frame_id);
742 parent_frame_id_for_extension = GetFrameId(parent_is_main_frame,
743 parent_frame_id);
745 out->SetString(keys::kRequestIdKey,
746 base::Uint64ToString(request->identifier()));
747 out->SetString(keys::kUrlKey, request->url().spec());
748 out->SetString(keys::kMethodKey, request->method());
749 out->SetInteger(keys::kFrameIdKey, frame_id_for_extension);
750 out->SetInteger(keys::kParentFrameIdKey, parent_frame_id_for_extension);
751 out->SetString(keys::kTypeKey, helpers::ResourceTypeToString(resource_type));
752 out->SetDouble(keys::kTimeStampKey, base::Time::Now().ToDoubleT() * 1000);
753 if (web_request_event_router_delegate_) {
754 web_request_event_router_delegate_->ExtractExtraRequestDetails(
755 request, out);
759 int ExtensionWebRequestEventRouter::OnBeforeRequest(
760 void* browser_context,
761 const InfoMap* extension_info_map,
762 net::URLRequest* request,
763 const net::CompletionCallback& callback,
764 GURL* new_url) {
765 if (ShouldHideEvent(browser_context, extension_info_map, request))
766 return net::OK;
768 if (IsPageLoad(request))
769 NotifyPageLoad();
771 request_time_tracker_->LogRequestStartTime(request->identifier(),
772 base::Time::Now(),
773 request->url(),
774 browser_context);
776 // Whether to initialized |blocked_requests_|.
777 bool initialize_blocked_requests = false;
779 initialize_blocked_requests |=
780 ProcessDeclarativeRules(browser_context, extension_info_map,
781 web_request::OnBeforeRequest::kEventName, request,
782 ON_BEFORE_REQUEST, NULL);
784 int extra_info_spec = 0;
785 EventListeners listeners = GetMatchingListeners(
786 browser_context, extension_info_map,
787 web_request::OnBeforeRequest::kEventName, request, &extra_info_spec);
788 if (!listeners.empty() &&
789 !GetAndSetSignaled(request->identifier(), kOnBeforeRequest)) {
790 base::ListValue args;
791 base::DictionaryValue* dict = new base::DictionaryValue();
792 ExtractRequestInfo(request, dict);
793 if (extra_info_spec & ExtraInfoSpec::REQUEST_BODY)
794 ExtractRequestInfoBody(request, dict);
795 args.Append(dict);
797 initialize_blocked_requests |=
798 DispatchEvent(browser_context, request, listeners, args);
801 if (!initialize_blocked_requests)
802 return net::OK; // Nobody saw a reason for modifying the request.
804 BlockedRequest& blocked_request = blocked_requests_[request->identifier()];
805 blocked_request.event = kOnBeforeRequest;
806 blocked_request.is_incognito |= IsIncognitoBrowserContext(browser_context);
807 blocked_request.request = request;
808 blocked_request.callback = callback;
809 blocked_request.new_url = new_url;
810 blocked_request.net_log = &request->net_log();
812 if (blocked_request.num_handlers_blocking == 0) {
813 // If there are no blocking handlers, only the declarative rules tried
814 // to modify the request and we can respond synchronously.
815 return ExecuteDeltas(browser_context, request->identifier(),
816 false /* call_callback*/);
818 return net::ERR_IO_PENDING;
821 int ExtensionWebRequestEventRouter::OnBeforeSendHeaders(
822 void* browser_context,
823 const InfoMap* extension_info_map,
824 net::URLRequest* request,
825 const net::CompletionCallback& callback,
826 net::HttpRequestHeaders* headers) {
827 if (ShouldHideEvent(browser_context, extension_info_map, request))
828 return net::OK;
830 bool initialize_blocked_requests = false;
832 initialize_blocked_requests |= ProcessDeclarativeRules(
833 browser_context, extension_info_map, keys::kOnBeforeSendHeadersEvent,
834 request, ON_BEFORE_SEND_HEADERS, NULL);
836 int extra_info_spec = 0;
837 EventListeners listeners = GetMatchingListeners(
838 browser_context, extension_info_map, keys::kOnBeforeSendHeadersEvent,
839 request, &extra_info_spec);
840 if (!listeners.empty() &&
841 !GetAndSetSignaled(request->identifier(), kOnBeforeSendHeaders)) {
842 base::ListValue args;
843 base::DictionaryValue* dict = new base::DictionaryValue();
844 ExtractRequestInfo(request, dict);
845 if (extra_info_spec & ExtraInfoSpec::REQUEST_HEADERS)
846 dict->Set(keys::kRequestHeadersKey, GetRequestHeadersList(*headers));
847 args.Append(dict);
849 initialize_blocked_requests |=
850 DispatchEvent(browser_context, request, listeners, args);
853 if (!initialize_blocked_requests)
854 return net::OK; // Nobody saw a reason for modifying the request.
856 BlockedRequest& blocked_request = blocked_requests_[request->identifier()];
857 blocked_request.event = kOnBeforeSendHeaders;
858 blocked_request.is_incognito |= IsIncognitoBrowserContext(browser_context);
859 blocked_request.request = request;
860 blocked_request.callback = callback;
861 blocked_request.request_headers = headers;
862 blocked_request.net_log = &request->net_log();
864 if (blocked_request.num_handlers_blocking == 0) {
865 // If there are no blocking handlers, only the declarative rules tried
866 // to modify the request and we can respond synchronously.
867 return ExecuteDeltas(browser_context, request->identifier(),
868 false /* call_callback*/);
870 return net::ERR_IO_PENDING;
873 void ExtensionWebRequestEventRouter::OnSendHeaders(
874 void* browser_context,
875 const InfoMap* extension_info_map,
876 net::URLRequest* request,
877 const net::HttpRequestHeaders& headers) {
878 if (ShouldHideEvent(browser_context, extension_info_map, request))
879 return;
881 if (GetAndSetSignaled(request->identifier(), kOnSendHeaders))
882 return;
884 ClearSignaled(request->identifier(), kOnBeforeRedirect);
886 int extra_info_spec = 0;
887 EventListeners listeners = GetMatchingListeners(
888 browser_context, extension_info_map, keys::kOnSendHeadersEvent, request,
889 &extra_info_spec);
890 if (listeners.empty())
891 return;
893 base::ListValue args;
894 base::DictionaryValue* dict = new base::DictionaryValue();
895 ExtractRequestInfo(request, dict);
896 if (extra_info_spec & ExtraInfoSpec::REQUEST_HEADERS)
897 dict->Set(keys::kRequestHeadersKey, GetRequestHeadersList(headers));
898 args.Append(dict);
900 DispatchEvent(browser_context, request, listeners, args);
903 int ExtensionWebRequestEventRouter::OnHeadersReceived(
904 void* browser_context,
905 const InfoMap* extension_info_map,
906 net::URLRequest* request,
907 const net::CompletionCallback& callback,
908 const net::HttpResponseHeaders* original_response_headers,
909 scoped_refptr<net::HttpResponseHeaders>* override_response_headers,
910 GURL* allowed_unsafe_redirect_url) {
911 if (ShouldHideEvent(browser_context, extension_info_map, request))
912 return net::OK;
914 bool initialize_blocked_requests = false;
916 initialize_blocked_requests |= ProcessDeclarativeRules(
917 browser_context, extension_info_map, keys::kOnHeadersReceivedEvent,
918 request, ON_HEADERS_RECEIVED, original_response_headers);
920 int extra_info_spec = 0;
921 EventListeners listeners = GetMatchingListeners(
922 browser_context, extension_info_map, keys::kOnHeadersReceivedEvent,
923 request, &extra_info_spec);
925 if (!listeners.empty() &&
926 !GetAndSetSignaled(request->identifier(), kOnHeadersReceived)) {
927 base::ListValue args;
928 base::DictionaryValue* dict = new base::DictionaryValue();
929 ExtractRequestInfo(request, dict);
930 dict->SetString(keys::kStatusLineKey,
931 original_response_headers->GetStatusLine());
932 dict->SetInteger(keys::kStatusCodeKey,
933 original_response_headers->response_code());
934 if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
935 dict->Set(keys::kResponseHeadersKey,
936 GetResponseHeadersList(original_response_headers));
938 args.Append(dict);
940 initialize_blocked_requests |=
941 DispatchEvent(browser_context, request, listeners, args);
944 if (!initialize_blocked_requests)
945 return net::OK; // Nobody saw a reason for modifying the request.
947 BlockedRequest& blocked_request = blocked_requests_[request->identifier()];
948 blocked_request.event = kOnHeadersReceived;
949 blocked_request.is_incognito |= IsIncognitoBrowserContext(browser_context);
950 blocked_request.request = request;
951 blocked_request.callback = callback;
952 blocked_request.net_log = &request->net_log();
953 blocked_request.override_response_headers = override_response_headers;
954 blocked_request.original_response_headers = original_response_headers;
955 blocked_request.new_url = allowed_unsafe_redirect_url;
957 if (blocked_request.num_handlers_blocking == 0) {
958 // If there are no blocking handlers, only the declarative rules tried
959 // to modify the request and we can respond synchronously.
960 return ExecuteDeltas(browser_context, request->identifier(),
961 false /* call_callback*/);
963 return net::ERR_IO_PENDING;
966 net::NetworkDelegate::AuthRequiredResponse
967 ExtensionWebRequestEventRouter::OnAuthRequired(
968 void* browser_context,
969 const InfoMap* extension_info_map,
970 net::URLRequest* request,
971 const net::AuthChallengeInfo& auth_info,
972 const net::NetworkDelegate::AuthCallback& callback,
973 net::AuthCredentials* credentials) {
974 // No browser_context means that this is for authentication challenges in the
975 // system context. Skip in that case. Also skip sensitive requests.
976 if (!browser_context ||
977 WebRequestPermissions::HideRequest(extension_info_map, request)) {
978 return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION;
981 int extra_info_spec = 0;
982 EventListeners listeners = GetMatchingListeners(
983 browser_context, extension_info_map, keys::kOnAuthRequiredEvent, request,
984 &extra_info_spec);
985 if (listeners.empty())
986 return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION;
988 base::ListValue args;
989 base::DictionaryValue* dict = new base::DictionaryValue();
990 ExtractRequestInfo(request, dict);
991 dict->SetBoolean(keys::kIsProxyKey, auth_info.is_proxy);
992 if (!auth_info.scheme.empty())
993 dict->SetString(keys::kSchemeKey, auth_info.scheme);
994 if (!auth_info.realm.empty())
995 dict->SetString(keys::kRealmKey, auth_info.realm);
996 base::DictionaryValue* challenger = new base::DictionaryValue();
997 challenger->SetString(keys::kHostKey, auth_info.challenger.host());
998 challenger->SetInteger(keys::kPortKey, auth_info.challenger.port());
999 dict->Set(keys::kChallengerKey, challenger);
1000 dict->Set(keys::kStatusLineKey, GetStatusLine(request->response_headers()));
1001 if (request->response_headers()) {
1002 dict->SetInteger(keys::kStatusCodeKey,
1003 request->response_headers()->response_code());
1005 if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
1006 dict->Set(keys::kResponseHeadersKey,
1007 GetResponseHeadersList(request->response_headers()));
1009 args.Append(dict);
1011 if (DispatchEvent(browser_context, request, listeners, args)) {
1012 BlockedRequest& blocked_request = blocked_requests_[request->identifier()];
1013 blocked_request.event = kOnAuthRequired;
1014 blocked_request.is_incognito |= IsIncognitoBrowserContext(browser_context);
1015 blocked_request.request = request;
1016 blocked_request.auth_callback = callback;
1017 blocked_request.auth_credentials = credentials;
1018 blocked_request.net_log = &request->net_log();
1019 return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_IO_PENDING;
1021 return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION;
1024 void ExtensionWebRequestEventRouter::OnBeforeRedirect(
1025 void* browser_context,
1026 const InfoMap* extension_info_map,
1027 net::URLRequest* request,
1028 const GURL& new_location) {
1029 if (ShouldHideEvent(browser_context, extension_info_map, request))
1030 return;
1032 if (GetAndSetSignaled(request->identifier(), kOnBeforeRedirect))
1033 return;
1035 ClearSignaled(request->identifier(), kOnBeforeRequest);
1036 ClearSignaled(request->identifier(), kOnBeforeSendHeaders);
1037 ClearSignaled(request->identifier(), kOnSendHeaders);
1038 ClearSignaled(request->identifier(), kOnHeadersReceived);
1040 int extra_info_spec = 0;
1041 EventListeners listeners = GetMatchingListeners(
1042 browser_context, extension_info_map, keys::kOnBeforeRedirectEvent,
1043 request, &extra_info_spec);
1044 if (listeners.empty())
1045 return;
1047 int http_status_code = request->GetResponseCode();
1049 std::string response_ip = request->GetSocketAddress().host();
1051 base::ListValue args;
1052 base::DictionaryValue* dict = new base::DictionaryValue();
1053 ExtractRequestInfo(request, dict);
1054 dict->SetString(keys::kRedirectUrlKey, new_location.spec());
1055 dict->SetInteger(keys::kStatusCodeKey, http_status_code);
1056 if (!response_ip.empty())
1057 dict->SetString(keys::kIpKey, response_ip);
1058 dict->SetBoolean(keys::kFromCache, request->was_cached());
1059 dict->Set(keys::kStatusLineKey, GetStatusLine(request->response_headers()));
1060 if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
1061 dict->Set(keys::kResponseHeadersKey,
1062 GetResponseHeadersList(request->response_headers()));
1064 args.Append(dict);
1066 DispatchEvent(browser_context, request, listeners, args);
1069 void ExtensionWebRequestEventRouter::OnResponseStarted(
1070 void* browser_context,
1071 const InfoMap* extension_info_map,
1072 net::URLRequest* request) {
1073 if (ShouldHideEvent(browser_context, extension_info_map, request))
1074 return;
1076 // OnResponseStarted is even triggered, when the request was cancelled.
1077 if (request->status().status() != net::URLRequestStatus::SUCCESS)
1078 return;
1080 int extra_info_spec = 0;
1081 EventListeners listeners = GetMatchingListeners(
1082 browser_context, extension_info_map, keys::kOnResponseStartedEvent,
1083 request, &extra_info_spec);
1084 if (listeners.empty())
1085 return;
1087 std::string response_ip = request->GetSocketAddress().host();
1089 base::ListValue args;
1090 base::DictionaryValue* dict = new base::DictionaryValue();
1091 ExtractRequestInfo(request, dict);
1092 if (!response_ip.empty())
1093 dict->SetString(keys::kIpKey, response_ip);
1094 dict->SetBoolean(keys::kFromCache, request->was_cached());
1095 dict->SetInteger(keys::kStatusCodeKey,
1096 GetResponseCodeWithDefault(request->response_headers()));
1097 dict->Set(keys::kStatusLineKey, GetStatusLine(request->response_headers()));
1098 if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
1099 dict->Set(keys::kResponseHeadersKey,
1100 GetResponseHeadersList(request->response_headers()));
1102 args.Append(dict);
1104 DispatchEvent(browser_context, request, listeners, args);
1107 void ExtensionWebRequestEventRouter::OnCompleted(
1108 void* browser_context,
1109 const InfoMap* extension_info_map,
1110 net::URLRequest* request) {
1111 // We hide events from the system context as well as sensitive requests.
1112 // However, if the request first became sensitive after redirecting we have
1113 // already signaled it and thus we have to signal the end of it. This is
1114 // risk-free because the handler cannot modify the request now.
1115 if (!browser_context ||
1116 (WebRequestPermissions::HideRequest(extension_info_map, request) &&
1117 !WasSignaled(*request))) {
1118 return;
1121 request_time_tracker_->LogRequestEndTime(request->identifier(),
1122 base::Time::Now());
1124 DCHECK(request->status().status() == net::URLRequestStatus::SUCCESS);
1126 DCHECK(!GetAndSetSignaled(request->identifier(), kOnCompleted));
1128 ClearPendingCallbacks(request);
1130 int extra_info_spec = 0;
1131 EventListeners listeners =
1132 GetMatchingListeners(browser_context, extension_info_map,
1133 keys::kOnCompletedEvent, request, &extra_info_spec);
1134 if (listeners.empty())
1135 return;
1137 std::string response_ip = request->GetSocketAddress().host();
1139 base::ListValue args;
1140 base::DictionaryValue* dict = new base::DictionaryValue();
1141 ExtractRequestInfo(request, dict);
1142 dict->SetInteger(keys::kStatusCodeKey,
1143 GetResponseCodeWithDefault(request->response_headers()));
1144 if (!response_ip.empty())
1145 dict->SetString(keys::kIpKey, response_ip);
1146 dict->SetBoolean(keys::kFromCache, request->was_cached());
1147 dict->Set(keys::kStatusLineKey, GetStatusLine(request->response_headers()));
1148 if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
1149 dict->Set(keys::kResponseHeadersKey,
1150 GetResponseHeadersList(request->response_headers()));
1152 args.Append(dict);
1154 DispatchEvent(browser_context, request, listeners, args);
1157 void ExtensionWebRequestEventRouter::OnErrorOccurred(
1158 void* browser_context,
1159 const InfoMap* extension_info_map,
1160 net::URLRequest* request,
1161 bool started) {
1162 // We hide events from the system context as well as sensitive requests.
1163 // However, if the request first became sensitive after redirecting we have
1164 // already signaled it and thus we have to signal the end of it. This is
1165 // risk-free because the handler cannot modify the request now.
1166 if (!browser_context ||
1167 (WebRequestPermissions::HideRequest(extension_info_map, request) &&
1168 !WasSignaled(*request))) {
1169 return;
1172 request_time_tracker_->LogRequestEndTime(request->identifier(),
1173 base::Time::Now());
1175 DCHECK(request->status().status() == net::URLRequestStatus::FAILED ||
1176 request->status().status() == net::URLRequestStatus::CANCELED);
1178 DCHECK(!GetAndSetSignaled(request->identifier(), kOnErrorOccurred));
1180 ClearPendingCallbacks(request);
1182 int extra_info_spec = 0;
1183 EventListeners listeners = GetMatchingListeners(
1184 browser_context, extension_info_map,
1185 web_request::OnErrorOccurred::kEventName, request, &extra_info_spec);
1186 if (listeners.empty())
1187 return;
1189 base::ListValue args;
1190 base::DictionaryValue* dict = new base::DictionaryValue();
1191 ExtractRequestInfo(request, dict);
1192 if (started) {
1193 std::string response_ip = request->GetSocketAddress().host();
1194 if (!response_ip.empty())
1195 dict->SetString(keys::kIpKey, response_ip);
1197 dict->SetBoolean(keys::kFromCache, request->was_cached());
1198 dict->SetString(keys::kErrorKey,
1199 net::ErrorToString(request->status().error()));
1200 args.Append(dict);
1202 DispatchEvent(browser_context, request, listeners, args);
1205 void ExtensionWebRequestEventRouter::OnURLRequestDestroyed(
1206 void* browser_context,
1207 const net::URLRequest* request) {
1208 ClearPendingCallbacks(request);
1210 signaled_requests_.erase(request->identifier());
1212 request_time_tracker_->LogRequestEndTime(request->identifier(),
1213 base::Time::Now());
1216 void ExtensionWebRequestEventRouter::ClearPendingCallbacks(
1217 const net::URLRequest* request) {
1218 blocked_requests_.erase(request->identifier());
1221 bool ExtensionWebRequestEventRouter::DispatchEvent(
1222 void* browser_context,
1223 net::URLRequest* request,
1224 const std::vector<const EventListener*>& listeners,
1225 const base::ListValue& args) {
1226 // TODO(mpcomplete): Consider consolidating common (extension_id,json_args)
1227 // pairs into a single message sent to a list of sub_event_names.
1228 int num_handlers_blocking = 0;
1229 for (const EventListener* listener : listeners) {
1230 // Filter out the optional keys that this listener didn't request.
1231 scoped_ptr<base::ListValue> args_filtered(args.DeepCopy());
1232 base::DictionaryValue* dict = NULL;
1233 CHECK(args_filtered->GetDictionary(0, &dict) && dict);
1234 if (!(listener->extra_info_spec & ExtraInfoSpec::REQUEST_HEADERS))
1235 dict->Remove(keys::kRequestHeadersKey, NULL);
1236 if (!(listener->extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS))
1237 dict->Remove(keys::kResponseHeadersKey, NULL);
1239 EventRouter::DispatchEventToSender(
1240 listener->ipc_sender.get(), browser_context, listener->extension_id,
1241 listener->histogram_value, listener->sub_event_name,
1242 args_filtered.Pass(), EventRouter::USER_GESTURE_UNKNOWN,
1243 EventFilteringInfo());
1244 if (listener->extra_info_spec &
1245 (ExtraInfoSpec::BLOCKING | ExtraInfoSpec::ASYNC_BLOCKING)) {
1246 listener->blocked_requests.insert(request->identifier());
1247 // If this is the first delegate blocking the request, go ahead and log
1248 // it.
1249 if (num_handlers_blocking == 0) {
1250 std::string delegate_info = l10n_util::GetStringFUTF8(
1251 IDS_LOAD_STATE_PARAMETER_EXTENSION,
1252 base::UTF8ToUTF16(listener->extension_name));
1253 // LobAndReport allows extensions that block requests to be displayed in
1254 // the load status bar.
1255 request->LogAndReportBlockedBy(delegate_info.c_str());
1257 ++num_handlers_blocking;
1261 if (num_handlers_blocking > 0) {
1262 BlockedRequest& blocked_request = blocked_requests_[request->identifier()];
1263 blocked_request.request = request;
1264 blocked_request.is_incognito |= IsIncognitoBrowserContext(browser_context);
1265 blocked_request.num_handlers_blocking += num_handlers_blocking;
1266 blocked_request.blocking_time = base::Time::Now();
1267 return true;
1270 return false;
1273 void ExtensionWebRequestEventRouter::OnEventHandled(
1274 void* browser_context,
1275 const std::string& extension_id,
1276 const std::string& event_name,
1277 const std::string& sub_event_name,
1278 uint64_t request_id,
1279 EventResponse* response) {
1280 // TODO(robwu): Does this also work with webviews? operator< (used by find)
1281 // takes the webview ID into account, which is not set on |listener|.
1282 EventListener listener;
1283 listener.extension_id = extension_id;
1284 listener.sub_event_name = sub_event_name;
1286 // The listener may have been removed (e.g. due to the process going away)
1287 // before we got here.
1288 std::set<EventListener>::iterator found =
1289 listeners_[browser_context][event_name].find(listener);
1290 if (found != listeners_[browser_context][event_name].end())
1291 found->blocked_requests.erase(request_id);
1293 DecrementBlockCount(
1294 browser_context, extension_id, event_name, request_id, response);
1297 bool ExtensionWebRequestEventRouter::AddEventListener(
1298 void* browser_context,
1299 const std::string& extension_id,
1300 const std::string& extension_name,
1301 events::HistogramValue histogram_value,
1302 const std::string& event_name,
1303 const std::string& sub_event_name,
1304 const RequestFilter& filter,
1305 int extra_info_spec,
1306 int embedder_process_id,
1307 int web_view_instance_id,
1308 base::WeakPtr<IPC::Sender> ipc_sender) {
1309 if (!IsWebRequestEvent(event_name))
1310 return false;
1312 EventListener listener;
1313 listener.extension_id = extension_id;
1314 listener.extension_name = extension_name;
1315 listener.histogram_value = histogram_value;
1316 listener.sub_event_name = sub_event_name;
1317 listener.filter = filter;
1318 listener.extra_info_spec = extra_info_spec;
1319 listener.ipc_sender = ipc_sender;
1320 listener.embedder_process_id = embedder_process_id;
1321 listener.web_view_instance_id = web_view_instance_id;
1322 if (listener.web_view_instance_id) {
1323 content::RecordAction(
1324 base::UserMetricsAction("WebView.WebRequest.AddListener"));
1327 if (ContainsKey(listeners_[browser_context][event_name], listener)) {
1328 // This is likely an abuse of the API by a malicious extension.
1329 return false;
1331 listeners_[browser_context][event_name].insert(listener);
1332 return true;
1335 void ExtensionWebRequestEventRouter::RemoveEventListener(
1336 void* browser_context,
1337 const std::string& extension_id,
1338 const std::string& sub_event_name,
1339 int embedder_process_id,
1340 int web_view_instance_id) {
1341 std::string event_name = EventRouter::GetBaseEventName(sub_event_name);
1342 DCHECK(IsWebRequestEvent(event_name));
1344 EventListener listener;
1345 listener.extension_id = extension_id;
1346 listener.sub_event_name = sub_event_name;
1347 listener.embedder_process_id = embedder_process_id;
1348 listener.web_view_instance_id = web_view_instance_id;
1350 std::set<EventListener>& event_listeners =
1351 listeners_[browser_context][event_name];
1352 // It's possible for AddEventListener to fail asynchronously. In that case,
1353 // the renderer believes the listener exists, while the browser does not.
1354 // Ignore a RemoveEventListener in that case.
1355 std::set<EventListener>::const_iterator it = event_listeners.find(listener);
1356 if (it == event_listeners.end())
1357 return;
1359 CHECK_EQ(event_listeners.count(listener), 1u) <<
1360 "extension=" << extension_id << " event=" << event_name;
1362 // Unblock any request that this event listener may have been blocking.
1363 for (uint64_t id : it->blocked_requests)
1364 DecrementBlockCount(browser_context, extension_id, event_name, id, NULL);
1366 event_listeners.erase(listener);
1368 helpers::ClearCacheOnNavigation();
1371 void ExtensionWebRequestEventRouter::RemoveWebViewEventListeners(
1372 void* browser_context,
1373 int embedder_process_id,
1374 int web_view_instance_id) {
1375 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1377 // Iterate over all listeners of all WebRequest events to delete
1378 // any listeners that belong to the provided <webview>.
1379 ListenerMapForBrowserContext& map_for_browser_context =
1380 listeners_[browser_context];
1381 for (const auto& event_iter : map_for_browser_context) {
1382 // Construct a listeners_to_delete vector so that we don't modify the set of
1383 // listeners as we iterate through it.
1384 std::vector<EventListener> listeners_to_delete;
1385 const std::set<EventListener>& listeners = event_iter.second;
1386 for (const auto& listener : listeners) {
1387 if (listener.embedder_process_id == embedder_process_id &&
1388 listener.web_view_instance_id == web_view_instance_id) {
1389 listeners_to_delete.push_back(listener);
1392 // Remove the listeners selected for deletion.
1393 for (const auto& listener : listeners_to_delete) {
1394 RemoveEventListenerOnIOThread(
1395 browser_context,
1396 listener.extension_id,
1397 listener.sub_event_name,
1398 listener.embedder_process_id,
1399 listener.web_view_instance_id);
1404 void ExtensionWebRequestEventRouter::OnOTRBrowserContextCreated(
1405 void* original_browser_context, void* otr_browser_context) {
1406 cross_browser_context_map_[original_browser_context] =
1407 std::make_pair(false, otr_browser_context);
1408 cross_browser_context_map_[otr_browser_context] =
1409 std::make_pair(true, original_browser_context);
1412 void ExtensionWebRequestEventRouter::OnOTRBrowserContextDestroyed(
1413 void* original_browser_context, void* otr_browser_context) {
1414 cross_browser_context_map_.erase(otr_browser_context);
1415 cross_browser_context_map_.erase(original_browser_context);
1418 void ExtensionWebRequestEventRouter::AddCallbackForPageLoad(
1419 const base::Closure& callback) {
1420 callbacks_for_page_load_.push_back(callback);
1423 bool ExtensionWebRequestEventRouter::IsPageLoad(
1424 const net::URLRequest* request) const {
1425 bool is_main_frame = false;
1426 int frame_id = -1;
1427 bool parent_is_main_frame = false;
1428 int parent_frame_id = -1;
1429 int render_process_host_id = -1;
1430 int routing_id = -1;
1431 ResourceType resource_type = content::RESOURCE_TYPE_LAST_TYPE;
1433 ExtractRequestInfoDetails(request, &is_main_frame, &frame_id,
1434 &parent_is_main_frame, &parent_frame_id,
1435 &render_process_host_id,
1436 &routing_id, &resource_type);
1438 return resource_type == content::RESOURCE_TYPE_MAIN_FRAME;
1441 void ExtensionWebRequestEventRouter::NotifyPageLoad() {
1442 for (const auto& callback : callbacks_for_page_load_)
1443 callback.Run();
1444 callbacks_for_page_load_.clear();
1447 void* ExtensionWebRequestEventRouter::GetCrossBrowserContext(
1448 void* browser_context) const {
1449 CrossBrowserContextMap::const_iterator cross_browser_context =
1450 cross_browser_context_map_.find(browser_context);
1451 if (cross_browser_context == cross_browser_context_map_.end())
1452 return NULL;
1453 return cross_browser_context->second.second;
1456 bool ExtensionWebRequestEventRouter::IsIncognitoBrowserContext(
1457 void* browser_context) const {
1458 CrossBrowserContextMap::const_iterator cross_browser_context =
1459 cross_browser_context_map_.find(browser_context);
1460 if (cross_browser_context == cross_browser_context_map_.end())
1461 return false;
1462 return cross_browser_context->second.first;
1465 bool ExtensionWebRequestEventRouter::WasSignaled(
1466 const net::URLRequest& request) const {
1467 SignaledRequestMap::const_iterator flag =
1468 signaled_requests_.find(request.identifier());
1469 return (flag != signaled_requests_.end()) && (flag->second != 0);
1472 void ExtensionWebRequestEventRouter::GetMatchingListenersImpl(
1473 void* browser_context,
1474 const net::URLRequest* request,
1475 const InfoMap* extension_info_map,
1476 bool crosses_incognito,
1477 const std::string& event_name,
1478 const GURL& url,
1479 int render_process_host_id,
1480 int routing_id,
1481 ResourceType resource_type,
1482 bool is_async_request,
1483 bool is_request_from_extension,
1484 int* extra_info_spec,
1485 EventListeners* matching_listeners) {
1486 std::string web_request_event_name(event_name);
1487 WebViewRendererState::WebViewInfo web_view_info;
1488 bool is_web_view_guest = WebViewRendererState::GetInstance()->GetInfo(
1489 render_process_host_id, routing_id, &web_view_info);
1490 if (is_web_view_guest) {
1491 web_request_event_name.replace(
1492 0, sizeof(kWebRequestEventPrefix) - 1, webview::kWebViewEventPrefix);
1495 std::set<EventListener>& listeners =
1496 listeners_[browser_context][web_request_event_name];
1497 for (const EventListener& listener : listeners) {
1498 if (!listener.ipc_sender.get()) {
1499 // The IPC sender has been deleted. This listener will be removed soon
1500 // via a call to RemoveEventListener. For now, just skip it.
1501 continue;
1504 if (is_web_view_guest &&
1505 (listener.embedder_process_id != web_view_info.embedder_process_id ||
1506 listener.web_view_instance_id != web_view_info.instance_id)) {
1507 continue;
1510 // Filter requests from other extensions / apps. This does not work for
1511 // content scripts, or extension pages in non-extension processes.
1512 if (is_request_from_extension &&
1513 listener.embedder_process_id != render_process_host_id) {
1514 continue;
1517 if (!listener.filter.urls.is_empty() &&
1518 !listener.filter.urls.MatchesURL(url)) {
1519 continue;
1522 if (web_request_event_router_delegate_ &&
1523 web_request_event_router_delegate_->OnGetMatchingListenersImplCheck(
1524 listener.filter.tab_id, listener.filter.window_id, request)) {
1525 continue;
1528 const std::vector<content::ResourceType>& types = listener.filter.types;
1529 if (!types.empty() &&
1530 std::find(types.begin(), types.end(), resource_type) == types.end()) {
1531 continue;
1534 if (!is_web_view_guest &&
1535 !WebRequestPermissions::CanExtensionAccessURL(
1536 extension_info_map, listener.extension_id, url, crosses_incognito,
1537 WebRequestPermissions::REQUIRE_HOST_PERMISSION)) {
1538 continue;
1541 bool blocking_listener =
1542 (listener.extra_info_spec &
1543 (ExtraInfoSpec::BLOCKING | ExtraInfoSpec::ASYNC_BLOCKING)) != 0;
1545 // We do not want to notify extensions about XHR requests that are
1546 // triggered by themselves. This is a workaround to prevent deadlocks
1547 // in case of synchronous XHR requests that block the extension renderer
1548 // and therefore prevent the extension from processing the request
1549 // handler. This is only a problem for blocking listeners.
1550 // http://crbug.com/105656
1551 bool synchronous_xhr_from_extension =
1552 !is_async_request && is_request_from_extension &&
1553 resource_type == content::RESOURCE_TYPE_XHR;
1555 // Only send webRequest events for URLs the extension has access to.
1556 if (blocking_listener && synchronous_xhr_from_extension)
1557 continue;
1559 matching_listeners->push_back(&listener);
1560 *extra_info_spec |= listener.extra_info_spec;
1564 ExtensionWebRequestEventRouter::EventListeners
1565 ExtensionWebRequestEventRouter::GetMatchingListeners(
1566 void* browser_context,
1567 const InfoMap* extension_info_map,
1568 const std::string& event_name,
1569 const net::URLRequest* request,
1570 int* extra_info_spec) {
1571 // TODO(mpcomplete): handle browser_context == NULL (should collect all
1572 // listeners).
1573 *extra_info_spec = 0;
1575 bool is_main_frame = false;
1576 int frame_id = -1;
1577 bool parent_is_main_frame = false;
1578 int parent_frame_id = -1;
1579 int render_process_host_id = -1;
1580 int routing_id = -1;
1581 ResourceType resource_type = content::RESOURCE_TYPE_LAST_TYPE;
1582 const GURL& url = request->url();
1584 ExtractRequestInfoDetails(request, &is_main_frame, &frame_id,
1585 &parent_is_main_frame, &parent_frame_id,
1586 &render_process_host_id,
1587 &routing_id, &resource_type);
1589 bool is_request_from_extension =
1590 IsRequestFromExtension(request, extension_info_map);
1592 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
1593 // We are conservative here and assume requests are asynchronous in case
1594 // we don't have an info object. We don't want to risk a deadlock.
1595 bool is_async_request = !info || info->IsAsync();
1597 EventListeners matching_listeners;
1598 GetMatchingListenersImpl(
1599 browser_context, request, extension_info_map, false, event_name,
1600 url, render_process_host_id, routing_id, resource_type,
1601 is_async_request, is_request_from_extension, extra_info_spec,
1602 &matching_listeners);
1603 void* cross_browser_context = GetCrossBrowserContext(browser_context);
1604 if (cross_browser_context) {
1605 GetMatchingListenersImpl(
1606 cross_browser_context, request, extension_info_map, true, event_name,
1607 url, render_process_host_id, routing_id, resource_type,
1608 is_async_request, is_request_from_extension, extra_info_spec,
1609 &matching_listeners);
1612 return matching_listeners;
1615 namespace {
1617 helpers::EventResponseDelta* CalculateDelta(
1618 ExtensionWebRequestEventRouter::BlockedRequest* blocked_request,
1619 ExtensionWebRequestEventRouter::EventResponse* response) {
1620 switch (blocked_request->event) {
1621 case ExtensionWebRequestEventRouter::kOnBeforeRequest:
1622 return helpers::CalculateOnBeforeRequestDelta(
1623 response->extension_id, response->extension_install_time,
1624 response->cancel, response->new_url);
1625 case ExtensionWebRequestEventRouter::kOnBeforeSendHeaders: {
1626 net::HttpRequestHeaders* old_headers = blocked_request->request_headers;
1627 net::HttpRequestHeaders* new_headers = response->request_headers.get();
1628 return helpers::CalculateOnBeforeSendHeadersDelta(
1629 response->extension_id, response->extension_install_time,
1630 response->cancel, old_headers, new_headers);
1632 case ExtensionWebRequestEventRouter::kOnHeadersReceived: {
1633 const net::HttpResponseHeaders* old_headers =
1634 blocked_request->original_response_headers.get();
1635 helpers::ResponseHeaders* new_headers =
1636 response->response_headers.get();
1637 return helpers::CalculateOnHeadersReceivedDelta(
1638 response->extension_id,
1639 response->extension_install_time,
1640 response->cancel,
1641 response->new_url,
1642 old_headers,
1643 new_headers);
1645 case ExtensionWebRequestEventRouter::kOnAuthRequired:
1646 return helpers::CalculateOnAuthRequiredDelta(
1647 response->extension_id, response->extension_install_time,
1648 response->cancel, &response->auth_credentials);
1649 default:
1650 NOTREACHED();
1651 return nullptr;
1655 base::Value* SerializeResponseHeaders(const helpers::ResponseHeaders& headers) {
1656 scoped_ptr<base::ListValue> serialized_headers(new base::ListValue());
1657 for (const auto& it : headers) {
1658 serialized_headers->Append(
1659 helpers::CreateHeaderDictionary(it.first, it.second));
1661 return serialized_headers.release();
1664 // Convert a RequestCookieModifications/ResponseCookieModifications object to a
1665 // base::ListValue which summarizes the changes made. This is templated since
1666 // the two types (request/response) are different but contain essentially the
1667 // same fields.
1668 template <typename CookieType>
1669 base::ListValue* SummarizeCookieModifications(
1670 const std::vector<linked_ptr<CookieType>>& modifications) {
1671 scoped_ptr<base::ListValue> cookie_modifications(new base::ListValue());
1672 for (const auto& it : modifications) {
1673 scoped_ptr<base::DictionaryValue> summary(new base::DictionaryValue());
1674 const CookieType& mod = *(it.get());
1675 switch (mod.type) {
1676 case helpers::ADD:
1677 summary->SetString(activity_log::kCookieModificationTypeKey,
1678 activity_log::kCookieModificationAdd);
1679 break;
1680 case helpers::EDIT:
1681 summary->SetString(activity_log::kCookieModificationTypeKey,
1682 activity_log::kCookieModificationEdit);
1683 break;
1684 case helpers::REMOVE:
1685 summary->SetString(activity_log::kCookieModificationTypeKey,
1686 activity_log::kCookieModificationRemove);
1687 break;
1689 if (mod.filter) {
1690 if (mod.filter->name) {
1691 summary->SetString(activity_log::kCookieFilterNameKey,
1692 *mod.modification->name);
1694 if (mod.filter->domain) {
1695 summary->SetString(activity_log::kCookieFilterDomainKey,
1696 *mod.modification->name);
1699 if (mod.modification) {
1700 if (mod.modification->name) {
1701 summary->SetString(activity_log::kCookieModDomainKey,
1702 *mod.modification->name);
1704 if (mod.modification->domain) {
1705 summary->SetString(activity_log::kCookieModDomainKey,
1706 *mod.modification->name);
1709 cookie_modifications->Append(summary.release());
1711 return cookie_modifications.release();
1714 // Converts an EventResponseDelta object to a dictionary value suitable for the
1715 // activity log.
1716 scoped_ptr<base::DictionaryValue> SummarizeResponseDelta(
1717 const std::string& event_name,
1718 const helpers::EventResponseDelta& delta) {
1719 scoped_ptr<base::DictionaryValue> details(new base::DictionaryValue());
1720 if (delta.cancel)
1721 details->SetBoolean(activity_log::kCancelKey, true);
1722 if (!delta.new_url.is_empty())
1723 details->SetString(activity_log::kNewUrlKey, delta.new_url.spec());
1725 scoped_ptr<base::ListValue> modified_headers(new base::ListValue());
1726 net::HttpRequestHeaders::Iterator iter(delta.modified_request_headers);
1727 while (iter.GetNext()) {
1728 modified_headers->Append(
1729 helpers::CreateHeaderDictionary(iter.name(), iter.value()));
1731 if (!modified_headers->empty()) {
1732 details->Set(activity_log::kModifiedRequestHeadersKey,
1733 modified_headers.release());
1736 scoped_ptr<base::ListValue> deleted_headers(new base::ListValue());
1737 deleted_headers->AppendStrings(delta.deleted_request_headers);
1738 if (!deleted_headers->empty()) {
1739 details->Set(activity_log::kDeletedRequestHeadersKey,
1740 deleted_headers.release());
1743 if (!delta.added_response_headers.empty()) {
1744 details->Set(activity_log::kAddedRequestHeadersKey,
1745 SerializeResponseHeaders(delta.added_response_headers));
1747 if (!delta.deleted_response_headers.empty()) {
1748 details->Set(activity_log::kDeletedResponseHeadersKey,
1749 SerializeResponseHeaders(delta.deleted_response_headers));
1751 if (delta.auth_credentials) {
1752 details->SetString(
1753 activity_log::kAuthCredentialsKey,
1754 base::UTF16ToUTF8(delta.auth_credentials->username()) + ":*");
1757 if (!delta.response_cookie_modifications.empty()) {
1758 details->Set(
1759 activity_log::kResponseCookieModificationsKey,
1760 SummarizeCookieModifications(delta.response_cookie_modifications));
1763 return details.Pass();
1766 } // namespace
1768 void ExtensionWebRequestEventRouter::LogExtensionActivity(
1769 void* browser_context_id,
1770 bool is_incognito,
1771 const std::string& extension_id,
1772 const GURL& url,
1773 const std::string& api_call,
1774 scoped_ptr<base::DictionaryValue> details) {
1775 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
1776 BrowserThread::PostTask(
1777 BrowserThread::UI,
1778 FROM_HERE,
1779 base::Bind(&ExtensionWebRequestEventRouter::LogExtensionActivity,
1780 base::Unretained(this),
1781 browser_context_id,
1782 is_incognito,
1783 extension_id,
1784 url,
1785 api_call,
1786 base::Passed(&details)));
1787 } else {
1788 if (web_request_event_router_delegate_) {
1789 web_request_event_router_delegate_->LogExtensionActivity(
1790 reinterpret_cast<content::BrowserContext*>(browser_context_id),
1791 is_incognito, extension_id, url, api_call, details.Pass());
1796 void ExtensionWebRequestEventRouter::DecrementBlockCount(
1797 void* browser_context,
1798 const std::string& extension_id,
1799 const std::string& event_name,
1800 uint64_t request_id,
1801 EventResponse* response) {
1802 scoped_ptr<EventResponse> response_scoped(response);
1804 // It's possible that this request was deleted, or cancelled by a previous
1805 // event handler. If so, ignore this response.
1806 auto it = blocked_requests_.find(request_id);
1807 if (it == blocked_requests_.end())
1808 return;
1810 BlockedRequest& blocked_request = it->second;
1811 int num_handlers_blocking = --blocked_request.num_handlers_blocking;
1812 CHECK_GE(num_handlers_blocking, 0);
1814 if (response) {
1815 helpers::EventResponseDelta* delta =
1816 CalculateDelta(&blocked_request, response);
1818 LogExtensionActivity(browser_context,
1819 blocked_request.is_incognito,
1820 extension_id,
1821 blocked_request.request->url(),
1822 event_name,
1823 SummarizeResponseDelta(event_name, *delta));
1825 blocked_request.response_deltas.push_back(
1826 linked_ptr<helpers::EventResponseDelta>(delta));
1829 base::TimeDelta block_time =
1830 base::Time::Now() - blocked_request.blocking_time;
1831 if (!extension_id.empty()) {
1832 request_time_tracker_->IncrementExtensionBlockTime(
1833 extension_id, request_id, block_time);
1834 } else {
1835 // |extension_id| is empty for requests blocked on startup waiting for the
1836 // declarative rules to be read from disk.
1837 UMA_HISTOGRAM_TIMES("Extensions.NetworkDelayStartup", block_time);
1840 if (num_handlers_blocking == 0) {
1841 blocked_request.request->LogUnblocked();
1842 ExecuteDeltas(browser_context, request_id, true);
1843 } else {
1844 // Update the URLRequest to make sure it's tagged with an extension that's
1845 // still blocking it. This may end up being the same extension as before.
1846 std::set<EventListener>& listeners =
1847 listeners_[browser_context][event_name];
1849 for (const auto& listener : listeners) {
1850 if (!ContainsKey(listener.blocked_requests, request_id))
1851 continue;
1852 std::string delegate_info =
1853 l10n_util::GetStringFUTF8(IDS_LOAD_STATE_PARAMETER_EXTENSION,
1854 base::UTF8ToUTF16(listener.extension_name));
1855 blocked_request.request->LogAndReportBlockedBy(delegate_info.c_str());
1856 break;
1861 void ExtensionWebRequestEventRouter::SendMessages(
1862 void* browser_context,
1863 const BlockedRequest& blocked_request) {
1864 const helpers::EventResponseDeltas& deltas = blocked_request.response_deltas;
1865 for (const auto& delta : deltas) {
1866 const std::set<std::string>& messages = delta->messages_to_extension;
1867 for (const std::string& message : messages) {
1868 scoped_ptr<base::DictionaryValue> argument(new base::DictionaryValue);
1869 ExtractRequestInfo(blocked_request.request, argument.get());
1870 WebViewRendererState::WebViewInfo web_view_info;
1871 bool is_web_view_guest = GetWebViewInfo(blocked_request.request,
1872 &web_view_info);
1873 argument->SetString(keys::kMessageKey, message);
1874 argument->SetString(keys::kStageKey,
1875 GetRequestStageAsString(blocked_request.event));
1877 BrowserThread::PostTask(
1878 BrowserThread::UI, FROM_HERE,
1879 base::Bind(&SendOnMessageEventOnUI, browser_context,
1880 delta->extension_id, is_web_view_guest, web_view_info,
1881 base::Passed(&argument)));
1886 int ExtensionWebRequestEventRouter::ExecuteDeltas(void* browser_context,
1887 uint64_t request_id,
1888 bool call_callback) {
1889 BlockedRequest& blocked_request = blocked_requests_[request_id];
1890 CHECK_EQ(0, blocked_request.num_handlers_blocking);
1891 helpers::EventResponseDeltas& deltas = blocked_request.response_deltas;
1892 base::TimeDelta block_time =
1893 base::Time::Now() - blocked_request.blocking_time;
1894 request_time_tracker_->IncrementTotalBlockTime(request_id, block_time);
1896 bool credentials_set = false;
1898 deltas.sort(&helpers::InDecreasingExtensionInstallationTimeOrder);
1900 bool canceled = false;
1901 helpers::MergeCancelOfResponses(blocked_request.response_deltas, &canceled,
1902 blocked_request.net_log);
1904 WarningSet warnings;
1905 if (blocked_request.event == kOnBeforeRequest) {
1906 CHECK(!blocked_request.callback.is_null());
1907 helpers::MergeOnBeforeRequestResponses(
1908 blocked_request.response_deltas,
1909 blocked_request.new_url,
1910 &warnings,
1911 blocked_request.net_log);
1912 } else if (blocked_request.event == kOnBeforeSendHeaders) {
1913 CHECK(!blocked_request.callback.is_null());
1914 helpers::MergeOnBeforeSendHeadersResponses(
1915 blocked_request.response_deltas,
1916 blocked_request.request_headers,
1917 &warnings,
1918 blocked_request.net_log);
1919 } else if (blocked_request.event == kOnHeadersReceived) {
1920 CHECK(!blocked_request.callback.is_null());
1921 helpers::MergeOnHeadersReceivedResponses(
1922 blocked_request.response_deltas,
1923 blocked_request.original_response_headers.get(),
1924 blocked_request.override_response_headers,
1925 blocked_request.new_url,
1926 &warnings,
1927 blocked_request.net_log);
1928 } else if (blocked_request.event == kOnAuthRequired) {
1929 CHECK(blocked_request.callback.is_null());
1930 CHECK(!blocked_request.auth_callback.is_null());
1931 credentials_set = helpers::MergeOnAuthRequiredResponses(
1932 blocked_request.response_deltas,
1933 blocked_request.auth_credentials,
1934 &warnings,
1935 blocked_request.net_log);
1936 } else {
1937 NOTREACHED();
1940 SendMessages(browser_context, blocked_request);
1942 if (!warnings.empty()) {
1943 BrowserThread::PostTask(
1944 BrowserThread::UI,
1945 FROM_HERE,
1946 base::Bind(&WarningService::NotifyWarningsOnUI,
1947 browser_context, warnings));
1950 if (canceled) {
1951 request_time_tracker_->SetRequestCanceled(request_id);
1952 } else if (blocked_request.new_url &&
1953 !blocked_request.new_url->is_empty()) {
1954 request_time_tracker_->SetRequestRedirected(request_id);
1957 // This triggers onErrorOccurred if canceled is true.
1958 int rv = canceled ? net::ERR_BLOCKED_BY_CLIENT : net::OK;
1960 if (!blocked_request.callback.is_null()) {
1961 net::CompletionCallback callback = blocked_request.callback;
1962 // Ensure that request is removed before callback because the callback
1963 // might trigger the next event.
1964 blocked_requests_.erase(request_id);
1965 if (call_callback)
1966 callback.Run(rv);
1967 } else if (!blocked_request.auth_callback.is_null()) {
1968 net::NetworkDelegate::AuthRequiredResponse response;
1969 if (canceled)
1970 response = net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_CANCEL_AUTH;
1971 else if (credentials_set)
1972 response = net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_SET_AUTH;
1973 else
1974 response = net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION;
1976 net::NetworkDelegate::AuthCallback callback = blocked_request.auth_callback;
1977 blocked_requests_.erase(request_id);
1978 if (call_callback)
1979 callback.Run(response);
1980 } else {
1981 blocked_requests_.erase(request_id);
1983 return rv;
1986 bool ExtensionWebRequestEventRouter::ProcessDeclarativeRules(
1987 void* browser_context,
1988 const InfoMap* extension_info_map,
1989 const std::string& event_name,
1990 net::URLRequest* request,
1991 RequestStage request_stage,
1992 const net::HttpResponseHeaders* original_response_headers) {
1993 WebViewRendererState::WebViewInfo web_view_info;
1994 bool is_web_view_guest = GetWebViewInfo(request, &web_view_info);
1995 int rules_registry_id = is_web_view_guest
1996 ? web_view_info.rules_registry_id
1997 : RulesRegistryService::kDefaultRulesRegistryID;
1999 RulesRegistryKey rules_key(browser_context, rules_registry_id);
2000 // If this check fails, check that the active stages are up-to-date in
2001 // extensions/browser/api/declarative_webrequest/request_stage.h .
2002 DCHECK(request_stage & kActiveStages);
2004 // Rules of the current |browser_context| may apply but we need to check also
2005 // whether there are applicable rules from extensions whose background page
2006 // spans from regular to incognito mode.
2008 // First parameter identifies the registry, the second indicates whether the
2009 // registry belongs to the cross browser_context.
2010 using RelevantRegistry = std::pair<WebRequestRulesRegistry*, bool>;
2011 std::vector<RelevantRegistry> relevant_registries;
2013 auto rules_key_it = rules_registries_.find(rules_key);
2014 if (rules_key_it != rules_registries_.end()) {
2015 relevant_registries.push_back(
2016 std::make_pair(rules_key_it->second.get(), false));
2019 void* cross_browser_context = GetCrossBrowserContext(browser_context);
2020 RulesRegistryKey cross_browser_context_rules_key(cross_browser_context,
2021 rules_registry_id);
2022 if (cross_browser_context) {
2023 auto it = rules_registries_.find(cross_browser_context_rules_key);
2024 if (it != rules_registries_.end())
2025 relevant_registries.push_back(std::make_pair(it->second.get(), true));
2028 // The following block is experimentally enabled and its impact on load time
2029 // logged with UMA Extensions.NetworkDelayRegistryLoad. crbug.com/175961
2030 for (auto it : relevant_registries) {
2031 WebRequestRulesRegistry* rules_registry = it.first;
2032 if (rules_registry->ready().is_signaled())
2033 continue;
2035 // The rules registry is still loading. Block this request until it
2036 // finishes.
2037 rules_registry->ready().Post(
2038 FROM_HERE,
2039 base::Bind(&ExtensionWebRequestEventRouter::OnRulesRegistryReady,
2040 AsWeakPtr(), browser_context, event_name,
2041 request->identifier(), request_stage));
2042 BlockedRequest& blocked_request = blocked_requests_[request->identifier()];
2043 blocked_request.num_handlers_blocking++;
2044 blocked_request.request = request;
2045 blocked_request.is_incognito |= IsIncognitoBrowserContext(browser_context);
2046 blocked_request.blocking_time = base::Time::Now();
2047 blocked_request.original_response_headers = original_response_headers;
2048 blocked_request.extension_info_map = extension_info_map;
2049 return true;
2052 base::Time start = base::Time::Now();
2054 bool deltas_created = false;
2055 for (const auto& it : relevant_registries) {
2056 WebRequestRulesRegistry* rules_registry = it.first;
2057 helpers::EventResponseDeltas result = rules_registry->CreateDeltas(
2058 extension_info_map,
2059 WebRequestData(request, request_stage, original_response_headers),
2060 it.second);
2062 if (!result.empty()) {
2063 helpers::EventResponseDeltas& deltas =
2064 blocked_requests_[request->identifier()].response_deltas;
2065 deltas.insert(deltas.end(), result.begin(), result.end());
2066 deltas_created = true;
2070 base::TimeDelta elapsed_time = start - base::Time::Now();
2071 UMA_HISTOGRAM_TIMES("Extensions.DeclarativeWebRequestNetworkDelay",
2072 elapsed_time);
2074 return deltas_created;
2077 void ExtensionWebRequestEventRouter::OnRulesRegistryReady(
2078 void* browser_context,
2079 const std::string& event_name,
2080 uint64_t request_id,
2081 RequestStage request_stage) {
2082 // It's possible that this request was deleted, or cancelled by a previous
2083 // event handler. If so, ignore this response.
2084 auto it = blocked_requests_.find(request_id);
2085 if (it == blocked_requests_.end())
2086 return;
2088 BlockedRequest& blocked_request = it->second;
2089 base::TimeDelta block_time =
2090 base::Time::Now() - blocked_request.blocking_time;
2091 UMA_HISTOGRAM_TIMES("Extensions.NetworkDelayRegistryLoad", block_time);
2093 ProcessDeclarativeRules(browser_context,
2094 blocked_request.extension_info_map,
2095 event_name,
2096 blocked_request.request,
2097 request_stage,
2098 blocked_request.original_response_headers.get());
2099 // Reset to NULL so that nobody relies on this being set.
2100 blocked_request.extension_info_map = NULL;
2101 DecrementBlockCount(
2102 browser_context, std::string(), event_name, request_id, NULL);
2105 bool ExtensionWebRequestEventRouter::GetAndSetSignaled(uint64_t request_id,
2106 EventTypes event_type) {
2107 SignaledRequestMap::iterator iter = signaled_requests_.find(request_id);
2108 if (iter == signaled_requests_.end()) {
2109 signaled_requests_[request_id] = event_type;
2110 return false;
2112 bool was_signaled_before = (iter->second & event_type) != 0;
2113 iter->second |= event_type;
2114 return was_signaled_before;
2117 void ExtensionWebRequestEventRouter::ClearSignaled(uint64_t request_id,
2118 EventTypes event_type) {
2119 SignaledRequestMap::iterator iter = signaled_requests_.find(request_id);
2120 if (iter == signaled_requests_.end())
2121 return;
2122 iter->second &= ~event_type;
2125 // Special QuotaLimitHeuristic for WebRequestHandlerBehaviorChangedFunction.
2127 // Each call of webRequest.handlerBehaviorChanged() clears the in-memory cache
2128 // of WebKit at the time of the next page load (top level navigation event).
2129 // This quota heuristic is intended to limit the number of times the cache is
2130 // cleared by an extension.
2132 // As we want to account for the number of times the cache is really cleared
2133 // (opposed to the number of times webRequest.handlerBehaviorChanged() is
2134 // called), we cannot decide whether a call of
2135 // webRequest.handlerBehaviorChanged() should trigger a quota violation at the
2136 // time it is called. Instead we only decrement the bucket counter at the time
2137 // when the cache is cleared (when page loads happen).
2138 class ClearCacheQuotaHeuristic : public QuotaLimitHeuristic {
2139 public:
2140 ClearCacheQuotaHeuristic(const Config& config, BucketMapper* map)
2141 : QuotaLimitHeuristic(
2142 config,
2143 map,
2144 "MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES"),
2145 callback_registered_(false),
2146 weak_ptr_factory_(this) {}
2147 ~ClearCacheQuotaHeuristic() override {}
2148 bool Apply(Bucket* bucket, const base::TimeTicks& event_time) override;
2150 private:
2151 // Callback that is triggered by the ExtensionWebRequestEventRouter on a page
2152 // load.
2154 // We don't need to take care of the life time of |bucket|: It is owned by the
2155 // BucketMapper of our base class in |QuotaLimitHeuristic::bucket_mapper_|. As
2156 // long as |this| exists, the respective BucketMapper and its bucket will
2157 // exist as well.
2158 void OnPageLoad(Bucket* bucket);
2160 // Flag to prevent that we register more than one call back in-between
2161 // clearing the cache.
2162 bool callback_registered_;
2164 base::WeakPtrFactory<ClearCacheQuotaHeuristic> weak_ptr_factory_;
2166 DISALLOW_COPY_AND_ASSIGN(ClearCacheQuotaHeuristic);
2169 bool ClearCacheQuotaHeuristic::Apply(Bucket* bucket,
2170 const base::TimeTicks& event_time) {
2171 if (event_time > bucket->expiration())
2172 bucket->Reset(config(), event_time);
2174 // Call bucket->DeductToken() on a new page load, this is when
2175 // webRequest.handlerBehaviorChanged() clears the cache.
2176 if (!callback_registered_) {
2177 ExtensionWebRequestEventRouter::GetInstance()->AddCallbackForPageLoad(
2178 base::Bind(&ClearCacheQuotaHeuristic::OnPageLoad,
2179 weak_ptr_factory_.GetWeakPtr(),
2180 bucket));
2181 callback_registered_ = true;
2184 // We only check whether tokens are left here. Deducting a token happens in
2185 // OnPageLoad().
2186 return bucket->has_tokens();
2189 void ClearCacheQuotaHeuristic::OnPageLoad(Bucket* bucket) {
2190 callback_registered_ = false;
2191 bucket->DeductToken();
2194 bool WebRequestInternalAddEventListenerFunction::RunSync() {
2195 // Argument 0 is the callback, which we don't use here.
2196 ExtensionWebRequestEventRouter::RequestFilter filter;
2197 base::DictionaryValue* value = NULL;
2198 error_.clear();
2199 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &value));
2200 // Failure + an empty error string means a fatal error.
2201 EXTENSION_FUNCTION_VALIDATE(filter.InitFromValue(*value, &error_) ||
2202 !error_.empty());
2203 if (!error_.empty())
2204 return false;
2206 int extra_info_spec = 0;
2207 if (HasOptionalArgument(2)) {
2208 base::ListValue* value = NULL;
2209 EXTENSION_FUNCTION_VALIDATE(args_->GetList(2, &value));
2210 EXTENSION_FUNCTION_VALIDATE(
2211 ExtensionWebRequestEventRouter::ExtraInfoSpec::InitFromValue(
2212 *value, &extra_info_spec));
2215 std::string event_name;
2216 EXTENSION_FUNCTION_VALIDATE(args_->GetString(3, &event_name));
2218 std::string sub_event_name;
2219 EXTENSION_FUNCTION_VALIDATE(args_->GetString(4, &sub_event_name));
2221 int web_view_instance_id = 0;
2222 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(5, &web_view_instance_id));
2224 base::WeakPtr<IOThreadExtensionMessageFilter> ipc_sender = ipc_sender_weak();
2225 int embedder_process_id = ipc_sender ? 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 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 GetEventHistogramValue(event_name), event_name, sub_event_name,
2263 filter, extra_info_spec, embedder_process_id, web_view_instance_id,
2264 ipc_sender_weak());
2265 EXTENSION_FUNCTION_VALIDATE(success);
2267 helpers::ClearCacheOnNavigation();
2269 if (!extension_id_safe().empty()) {
2270 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
2271 base::Bind(&helpers::NotifyWebRequestAPIUsed,
2272 profile_id(), extension_id_safe()));
2275 return true;
2278 void WebRequestInternalEventHandledFunction::RespondWithError(
2279 const std::string& event_name,
2280 const std::string& sub_event_name,
2281 uint64_t request_id,
2282 scoped_ptr<ExtensionWebRequestEventRouter::EventResponse> response,
2283 const std::string& error) {
2284 error_ = error;
2285 ExtensionWebRequestEventRouter::GetInstance()->OnEventHandled(
2286 profile_id(),
2287 extension_id_safe(),
2288 event_name,
2289 sub_event_name,
2290 request_id,
2291 response.release());
2294 bool WebRequestInternalEventHandledFunction::RunSync() {
2295 std::string event_name;
2296 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &event_name));
2298 std::string sub_event_name;
2299 EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &sub_event_name));
2301 std::string request_id_str;
2302 EXTENSION_FUNCTION_VALIDATE(args_->GetString(2, &request_id_str));
2303 uint64_t request_id;
2304 EXTENSION_FUNCTION_VALIDATE(base::StringToUint64(request_id_str,
2305 &request_id));
2307 scoped_ptr<ExtensionWebRequestEventRouter::EventResponse> response;
2308 if (HasOptionalArgument(3)) {
2309 base::DictionaryValue* value = NULL;
2310 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(3, &value));
2312 if (!value->empty()) {
2313 base::Time install_time =
2314 extension_info_map()->GetInstallTime(extension_id_safe());
2315 response.reset(new ExtensionWebRequestEventRouter::EventResponse(
2316 extension_id_safe(), install_time));
2319 if (value->HasKey("cancel")) {
2320 // Don't allow cancel mixed with other keys.
2321 if (value->size() != 1) {
2322 RespondWithError(event_name,
2323 sub_event_name,
2324 request_id,
2325 response.Pass(),
2326 keys::kInvalidBlockingResponse);
2327 return false;
2330 bool cancel = false;
2331 EXTENSION_FUNCTION_VALIDATE(value->GetBoolean("cancel", &cancel));
2332 response->cancel = cancel;
2335 if (value->HasKey("redirectUrl")) {
2336 std::string new_url_str;
2337 EXTENSION_FUNCTION_VALIDATE(value->GetString("redirectUrl",
2338 &new_url_str));
2339 response->new_url = GURL(new_url_str);
2340 if (!response->new_url.is_valid()) {
2341 RespondWithError(event_name,
2342 sub_event_name,
2343 request_id,
2344 response.Pass(),
2345 ErrorUtils::FormatErrorMessage(
2346 keys::kInvalidRedirectUrl, new_url_str));
2347 return false;
2351 const bool has_request_headers = value->HasKey("requestHeaders");
2352 const bool has_response_headers = value->HasKey("responseHeaders");
2353 if (has_request_headers || has_response_headers) {
2354 if (has_request_headers && has_response_headers) {
2355 // Allow only one of the keys, not both.
2356 RespondWithError(event_name,
2357 sub_event_name,
2358 request_id,
2359 response.Pass(),
2360 keys::kInvalidHeaderKeyCombination);
2361 return false;
2364 base::ListValue* headers_value = NULL;
2365 scoped_ptr<net::HttpRequestHeaders> request_headers;
2366 scoped_ptr<helpers::ResponseHeaders> response_headers;
2367 if (has_request_headers) {
2368 request_headers.reset(new net::HttpRequestHeaders());
2369 EXTENSION_FUNCTION_VALIDATE(value->GetList(keys::kRequestHeadersKey,
2370 &headers_value));
2371 } else {
2372 response_headers.reset(new helpers::ResponseHeaders());
2373 EXTENSION_FUNCTION_VALIDATE(value->GetList(keys::kResponseHeadersKey,
2374 &headers_value));
2377 for (size_t i = 0; i < headers_value->GetSize(); ++i) {
2378 base::DictionaryValue* header_value = NULL;
2379 std::string name;
2380 std::string value;
2381 EXTENSION_FUNCTION_VALIDATE(
2382 headers_value->GetDictionary(i, &header_value));
2383 if (!FromHeaderDictionary(header_value, &name, &value)) {
2384 std::string serialized_header;
2385 base::JSONWriter::Write(*header_value, &serialized_header);
2386 RespondWithError(event_name,
2387 sub_event_name,
2388 request_id,
2389 response.Pass(),
2390 ErrorUtils::FormatErrorMessage(keys::kInvalidHeader,
2391 serialized_header));
2392 return false;
2394 if (!net::HttpUtil::IsValidHeaderName(name)) {
2395 RespondWithError(event_name,
2396 sub_event_name,
2397 request_id,
2398 response.Pass(),
2399 keys::kInvalidHeaderName);
2400 return false;
2402 if (!net::HttpUtil::IsValidHeaderValue(value)) {
2403 RespondWithError(event_name,
2404 sub_event_name,
2405 request_id,
2406 response.Pass(),
2407 ErrorUtils::FormatErrorMessage(
2408 keys::kInvalidHeaderValue, name));
2409 return false;
2411 if (has_request_headers)
2412 request_headers->SetHeader(name, value);
2413 else
2414 response_headers->push_back(helpers::ResponseHeader(name, value));
2416 if (has_request_headers)
2417 response->request_headers.reset(request_headers.release());
2418 else
2419 response->response_headers.reset(response_headers.release());
2422 if (value->HasKey(keys::kAuthCredentialsKey)) {
2423 base::DictionaryValue* credentials_value = NULL;
2424 EXTENSION_FUNCTION_VALIDATE(value->GetDictionary(
2425 keys::kAuthCredentialsKey,
2426 &credentials_value));
2427 base::string16 username;
2428 base::string16 password;
2429 EXTENSION_FUNCTION_VALIDATE(
2430 credentials_value->GetString(keys::kUsernameKey, &username));
2431 EXTENSION_FUNCTION_VALIDATE(
2432 credentials_value->GetString(keys::kPasswordKey, &password));
2433 response->auth_credentials.reset(
2434 new net::AuthCredentials(username, password));
2438 ExtensionWebRequestEventRouter::GetInstance()->OnEventHandled(
2439 profile_id(), extension_id_safe(), event_name, sub_event_name, request_id,
2440 response.release());
2442 return true;
2445 void WebRequestHandlerBehaviorChangedFunction::GetQuotaLimitHeuristics(
2446 QuotaLimitHeuristics* heuristics) const {
2447 QuotaLimitHeuristic::Config config = {
2448 // See web_request.json for current value.
2449 web_request::MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES,
2450 base::TimeDelta::FromMinutes(10)};
2451 QuotaLimitHeuristic::BucketMapper* bucket_mapper =
2452 new QuotaLimitHeuristic::SingletonBucketMapper();
2453 ClearCacheQuotaHeuristic* heuristic =
2454 new ClearCacheQuotaHeuristic(config, bucket_mapper);
2455 heuristics->push_back(heuristic);
2458 void WebRequestHandlerBehaviorChangedFunction::OnQuotaExceeded(
2459 const std::string& violation_error) {
2460 // Post warning message.
2461 WarningSet warnings;
2462 warnings.insert(
2463 Warning::CreateRepeatedCacheFlushesWarning(extension_id_safe()));
2464 BrowserThread::PostTask(
2465 BrowserThread::UI,
2466 FROM_HERE,
2467 base::Bind(&WarningService::NotifyWarningsOnUI, profile_id(), warnings));
2469 // Continue gracefully.
2470 RunSync();
2473 bool WebRequestHandlerBehaviorChangedFunction::RunSync() {
2474 helpers::ClearCacheOnNavigation();
2475 return true;
2478 } // namespace extensions