cygprofile: increase timeouts to allow showing web contents
[chromium-blink-merge.git] / extensions / browser / api / web_request / web_request_api.cc
blob40b9db7ddf0c080438019823b180f00b6bd38c03
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 const std::set<std::string> extension_ids =
163 extension_info_map->process_map().GetExtensionsInProcess(
164 info->GetChildID());
165 if (extension_ids.empty())
166 return false;
168 // Treat hosted apps as normal web pages (crbug.com/526413).
169 for (const std::string& extension_id : extension_ids) {
170 const Extension* extension =
171 extension_info_map->extensions().GetByID(extension_id);
172 if (extension && !extension->is_hosted_app())
173 return true;
175 return false;
178 void ExtractRequestRoutingInfo(const net::URLRequest* request,
179 int* render_process_host_id,
180 int* routing_id) {
181 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
182 if (!info)
183 return;
184 *render_process_host_id = info->GetChildID();
185 *routing_id = info->GetRouteID();
188 // Given a |request|, this function determines whether it originated from
189 // a <webview> guest process or not. If it is from a <webview> guest process,
190 // then |web_view_info| is returned with information about the instance ID
191 // that uniquely identifies the <webview> and its embedder.
192 bool GetWebViewInfo(const net::URLRequest* request,
193 WebViewRendererState::WebViewInfo* web_view_info) {
194 int render_process_host_id = -1;
195 int routing_id = -1;
196 ExtractRequestRoutingInfo(request, &render_process_host_id, &routing_id);
197 return WebViewRendererState::GetInstance()->GetInfo(
198 render_process_host_id, routing_id, web_view_info);
201 void ExtractRequestInfoDetails(const net::URLRequest* request,
202 bool* is_main_frame,
203 int* frame_id,
204 bool* parent_is_main_frame,
205 int* parent_frame_id,
206 int* render_process_host_id,
207 int* routing_id,
208 ResourceType* resource_type) {
209 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
210 if (!info)
211 return;
213 *frame_id = info->GetRenderFrameID();
214 *is_main_frame = info->IsMainFrame();
215 *parent_frame_id = info->GetParentRenderFrameID();
216 *parent_is_main_frame = info->ParentIsMainFrame();
217 *render_process_host_id = info->GetChildID();
218 *routing_id = info->GetRouteID();
220 // Restrict the resource type to the values we care about.
221 if (helpers::IsRelevantResourceType(info->GetResourceType()))
222 *resource_type = info->GetResourceType();
223 else
224 *resource_type = content::RESOURCE_TYPE_LAST_TYPE;
227 // Extracts the body from |request| and writes the data into |out|.
228 void ExtractRequestInfoBody(const net::URLRequest* request,
229 base::DictionaryValue* out) {
230 const net::UploadDataStream* upload_data = request->get_upload();
231 if (!upload_data ||
232 (request->method() != "POST" && request->method() != "PUT")) {
233 return; // Need to exit without "out->Set(keys::kRequestBodyKey, ...);" .
236 base::DictionaryValue* request_body = new base::DictionaryValue();
237 out->Set(keys::kRequestBodyKey, request_body);
239 // Get the data presenters, ordered by how specific they are.
240 ParsedDataPresenter parsed_data_presenter(*request);
241 RawDataPresenter raw_data_presenter;
242 UploadDataPresenter* const presenters[] = {
243 &parsed_data_presenter, // 1: any parseable forms? (Specific to forms.)
244 &raw_data_presenter // 2: any data at all? (Non-specific.)
246 // Keys for the results of the corresponding presenters.
247 static const char* const kKeys[] = {
248 keys::kRequestBodyFormDataKey,
249 keys::kRequestBodyRawKey
252 const ScopedVector<net::UploadElementReader>* readers =
253 upload_data->GetElementReaders();
254 bool some_succeeded = false;
255 if (readers) {
256 for (size_t i = 0; i < arraysize(presenters); ++i) {
257 for (const auto& reader : *readers)
258 presenters[i]->FeedNext(*reader);
259 if (presenters[i]->Succeeded()) {
260 request_body->Set(kKeys[i], presenters[i]->Result().release());
261 some_succeeded = true;
262 break;
266 if (!some_succeeded)
267 request_body->SetString(keys::kRequestBodyErrorKey, "Unknown error.");
270 // Converts a HttpHeaders dictionary to a |name|, |value| pair. Returns
271 // true if successful.
272 bool FromHeaderDictionary(const base::DictionaryValue* header_value,
273 std::string* name,
274 std::string* value) {
275 if (!header_value->GetString(keys::kHeaderNameKey, name))
276 return false;
278 // We require either a "value" or a "binaryValue" entry.
279 if (!(header_value->HasKey(keys::kHeaderValueKey) ^
280 header_value->HasKey(keys::kHeaderBinaryValueKey))) {
281 return false;
284 if (header_value->HasKey(keys::kHeaderValueKey)) {
285 if (!header_value->GetString(keys::kHeaderValueKey, value)) {
286 return false;
288 } else if (header_value->HasKey(keys::kHeaderBinaryValueKey)) {
289 const base::ListValue* list = NULL;
290 if (!header_value->HasKey(keys::kHeaderBinaryValueKey)) {
291 *value = "";
292 } else if (!header_value->GetList(keys::kHeaderBinaryValueKey, &list) ||
293 !helpers::CharListToString(list, value)) {
294 return false;
297 return true;
300 // Creates a list of HttpHeaders (see the extension API JSON). If |headers| is
301 // NULL, the list is empty. Ownership is passed to the caller.
302 base::ListValue* GetResponseHeadersList(
303 const net::HttpResponseHeaders* headers) {
304 base::ListValue* headers_value = new base::ListValue();
305 if (headers) {
306 void* iter = NULL;
307 std::string name;
308 std::string value;
309 while (headers->EnumerateHeaderLines(&iter, &name, &value))
310 headers_value->Append(helpers::CreateHeaderDictionary(name, value));
312 return headers_value;
315 base::ListValue* GetRequestHeadersList(const net::HttpRequestHeaders& headers) {
316 base::ListValue* headers_value = new base::ListValue();
317 for (net::HttpRequestHeaders::Iterator it(headers); it.GetNext(); )
318 headers_value->Append(
319 helpers::CreateHeaderDictionary(it.name(), it.value()));
320 return headers_value;
323 // Creates a base::StringValue with the status line of |headers|. If |headers|
324 // is NULL, an empty string is returned. Ownership is passed to the caller.
325 base::StringValue* GetStatusLine(net::HttpResponseHeaders* headers) {
326 return new base::StringValue(
327 headers ? headers->GetStatusLine() : std::string());
330 // Returns the response code from the response headers, or 200 by default.
331 // |headers| may be NULL, e.g. UrlRequestFileJobs do not send headers, so
332 // simulate their behavior.
333 int GetResponseCodeWithDefault(net::HttpResponseHeaders* headers) {
334 return headers ? headers->response_code() : 200;
337 // Sends an event to subscribers of chrome.declarativeWebRequest.onMessage or
338 // to subscribers of webview.onMessage if the action is being operated upon
339 // a <webview> guest renderer.
340 // |extension_id| identifies the extension that sends and receives the event.
341 // |is_web_view_guest| indicates whether the action is for a <webview>.
342 // |web_view_info| is a struct containing information about the <webview>
343 // embedder.
344 // |event_argument| is passed to the event listener.
345 void SendOnMessageEventOnUI(
346 void* browser_context_id,
347 const std::string& extension_id,
348 bool is_web_view_guest,
349 const WebViewRendererState::WebViewInfo& web_view_info,
350 scoped_ptr<base::DictionaryValue> event_argument) {
351 DCHECK_CURRENTLY_ON(BrowserThread::UI);
353 content::BrowserContext* browser_context =
354 reinterpret_cast<content::BrowserContext*>(browser_context_id);
355 if (!ExtensionsBrowserClient::Get()->IsValidContext(browser_context))
356 return;
358 scoped_ptr<base::ListValue> event_args(new base::ListValue);
359 event_args->Append(event_argument.release());
361 EventRouter* event_router = EventRouter::Get(browser_context);
363 EventFilteringInfo event_filtering_info;
365 events::HistogramValue histogram_value = events::UNKNOWN;
366 std::string event_name;
367 // The instance ID uniquely identifies a <webview> instance within an embedder
368 // process. We use a filter here so that only event listeners for a particular
369 // <webview> will fire.
370 if (is_web_view_guest) {
371 event_filtering_info.SetInstanceID(web_view_info.instance_id);
372 histogram_value = events::WEB_VIEW_INTERNAL_ON_MESSAGE;
373 event_name = webview::kEventMessage;
374 } else {
375 histogram_value = events::DECLARATIVE_WEB_REQUEST_ON_MESSAGE;
376 event_name = declarative_keys::kOnMessage;
379 scoped_ptr<Event> event(new Event(
380 histogram_value, event_name, event_args.Pass(), browser_context, GURL(),
381 EventRouter::USER_GESTURE_UNKNOWN, event_filtering_info));
382 event_router->DispatchEventToExtension(extension_id, event.Pass());
385 void RemoveEventListenerOnIOThread(
386 void* browser_context,
387 const std::string& extension_id,
388 const std::string& sub_event_name,
389 int embedder_process_id,
390 int web_view_instance_id) {
391 DCHECK_CURRENTLY_ON(BrowserThread::IO);
392 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(
393 browser_context, extension_id, sub_event_name,
394 embedder_process_id, web_view_instance_id);
397 events::HistogramValue GetEventHistogramValue(const std::string& event_name) {
398 // Event names will either be webRequest events, or guest view (probably web
399 // view) events that map to webRequest events. Check webRequest first.
400 static struct ValueAndName {
401 events::HistogramValue histogram_value;
402 const char* const event_name;
403 } values_and_names[] = {
404 {events::WEB_REQUEST_ON_BEFORE_REDIRECT, keys::kOnBeforeRedirectEvent},
405 {events::WEB_REQUEST_ON_BEFORE_REQUEST,
406 web_request::OnBeforeRequest::kEventName},
407 {events::WEB_REQUEST_ON_BEFORE_SEND_HEADERS,
408 keys::kOnBeforeSendHeadersEvent},
409 {events::WEB_REQUEST_ON_COMPLETED, keys::kOnCompletedEvent},
410 {events::WEB_REQUEST_ON_ERROR_OCCURRED,
411 web_request::OnErrorOccurred::kEventName},
412 {events::WEB_REQUEST_ON_SEND_HEADERS, keys::kOnSendHeadersEvent},
413 {events::WEB_REQUEST_ON_AUTH_REQUIRED, keys::kOnAuthRequiredEvent},
414 {events::WEB_REQUEST_ON_RESPONSE_STARTED, keys::kOnResponseStartedEvent},
415 {events::WEB_REQUEST_ON_HEADERS_RECEIVED, keys::kOnHeadersReceivedEvent}};
416 COMPILE_ASSERT(arraysize(kWebRequestEvents) == arraysize(values_and_names),
417 "kWebRequestEvents and values_and_names must be the same");
418 for (const ValueAndName& value_and_name : values_and_names) {
419 if (value_and_name.event_name == event_name)
420 return value_and_name.histogram_value;
423 // If there is no webRequest event, it might be a guest view webRequest event.
424 events::HistogramValue guest_view_histogram_value =
425 guest_view_events::GetEventHistogramValue(event_name);
426 if (guest_view_histogram_value != events::UNKNOWN)
427 return guest_view_histogram_value;
429 // There is no histogram value for this event name. It should be added to
430 // either the mapping here, or in guest_view_events.
431 NOTREACHED() << "Event " << event_name << " must have a histogram value";
432 return events::UNKNOWN;
435 // We hide events from the system context as well as sensitive requests.
436 bool ShouldHideEvent(void* browser_context,
437 const InfoMap* extension_info_map,
438 const net::URLRequest* request) {
439 return (!browser_context ||
440 WebRequestPermissions::HideRequest(extension_info_map, request));
443 } // namespace
445 WebRequestAPI::WebRequestAPI(content::BrowserContext* context)
446 : browser_context_(context) {
447 EventRouter* event_router = EventRouter::Get(browser_context_);
448 for (size_t i = 0; i < arraysize(kWebRequestEvents); ++i) {
449 // Observe the webRequest event.
450 std::string event_name = kWebRequestEvents[i];
451 event_router->RegisterObserver(this, event_name);
453 // Also observe the corresponding webview event.
454 event_name.replace(
455 0, sizeof(kWebRequestEventPrefix) - 1, webview::kWebViewEventPrefix);
456 event_router->RegisterObserver(this, event_name);
460 WebRequestAPI::~WebRequestAPI() {
461 EventRouter::Get(browser_context_)->UnregisterObserver(this);
464 static base::LazyInstance<BrowserContextKeyedAPIFactory<WebRequestAPI> >
465 g_factory = LAZY_INSTANCE_INITIALIZER;
467 // static
468 BrowserContextKeyedAPIFactory<WebRequestAPI>*
469 WebRequestAPI::GetFactoryInstance() {
470 return g_factory.Pointer();
473 void WebRequestAPI::OnListenerRemoved(const EventListenerInfo& details) {
474 DCHECK_CURRENTLY_ON(BrowserThread::UI);
475 // Note that details.event_name includes the sub-event details (e.g. "/123").
476 // TODO(fsamuel): <webview> events will not be removed through this code path.
477 // <webview> events will be removed in RemoveWebViewEventListeners. Ideally,
478 // this code should be decoupled from extensions, we should use the host ID
479 // instead, and not have two different code paths. This is a huge undertaking
480 // unfortunately, so we'll resort to two code paths for now.
481 BrowserThread::PostTask(BrowserThread::IO,
482 FROM_HERE,
483 base::Bind(&RemoveEventListenerOnIOThread,
484 details.browser_context,
485 details.extension_id,
486 details.event_name,
487 0 /* embedder_process_id (ignored) */,
488 0 /* web_view_instance_id */));
491 // Represents a single unique listener to an event, along with whatever filter
492 // parameters and extra_info_spec were specified at the time the listener was
493 // added.
494 // NOTE(benjhayden) New APIs should not use this sub_event_name trick! It does
495 // not play well with event pages. See downloads.onDeterminingFilename and
496 // ExtensionDownloadsEventRouter for an alternative approach.
497 struct ExtensionWebRequestEventRouter::EventListener {
498 std::string extension_id;
499 std::string extension_name;
500 events::HistogramValue histogram_value;
501 std::string sub_event_name;
502 RequestFilter filter;
503 int extra_info_spec;
504 int embedder_process_id;
505 int web_view_instance_id;
506 base::WeakPtr<IPC::Sender> ipc_sender;
507 mutable std::set<uint64_t> blocked_requests;
509 // Comparator to work with std::set.
510 bool operator<(const EventListener& that) const {
511 if (extension_id != that.extension_id)
512 return extension_id < that.extension_id;
514 if (sub_event_name != that.sub_event_name)
515 return sub_event_name < that.sub_event_name;
517 if (web_view_instance_id != that.web_view_instance_id)
518 return web_view_instance_id < that.web_view_instance_id;
520 if (web_view_instance_id == 0) {
521 // Do not filter by process ID for non-webviews, because this comparator
522 // is also used to find and remove an event listener when an extension is
523 // unloaded. At this point, the event listener cannot be mapped back to
524 // the original process, so 0 is used instead of the actual process ID.
525 DCHECK(embedder_process_id == 0 || that.embedder_process_id == 0);
526 return false;
529 if (embedder_process_id != that.embedder_process_id)
530 return embedder_process_id < that.embedder_process_id;
532 return false;
535 EventListener()
536 : histogram_value(events::UNKNOWN),
537 extra_info_spec(0),
538 embedder_process_id(0),
539 web_view_instance_id(0) {}
542 // Contains info about requests that are blocked waiting for a response from
543 // an extension.
544 struct ExtensionWebRequestEventRouter::BlockedRequest {
545 // The request that is being blocked.
546 net::URLRequest* request;
548 // Whether the request originates from an incognito tab.
549 bool is_incognito;
551 // The event that we're currently blocked on.
552 EventTypes event;
554 // The number of event handlers that we are awaiting a response from.
555 int num_handlers_blocking;
557 // Pointer to NetLog to report significant changes to the request for
558 // debugging.
559 const net::BoundNetLog* net_log;
561 // The callback to call when we get a response from all event handlers.
562 net::CompletionCallback callback;
564 // If non-empty, this contains the new URL that the request will redirect to.
565 // Only valid for OnBeforeRequest and OnHeadersReceived.
566 GURL* new_url;
568 // The request headers that will be issued along with this request. Only valid
569 // for OnBeforeSendHeaders.
570 net::HttpRequestHeaders* request_headers;
572 // The response headers that were received from the server. Only valid for
573 // OnHeadersReceived.
574 scoped_refptr<const net::HttpResponseHeaders> original_response_headers;
576 // Location where to override response headers. Only valid for
577 // OnHeadersReceived.
578 scoped_refptr<net::HttpResponseHeaders>* override_response_headers;
580 // If non-empty, this contains the auth credentials that may be filled in.
581 // Only valid for OnAuthRequired.
582 net::AuthCredentials* auth_credentials;
584 // The callback to invoke for auth. If |auth_callback.is_null()| is false,
585 // |callback| must be NULL.
586 // Only valid for OnAuthRequired.
587 net::NetworkDelegate::AuthCallback auth_callback;
589 // Time the request was paused. Used for logging purposes.
590 base::Time blocking_time;
592 // Changes requested by extensions.
593 helpers::EventResponseDeltas response_deltas;
595 // Provider of meta data about extensions, only used and non-NULL for events
596 // that are delayed until the rules registry is ready.
597 const InfoMap* extension_info_map;
599 BlockedRequest()
600 : request(NULL),
601 is_incognito(false),
602 event(kInvalidEvent),
603 num_handlers_blocking(0),
604 net_log(NULL),
605 new_url(NULL),
606 request_headers(NULL),
607 override_response_headers(NULL),
608 auth_credentials(NULL),
609 extension_info_map(NULL) {}
612 bool ExtensionWebRequestEventRouter::RequestFilter::InitFromValue(
613 const base::DictionaryValue& value, std::string* error) {
614 if (!value.HasKey("urls"))
615 return false;
617 for (base::DictionaryValue::Iterator it(value); !it.IsAtEnd(); it.Advance()) {
618 if (it.key() == "urls") {
619 const base::ListValue* urls_value = NULL;
620 if (!it.value().GetAsList(&urls_value))
621 return false;
622 for (size_t i = 0; i < urls_value->GetSize(); ++i) {
623 std::string url;
624 URLPattern pattern(
625 URLPattern::SCHEME_HTTP | URLPattern::SCHEME_HTTPS |
626 URLPattern::SCHEME_FTP | URLPattern::SCHEME_FILE |
627 URLPattern::SCHEME_EXTENSION);
628 if (!urls_value->GetString(i, &url) ||
629 pattern.Parse(url) != URLPattern::PARSE_SUCCESS) {
630 *error = ErrorUtils::FormatErrorMessage(
631 keys::kInvalidRequestFilterUrl, url);
632 return false;
634 urls.AddPattern(pattern);
636 } else if (it.key() == "types") {
637 const base::ListValue* types_value = NULL;
638 if (!it.value().GetAsList(&types_value))
639 return false;
640 for (size_t i = 0; i < types_value->GetSize(); ++i) {
641 std::string type_str;
642 ResourceType type;
643 if (!types_value->GetString(i, &type_str) ||
644 !helpers::ParseResourceType(type_str, &type)) {
645 return false;
647 types.push_back(type);
649 } else if (it.key() == "tabId") {
650 if (!it.value().GetAsInteger(&tab_id))
651 return false;
652 } else if (it.key() == "windowId") {
653 if (!it.value().GetAsInteger(&window_id))
654 return false;
655 } else {
656 return false;
659 return true;
662 // static
663 bool ExtensionWebRequestEventRouter::ExtraInfoSpec::InitFromValue(
664 const base::ListValue& value, int* extra_info_spec) {
665 *extra_info_spec = 0;
666 for (size_t i = 0; i < value.GetSize(); ++i) {
667 std::string str;
668 if (!value.GetString(i, &str))
669 return false;
671 if (str == "requestHeaders")
672 *extra_info_spec |= REQUEST_HEADERS;
673 else if (str == "responseHeaders")
674 *extra_info_spec |= RESPONSE_HEADERS;
675 else if (str == "blocking")
676 *extra_info_spec |= BLOCKING;
677 else if (str == "asyncBlocking")
678 *extra_info_spec |= ASYNC_BLOCKING;
679 else if (str == "requestBody")
680 *extra_info_spec |= REQUEST_BODY;
681 else
682 return false;
684 // BLOCKING and ASYNC_BLOCKING are mutually exclusive.
685 if ((*extra_info_spec & BLOCKING) && (*extra_info_spec & ASYNC_BLOCKING))
686 return false;
688 return true;
692 ExtensionWebRequestEventRouter::EventResponse::EventResponse(
693 const std::string& extension_id, const base::Time& extension_install_time)
694 : extension_id(extension_id),
695 extension_install_time(extension_install_time),
696 cancel(false) {
699 ExtensionWebRequestEventRouter::EventResponse::~EventResponse() {
702 ExtensionWebRequestEventRouter::RequestFilter::RequestFilter()
703 : tab_id(-1), window_id(-1) {
706 ExtensionWebRequestEventRouter::RequestFilter::~RequestFilter() {
710 // ExtensionWebRequestEventRouter
713 // static
714 ExtensionWebRequestEventRouter* ExtensionWebRequestEventRouter::GetInstance() {
715 return Singleton<ExtensionWebRequestEventRouter>::get();
718 ExtensionWebRequestEventRouter::ExtensionWebRequestEventRouter()
719 : request_time_tracker_(new ExtensionWebRequestTimeTracker) {
720 web_request_event_router_delegate_.reset(
721 ExtensionsAPIClient::Get()->CreateWebRequestEventRouterDelegate());
724 ExtensionWebRequestEventRouter::~ExtensionWebRequestEventRouter() {
727 void ExtensionWebRequestEventRouter::RegisterRulesRegistry(
728 void* browser_context,
729 int rules_registry_id,
730 scoped_refptr<WebRequestRulesRegistry> rules_registry) {
731 RulesRegistryKey key(browser_context, rules_registry_id);
732 if (rules_registry.get())
733 rules_registries_[key] = rules_registry;
734 else
735 rules_registries_.erase(key);
738 void ExtensionWebRequestEventRouter::ExtractRequestInfo(
739 const net::URLRequest* request,
740 base::DictionaryValue* out) {
741 bool is_main_frame = false;
742 int frame_id = -1;
743 bool parent_is_main_frame = false;
744 int parent_frame_id = -1;
745 int frame_id_for_extension = -1;
746 int parent_frame_id_for_extension = -1;
747 int render_process_host_id = -1;
748 int routing_id = -1;
749 ResourceType resource_type = content::RESOURCE_TYPE_LAST_TYPE;
750 ExtractRequestInfoDetails(request, &is_main_frame, &frame_id,
751 &parent_is_main_frame, &parent_frame_id,
752 &render_process_host_id, &routing_id,
753 &resource_type);
754 frame_id_for_extension = GetFrameId(is_main_frame, frame_id);
755 parent_frame_id_for_extension = GetFrameId(parent_is_main_frame,
756 parent_frame_id);
758 out->SetString(keys::kRequestIdKey,
759 base::Uint64ToString(request->identifier()));
760 out->SetString(keys::kUrlKey, request->url().spec());
761 out->SetString(keys::kMethodKey, request->method());
762 out->SetInteger(keys::kFrameIdKey, frame_id_for_extension);
763 out->SetInteger(keys::kParentFrameIdKey, parent_frame_id_for_extension);
764 out->SetString(keys::kTypeKey, helpers::ResourceTypeToString(resource_type));
765 out->SetDouble(keys::kTimeStampKey, base::Time::Now().ToDoubleT() * 1000);
766 if (web_request_event_router_delegate_) {
767 web_request_event_router_delegate_->ExtractExtraRequestDetails(
768 request, out);
772 int ExtensionWebRequestEventRouter::OnBeforeRequest(
773 void* browser_context,
774 const InfoMap* extension_info_map,
775 net::URLRequest* request,
776 const net::CompletionCallback& callback,
777 GURL* new_url) {
778 if (ShouldHideEvent(browser_context, extension_info_map, request))
779 return net::OK;
781 if (IsPageLoad(request))
782 NotifyPageLoad();
784 request_time_tracker_->LogRequestStartTime(request->identifier(),
785 base::Time::Now(),
786 request->url(),
787 browser_context);
789 // Whether to initialized |blocked_requests_|.
790 bool initialize_blocked_requests = false;
792 initialize_blocked_requests |=
793 ProcessDeclarativeRules(browser_context, extension_info_map,
794 web_request::OnBeforeRequest::kEventName, request,
795 ON_BEFORE_REQUEST, NULL);
797 int extra_info_spec = 0;
798 EventListeners listeners = GetMatchingListeners(
799 browser_context, extension_info_map,
800 web_request::OnBeforeRequest::kEventName, request, &extra_info_spec);
801 if (!listeners.empty() &&
802 !GetAndSetSignaled(request->identifier(), kOnBeforeRequest)) {
803 base::ListValue args;
804 base::DictionaryValue* dict = new base::DictionaryValue();
805 ExtractRequestInfo(request, dict);
806 if (extra_info_spec & ExtraInfoSpec::REQUEST_BODY)
807 ExtractRequestInfoBody(request, dict);
808 args.Append(dict);
810 initialize_blocked_requests |=
811 DispatchEvent(browser_context, request, listeners, args);
814 if (!initialize_blocked_requests)
815 return net::OK; // Nobody saw a reason for modifying the request.
817 BlockedRequest& blocked_request = blocked_requests_[request->identifier()];
818 blocked_request.event = kOnBeforeRequest;
819 blocked_request.is_incognito |= IsIncognitoBrowserContext(browser_context);
820 blocked_request.request = request;
821 blocked_request.callback = callback;
822 blocked_request.new_url = new_url;
823 blocked_request.net_log = &request->net_log();
825 if (blocked_request.num_handlers_blocking == 0) {
826 // If there are no blocking handlers, only the declarative rules tried
827 // to modify the request and we can respond synchronously.
828 return ExecuteDeltas(browser_context, request->identifier(),
829 false /* call_callback*/);
831 return net::ERR_IO_PENDING;
834 int ExtensionWebRequestEventRouter::OnBeforeSendHeaders(
835 void* browser_context,
836 const InfoMap* extension_info_map,
837 net::URLRequest* request,
838 const net::CompletionCallback& callback,
839 net::HttpRequestHeaders* headers) {
840 if (ShouldHideEvent(browser_context, extension_info_map, request))
841 return net::OK;
843 bool initialize_blocked_requests = false;
845 initialize_blocked_requests |= ProcessDeclarativeRules(
846 browser_context, extension_info_map, keys::kOnBeforeSendHeadersEvent,
847 request, ON_BEFORE_SEND_HEADERS, NULL);
849 int extra_info_spec = 0;
850 EventListeners listeners = GetMatchingListeners(
851 browser_context, extension_info_map, keys::kOnBeforeSendHeadersEvent,
852 request, &extra_info_spec);
853 if (!listeners.empty() &&
854 !GetAndSetSignaled(request->identifier(), kOnBeforeSendHeaders)) {
855 base::ListValue args;
856 base::DictionaryValue* dict = new base::DictionaryValue();
857 ExtractRequestInfo(request, dict);
858 if (extra_info_spec & ExtraInfoSpec::REQUEST_HEADERS)
859 dict->Set(keys::kRequestHeadersKey, GetRequestHeadersList(*headers));
860 args.Append(dict);
862 initialize_blocked_requests |=
863 DispatchEvent(browser_context, request, listeners, args);
866 if (!initialize_blocked_requests)
867 return net::OK; // Nobody saw a reason for modifying the request.
869 BlockedRequest& blocked_request = blocked_requests_[request->identifier()];
870 blocked_request.event = kOnBeforeSendHeaders;
871 blocked_request.is_incognito |= IsIncognitoBrowserContext(browser_context);
872 blocked_request.request = request;
873 blocked_request.callback = callback;
874 blocked_request.request_headers = headers;
875 blocked_request.net_log = &request->net_log();
877 if (blocked_request.num_handlers_blocking == 0) {
878 // If there are no blocking handlers, only the declarative rules tried
879 // to modify the request and we can respond synchronously.
880 return ExecuteDeltas(browser_context, request->identifier(),
881 false /* call_callback*/);
883 return net::ERR_IO_PENDING;
886 void ExtensionWebRequestEventRouter::OnSendHeaders(
887 void* browser_context,
888 const InfoMap* extension_info_map,
889 net::URLRequest* request,
890 const net::HttpRequestHeaders& headers) {
891 if (ShouldHideEvent(browser_context, extension_info_map, request))
892 return;
894 if (GetAndSetSignaled(request->identifier(), kOnSendHeaders))
895 return;
897 ClearSignaled(request->identifier(), kOnBeforeRedirect);
899 int extra_info_spec = 0;
900 EventListeners listeners = GetMatchingListeners(
901 browser_context, extension_info_map, keys::kOnSendHeadersEvent, request,
902 &extra_info_spec);
903 if (listeners.empty())
904 return;
906 base::ListValue args;
907 base::DictionaryValue* dict = new base::DictionaryValue();
908 ExtractRequestInfo(request, dict);
909 if (extra_info_spec & ExtraInfoSpec::REQUEST_HEADERS)
910 dict->Set(keys::kRequestHeadersKey, GetRequestHeadersList(headers));
911 args.Append(dict);
913 DispatchEvent(browser_context, request, listeners, args);
916 int ExtensionWebRequestEventRouter::OnHeadersReceived(
917 void* browser_context,
918 const InfoMap* extension_info_map,
919 net::URLRequest* request,
920 const net::CompletionCallback& callback,
921 const net::HttpResponseHeaders* original_response_headers,
922 scoped_refptr<net::HttpResponseHeaders>* override_response_headers,
923 GURL* allowed_unsafe_redirect_url) {
924 if (ShouldHideEvent(browser_context, extension_info_map, request))
925 return net::OK;
927 bool initialize_blocked_requests = false;
929 initialize_blocked_requests |= ProcessDeclarativeRules(
930 browser_context, extension_info_map, keys::kOnHeadersReceivedEvent,
931 request, ON_HEADERS_RECEIVED, original_response_headers);
933 int extra_info_spec = 0;
934 EventListeners listeners = GetMatchingListeners(
935 browser_context, extension_info_map, keys::kOnHeadersReceivedEvent,
936 request, &extra_info_spec);
938 if (!listeners.empty() &&
939 !GetAndSetSignaled(request->identifier(), kOnHeadersReceived)) {
940 base::ListValue args;
941 base::DictionaryValue* dict = new base::DictionaryValue();
942 ExtractRequestInfo(request, dict);
943 dict->SetString(keys::kStatusLineKey,
944 original_response_headers->GetStatusLine());
945 dict->SetInteger(keys::kStatusCodeKey,
946 original_response_headers->response_code());
947 if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
948 dict->Set(keys::kResponseHeadersKey,
949 GetResponseHeadersList(original_response_headers));
951 args.Append(dict);
953 initialize_blocked_requests |=
954 DispatchEvent(browser_context, request, listeners, args);
957 if (!initialize_blocked_requests)
958 return net::OK; // Nobody saw a reason for modifying the request.
960 BlockedRequest& blocked_request = blocked_requests_[request->identifier()];
961 blocked_request.event = kOnHeadersReceived;
962 blocked_request.is_incognito |= IsIncognitoBrowserContext(browser_context);
963 blocked_request.request = request;
964 blocked_request.callback = callback;
965 blocked_request.net_log = &request->net_log();
966 blocked_request.override_response_headers = override_response_headers;
967 blocked_request.original_response_headers = original_response_headers;
968 blocked_request.new_url = allowed_unsafe_redirect_url;
970 if (blocked_request.num_handlers_blocking == 0) {
971 // If there are no blocking handlers, only the declarative rules tried
972 // to modify the request and we can respond synchronously.
973 return ExecuteDeltas(browser_context, request->identifier(),
974 false /* call_callback*/);
976 return net::ERR_IO_PENDING;
979 net::NetworkDelegate::AuthRequiredResponse
980 ExtensionWebRequestEventRouter::OnAuthRequired(
981 void* browser_context,
982 const InfoMap* extension_info_map,
983 net::URLRequest* request,
984 const net::AuthChallengeInfo& auth_info,
985 const net::NetworkDelegate::AuthCallback& callback,
986 net::AuthCredentials* credentials) {
987 // No browser_context means that this is for authentication challenges in the
988 // system context. Skip in that case. Also skip sensitive requests.
989 if (!browser_context ||
990 WebRequestPermissions::HideRequest(extension_info_map, request)) {
991 return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION;
994 int extra_info_spec = 0;
995 EventListeners listeners = GetMatchingListeners(
996 browser_context, extension_info_map, keys::kOnAuthRequiredEvent, request,
997 &extra_info_spec);
998 if (listeners.empty())
999 return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION;
1001 base::ListValue args;
1002 base::DictionaryValue* dict = new base::DictionaryValue();
1003 ExtractRequestInfo(request, dict);
1004 dict->SetBoolean(keys::kIsProxyKey, auth_info.is_proxy);
1005 if (!auth_info.scheme.empty())
1006 dict->SetString(keys::kSchemeKey, auth_info.scheme);
1007 if (!auth_info.realm.empty())
1008 dict->SetString(keys::kRealmKey, auth_info.realm);
1009 base::DictionaryValue* challenger = new base::DictionaryValue();
1010 challenger->SetString(keys::kHostKey, auth_info.challenger.host());
1011 challenger->SetInteger(keys::kPortKey, auth_info.challenger.port());
1012 dict->Set(keys::kChallengerKey, challenger);
1013 dict->Set(keys::kStatusLineKey, GetStatusLine(request->response_headers()));
1014 if (request->response_headers()) {
1015 dict->SetInteger(keys::kStatusCodeKey,
1016 request->response_headers()->response_code());
1018 if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
1019 dict->Set(keys::kResponseHeadersKey,
1020 GetResponseHeadersList(request->response_headers()));
1022 args.Append(dict);
1024 if (DispatchEvent(browser_context, request, listeners, args)) {
1025 BlockedRequest& blocked_request = blocked_requests_[request->identifier()];
1026 blocked_request.event = kOnAuthRequired;
1027 blocked_request.is_incognito |= IsIncognitoBrowserContext(browser_context);
1028 blocked_request.request = request;
1029 blocked_request.auth_callback = callback;
1030 blocked_request.auth_credentials = credentials;
1031 blocked_request.net_log = &request->net_log();
1032 return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_IO_PENDING;
1034 return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION;
1037 void ExtensionWebRequestEventRouter::OnBeforeRedirect(
1038 void* browser_context,
1039 const InfoMap* extension_info_map,
1040 net::URLRequest* request,
1041 const GURL& new_location) {
1042 if (ShouldHideEvent(browser_context, extension_info_map, request))
1043 return;
1045 if (GetAndSetSignaled(request->identifier(), kOnBeforeRedirect))
1046 return;
1048 ClearSignaled(request->identifier(), kOnBeforeRequest);
1049 ClearSignaled(request->identifier(), kOnBeforeSendHeaders);
1050 ClearSignaled(request->identifier(), kOnSendHeaders);
1051 ClearSignaled(request->identifier(), kOnHeadersReceived);
1053 int extra_info_spec = 0;
1054 EventListeners listeners = GetMatchingListeners(
1055 browser_context, extension_info_map, keys::kOnBeforeRedirectEvent,
1056 request, &extra_info_spec);
1057 if (listeners.empty())
1058 return;
1060 int http_status_code = request->GetResponseCode();
1062 std::string response_ip = request->GetSocketAddress().host();
1064 base::ListValue args;
1065 base::DictionaryValue* dict = new base::DictionaryValue();
1066 ExtractRequestInfo(request, dict);
1067 dict->SetString(keys::kRedirectUrlKey, new_location.spec());
1068 dict->SetInteger(keys::kStatusCodeKey, http_status_code);
1069 if (!response_ip.empty())
1070 dict->SetString(keys::kIpKey, response_ip);
1071 dict->SetBoolean(keys::kFromCache, request->was_cached());
1072 dict->Set(keys::kStatusLineKey, GetStatusLine(request->response_headers()));
1073 if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
1074 dict->Set(keys::kResponseHeadersKey,
1075 GetResponseHeadersList(request->response_headers()));
1077 args.Append(dict);
1079 DispatchEvent(browser_context, request, listeners, args);
1082 void ExtensionWebRequestEventRouter::OnResponseStarted(
1083 void* browser_context,
1084 const InfoMap* extension_info_map,
1085 net::URLRequest* request) {
1086 if (ShouldHideEvent(browser_context, extension_info_map, request))
1087 return;
1089 // OnResponseStarted is even triggered, when the request was cancelled.
1090 if (request->status().status() != net::URLRequestStatus::SUCCESS)
1091 return;
1093 int extra_info_spec = 0;
1094 EventListeners listeners = GetMatchingListeners(
1095 browser_context, extension_info_map, keys::kOnResponseStartedEvent,
1096 request, &extra_info_spec);
1097 if (listeners.empty())
1098 return;
1100 std::string response_ip = request->GetSocketAddress().host();
1102 base::ListValue args;
1103 base::DictionaryValue* dict = new base::DictionaryValue();
1104 ExtractRequestInfo(request, dict);
1105 if (!response_ip.empty())
1106 dict->SetString(keys::kIpKey, response_ip);
1107 dict->SetBoolean(keys::kFromCache, request->was_cached());
1108 dict->SetInteger(keys::kStatusCodeKey,
1109 GetResponseCodeWithDefault(request->response_headers()));
1110 dict->Set(keys::kStatusLineKey, GetStatusLine(request->response_headers()));
1111 if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
1112 dict->Set(keys::kResponseHeadersKey,
1113 GetResponseHeadersList(request->response_headers()));
1115 args.Append(dict);
1117 DispatchEvent(browser_context, request, listeners, args);
1120 void ExtensionWebRequestEventRouter::OnCompleted(
1121 void* browser_context,
1122 const InfoMap* extension_info_map,
1123 net::URLRequest* request) {
1124 // We hide events from the system context as well as sensitive requests.
1125 // However, if the request first became sensitive after redirecting we have
1126 // already signaled it and thus we have to signal the end of it. This is
1127 // risk-free because the handler cannot modify the request now.
1128 if (!browser_context ||
1129 (WebRequestPermissions::HideRequest(extension_info_map, request) &&
1130 !WasSignaled(*request))) {
1131 return;
1134 request_time_tracker_->LogRequestEndTime(request->identifier(),
1135 base::Time::Now());
1137 DCHECK(request->status().status() == net::URLRequestStatus::SUCCESS);
1139 DCHECK(!GetAndSetSignaled(request->identifier(), kOnCompleted));
1141 ClearPendingCallbacks(request);
1143 int extra_info_spec = 0;
1144 EventListeners listeners =
1145 GetMatchingListeners(browser_context, extension_info_map,
1146 keys::kOnCompletedEvent, request, &extra_info_spec);
1147 if (listeners.empty())
1148 return;
1150 std::string response_ip = request->GetSocketAddress().host();
1152 base::ListValue args;
1153 base::DictionaryValue* dict = new base::DictionaryValue();
1154 ExtractRequestInfo(request, dict);
1155 dict->SetInteger(keys::kStatusCodeKey,
1156 GetResponseCodeWithDefault(request->response_headers()));
1157 if (!response_ip.empty())
1158 dict->SetString(keys::kIpKey, response_ip);
1159 dict->SetBoolean(keys::kFromCache, request->was_cached());
1160 dict->Set(keys::kStatusLineKey, GetStatusLine(request->response_headers()));
1161 if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
1162 dict->Set(keys::kResponseHeadersKey,
1163 GetResponseHeadersList(request->response_headers()));
1165 args.Append(dict);
1167 DispatchEvent(browser_context, request, listeners, args);
1170 void ExtensionWebRequestEventRouter::OnErrorOccurred(
1171 void* browser_context,
1172 const InfoMap* extension_info_map,
1173 net::URLRequest* request,
1174 bool started) {
1175 // We hide events from the system context as well as sensitive requests.
1176 // However, if the request first became sensitive after redirecting we have
1177 // already signaled it and thus we have to signal the end of it. This is
1178 // risk-free because the handler cannot modify the request now.
1179 if (!browser_context ||
1180 (WebRequestPermissions::HideRequest(extension_info_map, request) &&
1181 !WasSignaled(*request))) {
1182 return;
1185 request_time_tracker_->LogRequestEndTime(request->identifier(),
1186 base::Time::Now());
1188 DCHECK(request->status().status() == net::URLRequestStatus::FAILED ||
1189 request->status().status() == net::URLRequestStatus::CANCELED);
1191 DCHECK(!GetAndSetSignaled(request->identifier(), kOnErrorOccurred));
1193 ClearPendingCallbacks(request);
1195 int extra_info_spec = 0;
1196 EventListeners listeners = GetMatchingListeners(
1197 browser_context, extension_info_map,
1198 web_request::OnErrorOccurred::kEventName, request, &extra_info_spec);
1199 if (listeners.empty())
1200 return;
1202 base::ListValue args;
1203 base::DictionaryValue* dict = new base::DictionaryValue();
1204 ExtractRequestInfo(request, dict);
1205 if (started) {
1206 std::string response_ip = request->GetSocketAddress().host();
1207 if (!response_ip.empty())
1208 dict->SetString(keys::kIpKey, response_ip);
1210 dict->SetBoolean(keys::kFromCache, request->was_cached());
1211 dict->SetString(keys::kErrorKey,
1212 net::ErrorToString(request->status().error()));
1213 args.Append(dict);
1215 DispatchEvent(browser_context, request, listeners, args);
1218 void ExtensionWebRequestEventRouter::OnURLRequestDestroyed(
1219 void* browser_context,
1220 const net::URLRequest* request) {
1221 ClearPendingCallbacks(request);
1223 signaled_requests_.erase(request->identifier());
1225 request_time_tracker_->LogRequestEndTime(request->identifier(),
1226 base::Time::Now());
1229 void ExtensionWebRequestEventRouter::ClearPendingCallbacks(
1230 const net::URLRequest* request) {
1231 blocked_requests_.erase(request->identifier());
1234 bool ExtensionWebRequestEventRouter::DispatchEvent(
1235 void* browser_context,
1236 net::URLRequest* request,
1237 const std::vector<const EventListener*>& listeners,
1238 const base::ListValue& args) {
1239 // TODO(mpcomplete): Consider consolidating common (extension_id,json_args)
1240 // pairs into a single message sent to a list of sub_event_names.
1241 int num_handlers_blocking = 0;
1242 for (const EventListener* listener : listeners) {
1243 // Filter out the optional keys that this listener didn't request.
1244 scoped_ptr<base::ListValue> args_filtered(args.DeepCopy());
1245 base::DictionaryValue* dict = NULL;
1246 CHECK(args_filtered->GetDictionary(0, &dict) && dict);
1247 if (!(listener->extra_info_spec & ExtraInfoSpec::REQUEST_HEADERS))
1248 dict->Remove(keys::kRequestHeadersKey, NULL);
1249 if (!(listener->extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS))
1250 dict->Remove(keys::kResponseHeadersKey, NULL);
1252 EventRouter::DispatchEventToSender(
1253 listener->ipc_sender.get(), browser_context, listener->extension_id,
1254 listener->histogram_value, listener->sub_event_name,
1255 args_filtered.Pass(), EventRouter::USER_GESTURE_UNKNOWN,
1256 EventFilteringInfo());
1257 if (listener->extra_info_spec &
1258 (ExtraInfoSpec::BLOCKING | ExtraInfoSpec::ASYNC_BLOCKING)) {
1259 listener->blocked_requests.insert(request->identifier());
1260 // If this is the first delegate blocking the request, go ahead and log
1261 // it.
1262 if (num_handlers_blocking == 0) {
1263 std::string delegate_info = l10n_util::GetStringFUTF8(
1264 IDS_LOAD_STATE_PARAMETER_EXTENSION,
1265 base::UTF8ToUTF16(listener->extension_name));
1266 // LobAndReport allows extensions that block requests to be displayed in
1267 // the load status bar.
1268 request->LogAndReportBlockedBy(delegate_info.c_str());
1270 ++num_handlers_blocking;
1274 if (num_handlers_blocking > 0) {
1275 BlockedRequest& blocked_request = blocked_requests_[request->identifier()];
1276 blocked_request.request = request;
1277 blocked_request.is_incognito |= IsIncognitoBrowserContext(browser_context);
1278 blocked_request.num_handlers_blocking += num_handlers_blocking;
1279 blocked_request.blocking_time = base::Time::Now();
1280 return true;
1283 return false;
1286 void ExtensionWebRequestEventRouter::OnEventHandled(
1287 void* browser_context,
1288 const std::string& extension_id,
1289 const std::string& event_name,
1290 const std::string& sub_event_name,
1291 uint64_t request_id,
1292 EventResponse* response) {
1293 // TODO(robwu): Does this also work with webviews? operator< (used by find)
1294 // takes the webview ID into account, which is not set on |listener|.
1295 EventListener listener;
1296 listener.extension_id = extension_id;
1297 listener.sub_event_name = sub_event_name;
1299 // The listener may have been removed (e.g. due to the process going away)
1300 // before we got here.
1301 std::set<EventListener>::iterator found =
1302 listeners_[browser_context][event_name].find(listener);
1303 if (found != listeners_[browser_context][event_name].end())
1304 found->blocked_requests.erase(request_id);
1306 DecrementBlockCount(
1307 browser_context, extension_id, event_name, request_id, response);
1310 bool ExtensionWebRequestEventRouter::AddEventListener(
1311 void* browser_context,
1312 const std::string& extension_id,
1313 const std::string& extension_name,
1314 events::HistogramValue histogram_value,
1315 const std::string& event_name,
1316 const std::string& sub_event_name,
1317 const RequestFilter& filter,
1318 int extra_info_spec,
1319 int embedder_process_id,
1320 int web_view_instance_id,
1321 base::WeakPtr<IPC::Sender> ipc_sender) {
1322 if (!IsWebRequestEvent(event_name))
1323 return false;
1325 EventListener listener;
1326 listener.extension_id = extension_id;
1327 listener.extension_name = extension_name;
1328 listener.histogram_value = histogram_value;
1329 listener.sub_event_name = sub_event_name;
1330 listener.filter = filter;
1331 listener.extra_info_spec = extra_info_spec;
1332 listener.ipc_sender = ipc_sender;
1333 listener.embedder_process_id = embedder_process_id;
1334 listener.web_view_instance_id = web_view_instance_id;
1335 if (listener.web_view_instance_id) {
1336 content::RecordAction(
1337 base::UserMetricsAction("WebView.WebRequest.AddListener"));
1340 if (ContainsKey(listeners_[browser_context][event_name], listener)) {
1341 // This is likely an abuse of the API by a malicious extension.
1342 return false;
1344 listeners_[browser_context][event_name].insert(listener);
1345 return true;
1348 void ExtensionWebRequestEventRouter::RemoveEventListener(
1349 void* browser_context,
1350 const std::string& extension_id,
1351 const std::string& sub_event_name,
1352 int embedder_process_id,
1353 int web_view_instance_id) {
1354 std::string event_name = EventRouter::GetBaseEventName(sub_event_name);
1355 DCHECK(IsWebRequestEvent(event_name));
1357 EventListener listener;
1358 listener.extension_id = extension_id;
1359 listener.sub_event_name = sub_event_name;
1360 listener.embedder_process_id = embedder_process_id;
1361 listener.web_view_instance_id = web_view_instance_id;
1363 std::set<EventListener>& event_listeners =
1364 listeners_[browser_context][event_name];
1365 // It's possible for AddEventListener to fail asynchronously. In that case,
1366 // the renderer believes the listener exists, while the browser does not.
1367 // Ignore a RemoveEventListener in that case.
1368 std::set<EventListener>::const_iterator it = event_listeners.find(listener);
1369 if (it == event_listeners.end())
1370 return;
1372 CHECK_EQ(event_listeners.count(listener), 1u) <<
1373 "extension=" << extension_id << " event=" << event_name;
1375 // Unblock any request that this event listener may have been blocking.
1376 for (uint64_t id : it->blocked_requests)
1377 DecrementBlockCount(browser_context, extension_id, event_name, id, NULL);
1379 event_listeners.erase(listener);
1381 helpers::ClearCacheOnNavigation();
1384 void ExtensionWebRequestEventRouter::RemoveWebViewEventListeners(
1385 void* browser_context,
1386 int embedder_process_id,
1387 int web_view_instance_id) {
1388 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1390 // Iterate over all listeners of all WebRequest events to delete
1391 // any listeners that belong to the provided <webview>.
1392 ListenerMapForBrowserContext& map_for_browser_context =
1393 listeners_[browser_context];
1394 for (const auto& event_iter : map_for_browser_context) {
1395 // Construct a listeners_to_delete vector so that we don't modify the set of
1396 // listeners as we iterate through it.
1397 std::vector<EventListener> listeners_to_delete;
1398 const std::set<EventListener>& listeners = event_iter.second;
1399 for (const auto& listener : listeners) {
1400 if (listener.embedder_process_id == embedder_process_id &&
1401 listener.web_view_instance_id == web_view_instance_id) {
1402 listeners_to_delete.push_back(listener);
1405 // Remove the listeners selected for deletion.
1406 for (const auto& listener : listeners_to_delete) {
1407 RemoveEventListenerOnIOThread(
1408 browser_context,
1409 listener.extension_id,
1410 listener.sub_event_name,
1411 listener.embedder_process_id,
1412 listener.web_view_instance_id);
1417 void ExtensionWebRequestEventRouter::OnOTRBrowserContextCreated(
1418 void* original_browser_context, void* otr_browser_context) {
1419 cross_browser_context_map_[original_browser_context] =
1420 std::make_pair(false, otr_browser_context);
1421 cross_browser_context_map_[otr_browser_context] =
1422 std::make_pair(true, original_browser_context);
1425 void ExtensionWebRequestEventRouter::OnOTRBrowserContextDestroyed(
1426 void* original_browser_context, void* otr_browser_context) {
1427 cross_browser_context_map_.erase(otr_browser_context);
1428 cross_browser_context_map_.erase(original_browser_context);
1431 void ExtensionWebRequestEventRouter::AddCallbackForPageLoad(
1432 const base::Closure& callback) {
1433 callbacks_for_page_load_.push_back(callback);
1436 bool ExtensionWebRequestEventRouter::IsPageLoad(
1437 const net::URLRequest* request) const {
1438 bool is_main_frame = false;
1439 int frame_id = -1;
1440 bool parent_is_main_frame = false;
1441 int parent_frame_id = -1;
1442 int render_process_host_id = -1;
1443 int routing_id = -1;
1444 ResourceType resource_type = content::RESOURCE_TYPE_LAST_TYPE;
1446 ExtractRequestInfoDetails(request, &is_main_frame, &frame_id,
1447 &parent_is_main_frame, &parent_frame_id,
1448 &render_process_host_id,
1449 &routing_id, &resource_type);
1451 return resource_type == content::RESOURCE_TYPE_MAIN_FRAME;
1454 void ExtensionWebRequestEventRouter::NotifyPageLoad() {
1455 for (const auto& callback : callbacks_for_page_load_)
1456 callback.Run();
1457 callbacks_for_page_load_.clear();
1460 void* ExtensionWebRequestEventRouter::GetCrossBrowserContext(
1461 void* browser_context) const {
1462 CrossBrowserContextMap::const_iterator cross_browser_context =
1463 cross_browser_context_map_.find(browser_context);
1464 if (cross_browser_context == cross_browser_context_map_.end())
1465 return NULL;
1466 return cross_browser_context->second.second;
1469 bool ExtensionWebRequestEventRouter::IsIncognitoBrowserContext(
1470 void* browser_context) const {
1471 CrossBrowserContextMap::const_iterator cross_browser_context =
1472 cross_browser_context_map_.find(browser_context);
1473 if (cross_browser_context == cross_browser_context_map_.end())
1474 return false;
1475 return cross_browser_context->second.first;
1478 bool ExtensionWebRequestEventRouter::WasSignaled(
1479 const net::URLRequest& request) const {
1480 SignaledRequestMap::const_iterator flag =
1481 signaled_requests_.find(request.identifier());
1482 return (flag != signaled_requests_.end()) && (flag->second != 0);
1485 void ExtensionWebRequestEventRouter::GetMatchingListenersImpl(
1486 void* browser_context,
1487 const net::URLRequest* request,
1488 const InfoMap* extension_info_map,
1489 bool crosses_incognito,
1490 const std::string& event_name,
1491 const GURL& url,
1492 int render_process_host_id,
1493 int routing_id,
1494 ResourceType resource_type,
1495 bool is_async_request,
1496 bool is_request_from_extension,
1497 int* extra_info_spec,
1498 EventListeners* matching_listeners) {
1499 std::string web_request_event_name(event_name);
1500 WebViewRendererState::WebViewInfo web_view_info;
1501 bool is_web_view_guest = WebViewRendererState::GetInstance()->GetInfo(
1502 render_process_host_id, routing_id, &web_view_info);
1503 if (is_web_view_guest) {
1504 web_request_event_name.replace(
1505 0, sizeof(kWebRequestEventPrefix) - 1, webview::kWebViewEventPrefix);
1508 std::set<EventListener>& listeners =
1509 listeners_[browser_context][web_request_event_name];
1510 for (const EventListener& listener : listeners) {
1511 if (!listener.ipc_sender.get()) {
1512 // The IPC sender has been deleted. This listener will be removed soon
1513 // via a call to RemoveEventListener. For now, just skip it.
1514 continue;
1517 if (is_web_view_guest &&
1518 (listener.embedder_process_id != web_view_info.embedder_process_id ||
1519 listener.web_view_instance_id != web_view_info.instance_id)) {
1520 continue;
1523 // Filter requests from other extensions / apps. This does not work for
1524 // content scripts, or extension pages in non-extension processes.
1525 if (is_request_from_extension &&
1526 listener.embedder_process_id != render_process_host_id) {
1527 continue;
1530 if (!listener.filter.urls.is_empty() &&
1531 !listener.filter.urls.MatchesURL(url)) {
1532 continue;
1535 if (web_request_event_router_delegate_ &&
1536 web_request_event_router_delegate_->OnGetMatchingListenersImplCheck(
1537 listener.filter.tab_id, listener.filter.window_id, request)) {
1538 continue;
1541 const std::vector<content::ResourceType>& types = listener.filter.types;
1542 if (!types.empty() &&
1543 std::find(types.begin(), types.end(), resource_type) == types.end()) {
1544 continue;
1547 if (!is_web_view_guest &&
1548 !WebRequestPermissions::CanExtensionAccessURL(
1549 extension_info_map, listener.extension_id, url, crosses_incognito,
1550 WebRequestPermissions::REQUIRE_HOST_PERMISSION)) {
1551 continue;
1554 bool blocking_listener =
1555 (listener.extra_info_spec &
1556 (ExtraInfoSpec::BLOCKING | ExtraInfoSpec::ASYNC_BLOCKING)) != 0;
1558 // We do not want to notify extensions about XHR requests that are
1559 // triggered by themselves. This is a workaround to prevent deadlocks
1560 // in case of synchronous XHR requests that block the extension renderer
1561 // and therefore prevent the extension from processing the request
1562 // handler. This is only a problem for blocking listeners.
1563 // http://crbug.com/105656
1564 bool synchronous_xhr_from_extension =
1565 !is_async_request && is_request_from_extension &&
1566 resource_type == content::RESOURCE_TYPE_XHR;
1568 // Only send webRequest events for URLs the extension has access to.
1569 if (blocking_listener && synchronous_xhr_from_extension)
1570 continue;
1572 matching_listeners->push_back(&listener);
1573 *extra_info_spec |= listener.extra_info_spec;
1577 ExtensionWebRequestEventRouter::EventListeners
1578 ExtensionWebRequestEventRouter::GetMatchingListeners(
1579 void* browser_context,
1580 const InfoMap* extension_info_map,
1581 const std::string& event_name,
1582 const net::URLRequest* request,
1583 int* extra_info_spec) {
1584 // TODO(mpcomplete): handle browser_context == NULL (should collect all
1585 // listeners).
1586 *extra_info_spec = 0;
1588 bool is_main_frame = false;
1589 int frame_id = -1;
1590 bool parent_is_main_frame = false;
1591 int parent_frame_id = -1;
1592 int render_process_host_id = -1;
1593 int routing_id = -1;
1594 ResourceType resource_type = content::RESOURCE_TYPE_LAST_TYPE;
1595 const GURL& url = request->url();
1597 ExtractRequestInfoDetails(request, &is_main_frame, &frame_id,
1598 &parent_is_main_frame, &parent_frame_id,
1599 &render_process_host_id,
1600 &routing_id, &resource_type);
1602 bool is_request_from_extension =
1603 IsRequestFromExtension(request, extension_info_map);
1605 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
1606 // We are conservative here and assume requests are asynchronous in case
1607 // we don't have an info object. We don't want to risk a deadlock.
1608 bool is_async_request = !info || info->IsAsync();
1610 EventListeners matching_listeners;
1611 GetMatchingListenersImpl(
1612 browser_context, request, extension_info_map, false, event_name,
1613 url, render_process_host_id, routing_id, resource_type,
1614 is_async_request, is_request_from_extension, extra_info_spec,
1615 &matching_listeners);
1616 void* cross_browser_context = GetCrossBrowserContext(browser_context);
1617 if (cross_browser_context) {
1618 GetMatchingListenersImpl(
1619 cross_browser_context, request, extension_info_map, true, event_name,
1620 url, render_process_host_id, routing_id, resource_type,
1621 is_async_request, is_request_from_extension, extra_info_spec,
1622 &matching_listeners);
1625 return matching_listeners;
1628 namespace {
1630 helpers::EventResponseDelta* CalculateDelta(
1631 ExtensionWebRequestEventRouter::BlockedRequest* blocked_request,
1632 ExtensionWebRequestEventRouter::EventResponse* response) {
1633 switch (blocked_request->event) {
1634 case ExtensionWebRequestEventRouter::kOnBeforeRequest:
1635 return helpers::CalculateOnBeforeRequestDelta(
1636 response->extension_id, response->extension_install_time,
1637 response->cancel, response->new_url);
1638 case ExtensionWebRequestEventRouter::kOnBeforeSendHeaders: {
1639 net::HttpRequestHeaders* old_headers = blocked_request->request_headers;
1640 net::HttpRequestHeaders* new_headers = response->request_headers.get();
1641 return helpers::CalculateOnBeforeSendHeadersDelta(
1642 response->extension_id, response->extension_install_time,
1643 response->cancel, old_headers, new_headers);
1645 case ExtensionWebRequestEventRouter::kOnHeadersReceived: {
1646 const net::HttpResponseHeaders* old_headers =
1647 blocked_request->original_response_headers.get();
1648 helpers::ResponseHeaders* new_headers =
1649 response->response_headers.get();
1650 return helpers::CalculateOnHeadersReceivedDelta(
1651 response->extension_id,
1652 response->extension_install_time,
1653 response->cancel,
1654 response->new_url,
1655 old_headers,
1656 new_headers);
1658 case ExtensionWebRequestEventRouter::kOnAuthRequired:
1659 return helpers::CalculateOnAuthRequiredDelta(
1660 response->extension_id, response->extension_install_time,
1661 response->cancel, &response->auth_credentials);
1662 default:
1663 NOTREACHED();
1664 return nullptr;
1668 base::Value* SerializeResponseHeaders(const helpers::ResponseHeaders& headers) {
1669 scoped_ptr<base::ListValue> serialized_headers(new base::ListValue());
1670 for (const auto& it : headers) {
1671 serialized_headers->Append(
1672 helpers::CreateHeaderDictionary(it.first, it.second));
1674 return serialized_headers.release();
1677 // Convert a RequestCookieModifications/ResponseCookieModifications object to a
1678 // base::ListValue which summarizes the changes made. This is templated since
1679 // the two types (request/response) are different but contain essentially the
1680 // same fields.
1681 template <typename CookieType>
1682 base::ListValue* SummarizeCookieModifications(
1683 const std::vector<linked_ptr<CookieType>>& modifications) {
1684 scoped_ptr<base::ListValue> cookie_modifications(new base::ListValue());
1685 for (const auto& it : modifications) {
1686 scoped_ptr<base::DictionaryValue> summary(new base::DictionaryValue());
1687 const CookieType& mod = *(it.get());
1688 switch (mod.type) {
1689 case helpers::ADD:
1690 summary->SetString(activity_log::kCookieModificationTypeKey,
1691 activity_log::kCookieModificationAdd);
1692 break;
1693 case helpers::EDIT:
1694 summary->SetString(activity_log::kCookieModificationTypeKey,
1695 activity_log::kCookieModificationEdit);
1696 break;
1697 case helpers::REMOVE:
1698 summary->SetString(activity_log::kCookieModificationTypeKey,
1699 activity_log::kCookieModificationRemove);
1700 break;
1702 if (mod.filter) {
1703 if (mod.filter->name) {
1704 summary->SetString(activity_log::kCookieFilterNameKey,
1705 *mod.modification->name);
1707 if (mod.filter->domain) {
1708 summary->SetString(activity_log::kCookieFilterDomainKey,
1709 *mod.modification->name);
1712 if (mod.modification) {
1713 if (mod.modification->name) {
1714 summary->SetString(activity_log::kCookieModDomainKey,
1715 *mod.modification->name);
1717 if (mod.modification->domain) {
1718 summary->SetString(activity_log::kCookieModDomainKey,
1719 *mod.modification->name);
1722 cookie_modifications->Append(summary.release());
1724 return cookie_modifications.release();
1727 // Converts an EventResponseDelta object to a dictionary value suitable for the
1728 // activity log.
1729 scoped_ptr<base::DictionaryValue> SummarizeResponseDelta(
1730 const std::string& event_name,
1731 const helpers::EventResponseDelta& delta) {
1732 scoped_ptr<base::DictionaryValue> details(new base::DictionaryValue());
1733 if (delta.cancel)
1734 details->SetBoolean(activity_log::kCancelKey, true);
1735 if (!delta.new_url.is_empty())
1736 details->SetString(activity_log::kNewUrlKey, delta.new_url.spec());
1738 scoped_ptr<base::ListValue> modified_headers(new base::ListValue());
1739 net::HttpRequestHeaders::Iterator iter(delta.modified_request_headers);
1740 while (iter.GetNext()) {
1741 modified_headers->Append(
1742 helpers::CreateHeaderDictionary(iter.name(), iter.value()));
1744 if (!modified_headers->empty()) {
1745 details->Set(activity_log::kModifiedRequestHeadersKey,
1746 modified_headers.release());
1749 scoped_ptr<base::ListValue> deleted_headers(new base::ListValue());
1750 deleted_headers->AppendStrings(delta.deleted_request_headers);
1751 if (!deleted_headers->empty()) {
1752 details->Set(activity_log::kDeletedRequestHeadersKey,
1753 deleted_headers.release());
1756 if (!delta.added_response_headers.empty()) {
1757 details->Set(activity_log::kAddedRequestHeadersKey,
1758 SerializeResponseHeaders(delta.added_response_headers));
1760 if (!delta.deleted_response_headers.empty()) {
1761 details->Set(activity_log::kDeletedResponseHeadersKey,
1762 SerializeResponseHeaders(delta.deleted_response_headers));
1764 if (delta.auth_credentials) {
1765 details->SetString(
1766 activity_log::kAuthCredentialsKey,
1767 base::UTF16ToUTF8(delta.auth_credentials->username()) + ":*");
1770 if (!delta.response_cookie_modifications.empty()) {
1771 details->Set(
1772 activity_log::kResponseCookieModificationsKey,
1773 SummarizeCookieModifications(delta.response_cookie_modifications));
1776 return details.Pass();
1779 } // namespace
1781 void ExtensionWebRequestEventRouter::LogExtensionActivity(
1782 void* browser_context_id,
1783 bool is_incognito,
1784 const std::string& extension_id,
1785 const GURL& url,
1786 const std::string& api_call,
1787 scoped_ptr<base::DictionaryValue> details) {
1788 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
1789 BrowserThread::PostTask(
1790 BrowserThread::UI,
1791 FROM_HERE,
1792 base::Bind(&ExtensionWebRequestEventRouter::LogExtensionActivity,
1793 base::Unretained(this),
1794 browser_context_id,
1795 is_incognito,
1796 extension_id,
1797 url,
1798 api_call,
1799 base::Passed(&details)));
1800 } else {
1801 if (web_request_event_router_delegate_) {
1802 web_request_event_router_delegate_->LogExtensionActivity(
1803 reinterpret_cast<content::BrowserContext*>(browser_context_id),
1804 is_incognito, extension_id, url, api_call, details.Pass());
1809 void ExtensionWebRequestEventRouter::DecrementBlockCount(
1810 void* browser_context,
1811 const std::string& extension_id,
1812 const std::string& event_name,
1813 uint64_t request_id,
1814 EventResponse* response) {
1815 scoped_ptr<EventResponse> response_scoped(response);
1817 // It's possible that this request was deleted, or cancelled by a previous
1818 // event handler. If so, ignore this response.
1819 auto it = blocked_requests_.find(request_id);
1820 if (it == blocked_requests_.end())
1821 return;
1823 BlockedRequest& blocked_request = it->second;
1824 int num_handlers_blocking = --blocked_request.num_handlers_blocking;
1825 CHECK_GE(num_handlers_blocking, 0);
1827 if (response) {
1828 helpers::EventResponseDelta* delta =
1829 CalculateDelta(&blocked_request, response);
1831 LogExtensionActivity(browser_context,
1832 blocked_request.is_incognito,
1833 extension_id,
1834 blocked_request.request->url(),
1835 event_name,
1836 SummarizeResponseDelta(event_name, *delta));
1838 blocked_request.response_deltas.push_back(
1839 linked_ptr<helpers::EventResponseDelta>(delta));
1842 base::TimeDelta block_time =
1843 base::Time::Now() - blocked_request.blocking_time;
1844 if (!extension_id.empty()) {
1845 request_time_tracker_->IncrementExtensionBlockTime(
1846 extension_id, request_id, block_time);
1847 } else {
1848 // |extension_id| is empty for requests blocked on startup waiting for the
1849 // declarative rules to be read from disk.
1850 UMA_HISTOGRAM_TIMES("Extensions.NetworkDelayStartup", block_time);
1853 if (num_handlers_blocking == 0) {
1854 blocked_request.request->LogUnblocked();
1855 ExecuteDeltas(browser_context, request_id, true);
1856 } else {
1857 // Update the URLRequest to make sure it's tagged with an extension that's
1858 // still blocking it. This may end up being the same extension as before.
1859 std::set<EventListener>& listeners =
1860 listeners_[browser_context][event_name];
1862 for (const auto& listener : listeners) {
1863 if (!ContainsKey(listener.blocked_requests, request_id))
1864 continue;
1865 std::string delegate_info =
1866 l10n_util::GetStringFUTF8(IDS_LOAD_STATE_PARAMETER_EXTENSION,
1867 base::UTF8ToUTF16(listener.extension_name));
1868 blocked_request.request->LogAndReportBlockedBy(delegate_info.c_str());
1869 break;
1874 void ExtensionWebRequestEventRouter::SendMessages(
1875 void* browser_context,
1876 const BlockedRequest& blocked_request) {
1877 const helpers::EventResponseDeltas& deltas = blocked_request.response_deltas;
1878 for (const auto& delta : deltas) {
1879 const std::set<std::string>& messages = delta->messages_to_extension;
1880 for (const std::string& message : messages) {
1881 scoped_ptr<base::DictionaryValue> argument(new base::DictionaryValue);
1882 ExtractRequestInfo(blocked_request.request, argument.get());
1883 WebViewRendererState::WebViewInfo web_view_info;
1884 bool is_web_view_guest = GetWebViewInfo(blocked_request.request,
1885 &web_view_info);
1886 argument->SetString(keys::kMessageKey, message);
1887 argument->SetString(keys::kStageKey,
1888 GetRequestStageAsString(blocked_request.event));
1890 BrowserThread::PostTask(
1891 BrowserThread::UI, FROM_HERE,
1892 base::Bind(&SendOnMessageEventOnUI, browser_context,
1893 delta->extension_id, is_web_view_guest, web_view_info,
1894 base::Passed(&argument)));
1899 int ExtensionWebRequestEventRouter::ExecuteDeltas(void* browser_context,
1900 uint64_t request_id,
1901 bool call_callback) {
1902 BlockedRequest& blocked_request = blocked_requests_[request_id];
1903 CHECK_EQ(0, blocked_request.num_handlers_blocking);
1904 helpers::EventResponseDeltas& deltas = blocked_request.response_deltas;
1905 base::TimeDelta block_time =
1906 base::Time::Now() - blocked_request.blocking_time;
1907 request_time_tracker_->IncrementTotalBlockTime(request_id, block_time);
1909 bool credentials_set = false;
1911 deltas.sort(&helpers::InDecreasingExtensionInstallationTimeOrder);
1913 bool canceled = false;
1914 helpers::MergeCancelOfResponses(blocked_request.response_deltas, &canceled,
1915 blocked_request.net_log);
1917 WarningSet warnings;
1918 if (blocked_request.event == kOnBeforeRequest) {
1919 CHECK(!blocked_request.callback.is_null());
1920 helpers::MergeOnBeforeRequestResponses(
1921 blocked_request.response_deltas,
1922 blocked_request.new_url,
1923 &warnings,
1924 blocked_request.net_log);
1925 } else if (blocked_request.event == kOnBeforeSendHeaders) {
1926 CHECK(!blocked_request.callback.is_null());
1927 helpers::MergeOnBeforeSendHeadersResponses(
1928 blocked_request.response_deltas,
1929 blocked_request.request_headers,
1930 &warnings,
1931 blocked_request.net_log);
1932 } else if (blocked_request.event == kOnHeadersReceived) {
1933 CHECK(!blocked_request.callback.is_null());
1934 helpers::MergeOnHeadersReceivedResponses(
1935 blocked_request.response_deltas,
1936 blocked_request.original_response_headers.get(),
1937 blocked_request.override_response_headers,
1938 blocked_request.new_url,
1939 &warnings,
1940 blocked_request.net_log);
1941 } else if (blocked_request.event == kOnAuthRequired) {
1942 CHECK(blocked_request.callback.is_null());
1943 CHECK(!blocked_request.auth_callback.is_null());
1944 credentials_set = helpers::MergeOnAuthRequiredResponses(
1945 blocked_request.response_deltas,
1946 blocked_request.auth_credentials,
1947 &warnings,
1948 blocked_request.net_log);
1949 } else {
1950 NOTREACHED();
1953 SendMessages(browser_context, blocked_request);
1955 if (!warnings.empty()) {
1956 BrowserThread::PostTask(
1957 BrowserThread::UI,
1958 FROM_HERE,
1959 base::Bind(&WarningService::NotifyWarningsOnUI,
1960 browser_context, warnings));
1963 if (canceled) {
1964 request_time_tracker_->SetRequestCanceled(request_id);
1965 } else if (blocked_request.new_url &&
1966 !blocked_request.new_url->is_empty()) {
1967 request_time_tracker_->SetRequestRedirected(request_id);
1970 // This triggers onErrorOccurred if canceled is true.
1971 int rv = canceled ? net::ERR_BLOCKED_BY_CLIENT : net::OK;
1973 if (!blocked_request.callback.is_null()) {
1974 net::CompletionCallback callback = blocked_request.callback;
1975 // Ensure that request is removed before callback because the callback
1976 // might trigger the next event.
1977 blocked_requests_.erase(request_id);
1978 if (call_callback)
1979 callback.Run(rv);
1980 } else if (!blocked_request.auth_callback.is_null()) {
1981 net::NetworkDelegate::AuthRequiredResponse response;
1982 if (canceled)
1983 response = net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_CANCEL_AUTH;
1984 else if (credentials_set)
1985 response = net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_SET_AUTH;
1986 else
1987 response = net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION;
1989 net::NetworkDelegate::AuthCallback callback = blocked_request.auth_callback;
1990 blocked_requests_.erase(request_id);
1991 if (call_callback)
1992 callback.Run(response);
1993 } else {
1994 blocked_requests_.erase(request_id);
1996 return rv;
1999 bool ExtensionWebRequestEventRouter::ProcessDeclarativeRules(
2000 void* browser_context,
2001 const InfoMap* extension_info_map,
2002 const std::string& event_name,
2003 net::URLRequest* request,
2004 RequestStage request_stage,
2005 const net::HttpResponseHeaders* original_response_headers) {
2006 WebViewRendererState::WebViewInfo web_view_info;
2007 bool is_web_view_guest = GetWebViewInfo(request, &web_view_info);
2008 int rules_registry_id = is_web_view_guest
2009 ? web_view_info.rules_registry_id
2010 : RulesRegistryService::kDefaultRulesRegistryID;
2012 RulesRegistryKey rules_key(browser_context, rules_registry_id);
2013 // If this check fails, check that the active stages are up-to-date in
2014 // extensions/browser/api/declarative_webrequest/request_stage.h .
2015 DCHECK(request_stage & kActiveStages);
2017 // Rules of the current |browser_context| may apply but we need to check also
2018 // whether there are applicable rules from extensions whose background page
2019 // spans from regular to incognito mode.
2021 // First parameter identifies the registry, the second indicates whether the
2022 // registry belongs to the cross browser_context.
2023 using RelevantRegistry = std::pair<WebRequestRulesRegistry*, bool>;
2024 std::vector<RelevantRegistry> relevant_registries;
2026 auto rules_key_it = rules_registries_.find(rules_key);
2027 if (rules_key_it != rules_registries_.end()) {
2028 relevant_registries.push_back(
2029 std::make_pair(rules_key_it->second.get(), false));
2032 void* cross_browser_context = GetCrossBrowserContext(browser_context);
2033 RulesRegistryKey cross_browser_context_rules_key(cross_browser_context,
2034 rules_registry_id);
2035 if (cross_browser_context) {
2036 auto it = rules_registries_.find(cross_browser_context_rules_key);
2037 if (it != rules_registries_.end())
2038 relevant_registries.push_back(std::make_pair(it->second.get(), true));
2041 // The following block is experimentally enabled and its impact on load time
2042 // logged with UMA Extensions.NetworkDelayRegistryLoad. crbug.com/175961
2043 for (auto it : relevant_registries) {
2044 WebRequestRulesRegistry* rules_registry = it.first;
2045 if (rules_registry->ready().is_signaled())
2046 continue;
2048 // The rules registry is still loading. Block this request until it
2049 // finishes.
2050 rules_registry->ready().Post(
2051 FROM_HERE,
2052 base::Bind(&ExtensionWebRequestEventRouter::OnRulesRegistryReady,
2053 AsWeakPtr(), browser_context, event_name,
2054 request->identifier(), request_stage));
2055 BlockedRequest& blocked_request = blocked_requests_[request->identifier()];
2056 blocked_request.num_handlers_blocking++;
2057 blocked_request.request = request;
2058 blocked_request.is_incognito |= IsIncognitoBrowserContext(browser_context);
2059 blocked_request.blocking_time = base::Time::Now();
2060 blocked_request.original_response_headers = original_response_headers;
2061 blocked_request.extension_info_map = extension_info_map;
2062 return true;
2065 base::Time start = base::Time::Now();
2067 bool deltas_created = false;
2068 for (const auto& it : relevant_registries) {
2069 WebRequestRulesRegistry* rules_registry = it.first;
2070 helpers::EventResponseDeltas result = rules_registry->CreateDeltas(
2071 extension_info_map,
2072 WebRequestData(request, request_stage, original_response_headers),
2073 it.second);
2075 if (!result.empty()) {
2076 helpers::EventResponseDeltas& deltas =
2077 blocked_requests_[request->identifier()].response_deltas;
2078 deltas.insert(deltas.end(), result.begin(), result.end());
2079 deltas_created = true;
2083 base::TimeDelta elapsed_time = start - base::Time::Now();
2084 UMA_HISTOGRAM_TIMES("Extensions.DeclarativeWebRequestNetworkDelay",
2085 elapsed_time);
2087 return deltas_created;
2090 void ExtensionWebRequestEventRouter::OnRulesRegistryReady(
2091 void* browser_context,
2092 const std::string& event_name,
2093 uint64_t request_id,
2094 RequestStage request_stage) {
2095 // It's possible that this request was deleted, or cancelled by a previous
2096 // event handler. If so, ignore this response.
2097 auto it = blocked_requests_.find(request_id);
2098 if (it == blocked_requests_.end())
2099 return;
2101 BlockedRequest& blocked_request = it->second;
2102 base::TimeDelta block_time =
2103 base::Time::Now() - blocked_request.blocking_time;
2104 UMA_HISTOGRAM_TIMES("Extensions.NetworkDelayRegistryLoad", block_time);
2106 ProcessDeclarativeRules(browser_context,
2107 blocked_request.extension_info_map,
2108 event_name,
2109 blocked_request.request,
2110 request_stage,
2111 blocked_request.original_response_headers.get());
2112 // Reset to NULL so that nobody relies on this being set.
2113 blocked_request.extension_info_map = NULL;
2114 DecrementBlockCount(
2115 browser_context, std::string(), event_name, request_id, NULL);
2118 bool ExtensionWebRequestEventRouter::GetAndSetSignaled(uint64_t request_id,
2119 EventTypes event_type) {
2120 SignaledRequestMap::iterator iter = signaled_requests_.find(request_id);
2121 if (iter == signaled_requests_.end()) {
2122 signaled_requests_[request_id] = event_type;
2123 return false;
2125 bool was_signaled_before = (iter->second & event_type) != 0;
2126 iter->second |= event_type;
2127 return was_signaled_before;
2130 void ExtensionWebRequestEventRouter::ClearSignaled(uint64_t request_id,
2131 EventTypes event_type) {
2132 SignaledRequestMap::iterator iter = signaled_requests_.find(request_id);
2133 if (iter == signaled_requests_.end())
2134 return;
2135 iter->second &= ~event_type;
2138 // Special QuotaLimitHeuristic for WebRequestHandlerBehaviorChangedFunction.
2140 // Each call of webRequest.handlerBehaviorChanged() clears the in-memory cache
2141 // of WebKit at the time of the next page load (top level navigation event).
2142 // This quota heuristic is intended to limit the number of times the cache is
2143 // cleared by an extension.
2145 // As we want to account for the number of times the cache is really cleared
2146 // (opposed to the number of times webRequest.handlerBehaviorChanged() is
2147 // called), we cannot decide whether a call of
2148 // webRequest.handlerBehaviorChanged() should trigger a quota violation at the
2149 // time it is called. Instead we only decrement the bucket counter at the time
2150 // when the cache is cleared (when page loads happen).
2151 class ClearCacheQuotaHeuristic : public QuotaLimitHeuristic {
2152 public:
2153 ClearCacheQuotaHeuristic(const Config& config, BucketMapper* map)
2154 : QuotaLimitHeuristic(
2155 config,
2156 map,
2157 "MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES"),
2158 callback_registered_(false),
2159 weak_ptr_factory_(this) {}
2160 ~ClearCacheQuotaHeuristic() override {}
2161 bool Apply(Bucket* bucket, const base::TimeTicks& event_time) override;
2163 private:
2164 // Callback that is triggered by the ExtensionWebRequestEventRouter on a page
2165 // load.
2167 // We don't need to take care of the life time of |bucket|: It is owned by the
2168 // BucketMapper of our base class in |QuotaLimitHeuristic::bucket_mapper_|. As
2169 // long as |this| exists, the respective BucketMapper and its bucket will
2170 // exist as well.
2171 void OnPageLoad(Bucket* bucket);
2173 // Flag to prevent that we register more than one call back in-between
2174 // clearing the cache.
2175 bool callback_registered_;
2177 base::WeakPtrFactory<ClearCacheQuotaHeuristic> weak_ptr_factory_;
2179 DISALLOW_COPY_AND_ASSIGN(ClearCacheQuotaHeuristic);
2182 bool ClearCacheQuotaHeuristic::Apply(Bucket* bucket,
2183 const base::TimeTicks& event_time) {
2184 if (event_time > bucket->expiration())
2185 bucket->Reset(config(), event_time);
2187 // Call bucket->DeductToken() on a new page load, this is when
2188 // webRequest.handlerBehaviorChanged() clears the cache.
2189 if (!callback_registered_) {
2190 ExtensionWebRequestEventRouter::GetInstance()->AddCallbackForPageLoad(
2191 base::Bind(&ClearCacheQuotaHeuristic::OnPageLoad,
2192 weak_ptr_factory_.GetWeakPtr(),
2193 bucket));
2194 callback_registered_ = true;
2197 // We only check whether tokens are left here. Deducting a token happens in
2198 // OnPageLoad().
2199 return bucket->has_tokens();
2202 void ClearCacheQuotaHeuristic::OnPageLoad(Bucket* bucket) {
2203 callback_registered_ = false;
2204 bucket->DeductToken();
2207 bool WebRequestInternalAddEventListenerFunction::RunSync() {
2208 // Argument 0 is the callback, which we don't use here.
2209 ExtensionWebRequestEventRouter::RequestFilter filter;
2210 base::DictionaryValue* value = NULL;
2211 error_.clear();
2212 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &value));
2213 // Failure + an empty error string means a fatal error.
2214 EXTENSION_FUNCTION_VALIDATE(filter.InitFromValue(*value, &error_) ||
2215 !error_.empty());
2216 if (!error_.empty())
2217 return false;
2219 int extra_info_spec = 0;
2220 if (HasOptionalArgument(2)) {
2221 base::ListValue* value = NULL;
2222 EXTENSION_FUNCTION_VALIDATE(args_->GetList(2, &value));
2223 EXTENSION_FUNCTION_VALIDATE(
2224 ExtensionWebRequestEventRouter::ExtraInfoSpec::InitFromValue(
2225 *value, &extra_info_spec));
2228 std::string event_name;
2229 EXTENSION_FUNCTION_VALIDATE(args_->GetString(3, &event_name));
2231 std::string sub_event_name;
2232 EXTENSION_FUNCTION_VALIDATE(args_->GetString(4, &sub_event_name));
2234 int web_view_instance_id = 0;
2235 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(5, &web_view_instance_id));
2237 base::WeakPtr<IOThreadExtensionMessageFilter> ipc_sender = ipc_sender_weak();
2238 int embedder_process_id = ipc_sender ? ipc_sender->render_process_id() : 0;
2240 const Extension* extension =
2241 extension_info_map()->extensions().GetByID(extension_id_safe());
2242 std::string extension_name =
2243 extension ? extension->name() : extension_id_safe();
2245 if (!web_view_instance_id) {
2246 // We check automatically whether the extension has the 'webRequest'
2247 // permission. For blocking calls we require the additional permission
2248 // 'webRequestBlocking'.
2249 if ((extra_info_spec &
2250 (ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING |
2251 ExtensionWebRequestEventRouter::ExtraInfoSpec::ASYNC_BLOCKING)) &&
2252 !extension->permissions_data()->HasAPIPermission(
2253 APIPermission::kWebRequestBlocking)) {
2254 error_ = keys::kBlockingPermissionRequired;
2255 return false;
2258 // We allow to subscribe to patterns that are broader than the host
2259 // permissions. E.g., we could subscribe to http://www.example.com/*
2260 // while having host permissions for http://www.example.com/foo/* and
2261 // http://www.example.com/bar/*.
2262 // For this reason we do only a coarse check here to warn the extension
2263 // developer if he does something obviously wrong.
2264 if (extension->permissions_data()
2265 ->GetEffectiveHostPermissions()
2266 .is_empty()) {
2267 error_ = keys::kHostPermissionsRequired;
2268 return false;
2272 bool success =
2273 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
2274 profile_id(), extension_id_safe(), extension_name,
2275 GetEventHistogramValue(event_name), event_name, sub_event_name,
2276 filter, extra_info_spec, embedder_process_id, web_view_instance_id,
2277 ipc_sender_weak());
2278 EXTENSION_FUNCTION_VALIDATE(success);
2280 helpers::ClearCacheOnNavigation();
2282 if (!extension_id_safe().empty()) {
2283 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
2284 base::Bind(&helpers::NotifyWebRequestAPIUsed,
2285 profile_id(), extension_id_safe()));
2288 return true;
2291 void WebRequestInternalEventHandledFunction::RespondWithError(
2292 const std::string& event_name,
2293 const std::string& sub_event_name,
2294 uint64_t request_id,
2295 scoped_ptr<ExtensionWebRequestEventRouter::EventResponse> response,
2296 const std::string& error) {
2297 error_ = error;
2298 ExtensionWebRequestEventRouter::GetInstance()->OnEventHandled(
2299 profile_id(),
2300 extension_id_safe(),
2301 event_name,
2302 sub_event_name,
2303 request_id,
2304 response.release());
2307 bool WebRequestInternalEventHandledFunction::RunSync() {
2308 std::string event_name;
2309 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &event_name));
2311 std::string sub_event_name;
2312 EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &sub_event_name));
2314 std::string request_id_str;
2315 EXTENSION_FUNCTION_VALIDATE(args_->GetString(2, &request_id_str));
2316 uint64_t request_id;
2317 EXTENSION_FUNCTION_VALIDATE(base::StringToUint64(request_id_str,
2318 &request_id));
2320 scoped_ptr<ExtensionWebRequestEventRouter::EventResponse> response;
2321 if (HasOptionalArgument(3)) {
2322 base::DictionaryValue* value = NULL;
2323 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(3, &value));
2325 if (!value->empty()) {
2326 base::Time install_time =
2327 extension_info_map()->GetInstallTime(extension_id_safe());
2328 response.reset(new ExtensionWebRequestEventRouter::EventResponse(
2329 extension_id_safe(), install_time));
2332 if (value->HasKey("cancel")) {
2333 // Don't allow cancel mixed with other keys.
2334 if (value->size() != 1) {
2335 RespondWithError(event_name,
2336 sub_event_name,
2337 request_id,
2338 response.Pass(),
2339 keys::kInvalidBlockingResponse);
2340 return false;
2343 bool cancel = false;
2344 EXTENSION_FUNCTION_VALIDATE(value->GetBoolean("cancel", &cancel));
2345 response->cancel = cancel;
2348 if (value->HasKey("redirectUrl")) {
2349 std::string new_url_str;
2350 EXTENSION_FUNCTION_VALIDATE(value->GetString("redirectUrl",
2351 &new_url_str));
2352 response->new_url = GURL(new_url_str);
2353 if (!response->new_url.is_valid()) {
2354 RespondWithError(event_name,
2355 sub_event_name,
2356 request_id,
2357 response.Pass(),
2358 ErrorUtils::FormatErrorMessage(
2359 keys::kInvalidRedirectUrl, new_url_str));
2360 return false;
2364 const bool has_request_headers = value->HasKey("requestHeaders");
2365 const bool has_response_headers = value->HasKey("responseHeaders");
2366 if (has_request_headers || has_response_headers) {
2367 if (has_request_headers && has_response_headers) {
2368 // Allow only one of the keys, not both.
2369 RespondWithError(event_name,
2370 sub_event_name,
2371 request_id,
2372 response.Pass(),
2373 keys::kInvalidHeaderKeyCombination);
2374 return false;
2377 base::ListValue* headers_value = NULL;
2378 scoped_ptr<net::HttpRequestHeaders> request_headers;
2379 scoped_ptr<helpers::ResponseHeaders> response_headers;
2380 if (has_request_headers) {
2381 request_headers.reset(new net::HttpRequestHeaders());
2382 EXTENSION_FUNCTION_VALIDATE(value->GetList(keys::kRequestHeadersKey,
2383 &headers_value));
2384 } else {
2385 response_headers.reset(new helpers::ResponseHeaders());
2386 EXTENSION_FUNCTION_VALIDATE(value->GetList(keys::kResponseHeadersKey,
2387 &headers_value));
2390 for (size_t i = 0; i < headers_value->GetSize(); ++i) {
2391 base::DictionaryValue* header_value = NULL;
2392 std::string name;
2393 std::string value;
2394 EXTENSION_FUNCTION_VALIDATE(
2395 headers_value->GetDictionary(i, &header_value));
2396 if (!FromHeaderDictionary(header_value, &name, &value)) {
2397 std::string serialized_header;
2398 base::JSONWriter::Write(*header_value, &serialized_header);
2399 RespondWithError(event_name,
2400 sub_event_name,
2401 request_id,
2402 response.Pass(),
2403 ErrorUtils::FormatErrorMessage(keys::kInvalidHeader,
2404 serialized_header));
2405 return false;
2407 if (!net::HttpUtil::IsValidHeaderName(name)) {
2408 RespondWithError(event_name,
2409 sub_event_name,
2410 request_id,
2411 response.Pass(),
2412 keys::kInvalidHeaderName);
2413 return false;
2415 if (!net::HttpUtil::IsValidHeaderValue(value)) {
2416 RespondWithError(event_name,
2417 sub_event_name,
2418 request_id,
2419 response.Pass(),
2420 ErrorUtils::FormatErrorMessage(
2421 keys::kInvalidHeaderValue, name));
2422 return false;
2424 if (has_request_headers)
2425 request_headers->SetHeader(name, value);
2426 else
2427 response_headers->push_back(helpers::ResponseHeader(name, value));
2429 if (has_request_headers)
2430 response->request_headers.reset(request_headers.release());
2431 else
2432 response->response_headers.reset(response_headers.release());
2435 if (value->HasKey(keys::kAuthCredentialsKey)) {
2436 base::DictionaryValue* credentials_value = NULL;
2437 EXTENSION_FUNCTION_VALIDATE(value->GetDictionary(
2438 keys::kAuthCredentialsKey,
2439 &credentials_value));
2440 base::string16 username;
2441 base::string16 password;
2442 EXTENSION_FUNCTION_VALIDATE(
2443 credentials_value->GetString(keys::kUsernameKey, &username));
2444 EXTENSION_FUNCTION_VALIDATE(
2445 credentials_value->GetString(keys::kPasswordKey, &password));
2446 response->auth_credentials.reset(
2447 new net::AuthCredentials(username, password));
2451 ExtensionWebRequestEventRouter::GetInstance()->OnEventHandled(
2452 profile_id(), extension_id_safe(), event_name, sub_event_name, request_id,
2453 response.release());
2455 return true;
2458 void WebRequestHandlerBehaviorChangedFunction::GetQuotaLimitHeuristics(
2459 QuotaLimitHeuristics* heuristics) const {
2460 QuotaLimitHeuristic::Config config = {
2461 // See web_request.json for current value.
2462 web_request::MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES,
2463 base::TimeDelta::FromMinutes(10)};
2464 QuotaLimitHeuristic::BucketMapper* bucket_mapper =
2465 new QuotaLimitHeuristic::SingletonBucketMapper();
2466 ClearCacheQuotaHeuristic* heuristic =
2467 new ClearCacheQuotaHeuristic(config, bucket_mapper);
2468 heuristics->push_back(heuristic);
2471 void WebRequestHandlerBehaviorChangedFunction::OnQuotaExceeded(
2472 const std::string& violation_error) {
2473 // Post warning message.
2474 WarningSet warnings;
2475 warnings.insert(
2476 Warning::CreateRepeatedCacheFlushesWarning(extension_id_safe()));
2477 BrowserThread::PostTask(
2478 BrowserThread::UI,
2479 FROM_HERE,
2480 base::Bind(&WarningService::NotifyWarningsOnUI, profile_id(), warnings));
2482 // Continue gracefully.
2483 RunSync();
2486 bool WebRequestHandlerBehaviorChangedFunction::RunSync() {
2487 helpers::ClearCacheOnNavigation();
2488 return true;
2491 } // namespace extensions