Roll src/third_party/WebKit a3b4a2e:7441784 (svn 202551:202552)
[chromium-blink-merge.git] / extensions / browser / api / web_request / web_request_api.cc
blob33616986882c26ad23ae7afcf88338c3875cb35b
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/debug/alias.h"
12 #include "base/json/json_writer.h"
13 #include "base/lazy_instance.h"
14 #include "base/macros.h"
15 #include "base/metrics/histogram.h"
16 #include "base/strings/string_number_conversions.h"
17 #include "base/strings/string_util.h"
18 #include "base/strings/utf_string_conversions.h"
19 #include "base/time/time.h"
20 #include "base/values.h"
21 #include "content/public/browser/browser_message_filter.h"
22 #include "content/public/browser/browser_thread.h"
23 #include "content/public/browser/render_frame_host.h"
24 #include "content/public/browser/render_process_host.h"
25 #include "content/public/browser/resource_request_info.h"
26 #include "content/public/browser/user_metrics.h"
27 #include "extensions/browser/api/activity_log/web_request_constants.h"
28 #include "extensions/browser/api/declarative/rules_registry_service.h"
29 #include "extensions/browser/api/declarative_webrequest/request_stage.h"
30 #include "extensions/browser/api/declarative_webrequest/webrequest_constants.h"
31 #include "extensions/browser/api/declarative_webrequest/webrequest_rules_registry.h"
32 #include "extensions/browser/api/extensions_api_client.h"
33 #include "extensions/browser/api/web_request/upload_data_presenter.h"
34 #include "extensions/browser/api/web_request/web_request_api_constants.h"
35 #include "extensions/browser/api/web_request/web_request_api_helpers.h"
36 #include "extensions/browser/api/web_request/web_request_event_router_delegate.h"
37 #include "extensions/browser/api/web_request/web_request_time_tracker.h"
38 #include "extensions/browser/event_router.h"
39 #include "extensions/browser/extension_prefs.h"
40 #include "extensions/browser/extension_registry.h"
41 #include "extensions/browser/extension_system.h"
42 #include "extensions/browser/extensions_browser_client.h"
43 #include "extensions/browser/guest_view/guest_view_events.h"
44 #include "extensions/browser/guest_view/web_view/web_view_constants.h"
45 #include "extensions/browser/guest_view/web_view/web_view_renderer_state.h"
46 #include "extensions/browser/info_map.h"
47 #include "extensions/browser/io_thread_extension_message_filter.h"
48 #include "extensions/browser/runtime_data.h"
49 #include "extensions/browser/warning_service.h"
50 #include "extensions/browser/warning_set.h"
51 #include "extensions/common/api/web_request.h"
52 #include "extensions/common/error_utils.h"
53 #include "extensions/common/event_filtering_info.h"
54 #include "extensions/common/extension.h"
55 #include "extensions/common/features/feature.h"
56 #include "extensions/common/permissions/permissions_data.h"
57 #include "extensions/common/url_pattern.h"
58 #include "extensions/strings/grit/extensions_strings.h"
59 #include "net/base/auth.h"
60 #include "net/base/net_errors.h"
61 #include "net/base/upload_data_stream.h"
62 #include "net/http/http_response_headers.h"
63 #include "net/http/http_util.h"
64 #include "net/url_request/url_request.h"
65 #include "ui/base/l10n/l10n_util.h"
66 #include "url/gurl.h"
68 using base::DictionaryValue;
69 using base::ListValue;
70 using base::StringValue;
71 using content::BrowserMessageFilter;
72 using content::BrowserThread;
73 using content::ResourceRequestInfo;
74 using content::ResourceType;
76 namespace activity_log = activity_log_web_request_constants;
77 namespace helpers = extension_web_request_api_helpers;
78 namespace keys = extension_web_request_api_constants;
80 namespace extensions {
82 namespace declarative_keys = declarative_webrequest_constants;
83 namespace web_request = api::web_request;
85 namespace {
87 const char kWebRequestEventPrefix[] = "webRequest.";
89 // List of all the webRequest events.
90 const char* const kWebRequestEvents[] = {
91 keys::kOnBeforeRedirectEvent,
92 web_request::OnBeforeRequest::kEventName,
93 keys::kOnBeforeSendHeadersEvent,
94 keys::kOnCompletedEvent,
95 web_request::OnErrorOccurred::kEventName,
96 keys::kOnSendHeadersEvent,
97 keys::kOnAuthRequiredEvent,
98 keys::kOnResponseStartedEvent,
99 keys::kOnHeadersReceivedEvent,
102 const char* GetRequestStageAsString(
103 ExtensionWebRequestEventRouter::EventTypes type) {
104 switch (type) {
105 case ExtensionWebRequestEventRouter::kInvalidEvent:
106 return "Invalid";
107 case ExtensionWebRequestEventRouter::kOnBeforeRequest:
108 return keys::kOnBeforeRequest;
109 case ExtensionWebRequestEventRouter::kOnBeforeSendHeaders:
110 return keys::kOnBeforeSendHeaders;
111 case ExtensionWebRequestEventRouter::kOnSendHeaders:
112 return keys::kOnSendHeaders;
113 case ExtensionWebRequestEventRouter::kOnHeadersReceived:
114 return keys::kOnHeadersReceived;
115 case ExtensionWebRequestEventRouter::kOnBeforeRedirect:
116 return keys::kOnBeforeRedirect;
117 case ExtensionWebRequestEventRouter::kOnAuthRequired:
118 return keys::kOnAuthRequired;
119 case ExtensionWebRequestEventRouter::kOnResponseStarted:
120 return keys::kOnResponseStarted;
121 case ExtensionWebRequestEventRouter::kOnErrorOccurred:
122 return keys::kOnErrorOccurred;
123 case ExtensionWebRequestEventRouter::kOnCompleted:
124 return keys::kOnCompleted;
126 NOTREACHED();
127 return "Not reached";
130 int GetFrameId(bool is_main_frame, int frame_id) {
131 return is_main_frame ? 0 : frame_id;
134 bool IsWebRequestEvent(const std::string& event_name) {
135 std::string web_request_event_name(event_name);
136 if (base::StartsWith(web_request_event_name,
137 webview::kWebViewEventPrefix,
138 base::CompareCase::SENSITIVE)) {
139 web_request_event_name.replace(
140 0, strlen(webview::kWebViewEventPrefix), kWebRequestEventPrefix);
142 const auto web_request_events_end =
143 kWebRequestEvents + arraysize(kWebRequestEvents);
144 return std::find(kWebRequestEvents, web_request_events_end,
145 web_request_event_name) != web_request_events_end;
148 // Returns whether |request| has been triggered by an extension in
149 // |extension_info_map|.
150 bool IsRequestFromExtension(const net::URLRequest* request,
151 const InfoMap* extension_info_map) {
152 // |extension_info_map| is NULL for system-level requests.
153 if (!extension_info_map)
154 return false;
156 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
158 // If this request was not created by the ResourceDispatcher, |info| is NULL.
159 // All requests from extensions are created by the ResourceDispatcher.
160 if (!info)
161 return false;
163 const std::set<std::string> extension_ids =
164 extension_info_map->process_map().GetExtensionsInProcess(
165 info->GetChildID());
166 if (extension_ids.empty())
167 return false;
169 // Treat hosted apps as normal web pages (crbug.com/526413).
170 for (const std::string& extension_id : extension_ids) {
171 const Extension* extension =
172 extension_info_map->extensions().GetByID(extension_id);
173 if (extension && !extension->is_hosted_app())
174 return true;
176 return false;
179 void ExtractRequestRoutingInfo(const net::URLRequest* request,
180 int* render_process_host_id,
181 int* routing_id) {
182 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
183 if (!info)
184 return;
185 *render_process_host_id = info->GetChildID();
186 *routing_id = info->GetRouteID();
189 // Given a |request|, this function determines whether it originated from
190 // a <webview> guest process or not. If it is from a <webview> guest process,
191 // then |web_view_info| is returned with information about the instance ID
192 // that uniquely identifies the <webview> and its embedder.
193 bool GetWebViewInfo(const net::URLRequest* request,
194 WebViewRendererState::WebViewInfo* web_view_info) {
195 int render_process_host_id = -1;
196 int routing_id = -1;
197 ExtractRequestRoutingInfo(request, &render_process_host_id, &routing_id);
198 return WebViewRendererState::GetInstance()->GetInfo(
199 render_process_host_id, routing_id, web_view_info);
202 void ExtractRequestInfoDetails(const net::URLRequest* request,
203 bool* is_main_frame,
204 int* frame_id,
205 bool* parent_is_main_frame,
206 int* parent_frame_id,
207 int* render_process_host_id,
208 int* routing_id,
209 ResourceType* resource_type) {
210 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
211 if (!info)
212 return;
214 *frame_id = info->GetRenderFrameID();
215 *is_main_frame = info->IsMainFrame();
216 *parent_frame_id = info->GetParentRenderFrameID();
217 *parent_is_main_frame = info->ParentIsMainFrame();
218 *render_process_host_id = info->GetChildID();
219 *routing_id = info->GetRouteID();
221 // Restrict the resource type to the values we care about.
222 if (helpers::IsRelevantResourceType(info->GetResourceType()))
223 *resource_type = info->GetResourceType();
224 else
225 *resource_type = content::RESOURCE_TYPE_LAST_TYPE;
228 // Extracts the body from |request| and writes the data into |out|.
229 void ExtractRequestInfoBody(const net::URLRequest* request,
230 base::DictionaryValue* out) {
231 const net::UploadDataStream* upload_data = request->get_upload();
232 if (!upload_data ||
233 (request->method() != "POST" && request->method() != "PUT")) {
234 return; // Need to exit without "out->Set(keys::kRequestBodyKey, ...);" .
237 base::DictionaryValue* request_body = new base::DictionaryValue();
238 out->Set(keys::kRequestBodyKey, request_body);
240 // Get the data presenters, ordered by how specific they are.
241 ParsedDataPresenter parsed_data_presenter(*request);
242 RawDataPresenter raw_data_presenter;
243 UploadDataPresenter* const presenters[] = {
244 &parsed_data_presenter, // 1: any parseable forms? (Specific to forms.)
245 &raw_data_presenter // 2: any data at all? (Non-specific.)
247 // Keys for the results of the corresponding presenters.
248 static const char* const kKeys[] = {
249 keys::kRequestBodyFormDataKey,
250 keys::kRequestBodyRawKey
253 const ScopedVector<net::UploadElementReader>* readers =
254 upload_data->GetElementReaders();
255 bool some_succeeded = false;
256 if (readers) {
257 for (size_t i = 0; i < arraysize(presenters); ++i) {
258 for (const auto& reader : *readers)
259 presenters[i]->FeedNext(*reader);
260 if (presenters[i]->Succeeded()) {
261 request_body->Set(kKeys[i], presenters[i]->Result().release());
262 some_succeeded = true;
263 break;
267 if (!some_succeeded)
268 request_body->SetString(keys::kRequestBodyErrorKey, "Unknown error.");
271 // Converts a HttpHeaders dictionary to a |name|, |value| pair. Returns
272 // true if successful.
273 bool FromHeaderDictionary(const base::DictionaryValue* header_value,
274 std::string* name,
275 std::string* value) {
276 if (!header_value->GetString(keys::kHeaderNameKey, name))
277 return false;
279 // We require either a "value" or a "binaryValue" entry.
280 if (!(header_value->HasKey(keys::kHeaderValueKey) ^
281 header_value->HasKey(keys::kHeaderBinaryValueKey))) {
282 return false;
285 if (header_value->HasKey(keys::kHeaderValueKey)) {
286 if (!header_value->GetString(keys::kHeaderValueKey, value)) {
287 return false;
289 } else if (header_value->HasKey(keys::kHeaderBinaryValueKey)) {
290 const base::ListValue* list = NULL;
291 if (!header_value->HasKey(keys::kHeaderBinaryValueKey)) {
292 *value = "";
293 } else if (!header_value->GetList(keys::kHeaderBinaryValueKey, &list) ||
294 !helpers::CharListToString(list, value)) {
295 return false;
298 return true;
301 // Creates a list of HttpHeaders (see the extension API JSON). If |headers| is
302 // NULL, the list is empty. Ownership is passed to the caller.
303 base::ListValue* GetResponseHeadersList(
304 const net::HttpResponseHeaders* headers) {
305 base::ListValue* headers_value = new base::ListValue();
306 if (headers) {
307 void* iter = NULL;
308 std::string name;
309 std::string value;
310 while (headers->EnumerateHeaderLines(&iter, &name, &value))
311 headers_value->Append(helpers::CreateHeaderDictionary(name, value));
313 return headers_value;
316 base::ListValue* GetRequestHeadersList(const net::HttpRequestHeaders& headers) {
317 base::ListValue* headers_value = new base::ListValue();
318 for (net::HttpRequestHeaders::Iterator it(headers); it.GetNext(); )
319 headers_value->Append(
320 helpers::CreateHeaderDictionary(it.name(), it.value()));
321 return headers_value;
324 // Creates a base::StringValue with the status line of |headers|. If |headers|
325 // is NULL, an empty string is returned. Ownership is passed to the caller.
326 base::StringValue* GetStatusLine(net::HttpResponseHeaders* headers) {
327 return new base::StringValue(
328 headers ? headers->GetStatusLine() : std::string());
331 // Returns the response code from the response headers, or 200 by default.
332 // |headers| may be NULL, e.g. UrlRequestFileJobs do not send headers, so
333 // simulate their behavior.
334 int GetResponseCodeWithDefault(net::HttpResponseHeaders* headers) {
335 return headers ? headers->response_code() : 200;
338 // Sends an event to subscribers of chrome.declarativeWebRequest.onMessage or
339 // to subscribers of webview.onMessage if the action is being operated upon
340 // a <webview> guest renderer.
341 // |extension_id| identifies the extension that sends and receives the event.
342 // |is_web_view_guest| indicates whether the action is for a <webview>.
343 // |web_view_info| is a struct containing information about the <webview>
344 // embedder.
345 // |event_argument| is passed to the event listener.
346 void SendOnMessageEventOnUI(
347 void* browser_context_id,
348 const std::string& extension_id,
349 bool is_web_view_guest,
350 const WebViewRendererState::WebViewInfo& web_view_info,
351 scoped_ptr<base::DictionaryValue> event_argument) {
352 DCHECK_CURRENTLY_ON(BrowserThread::UI);
354 content::BrowserContext* browser_context =
355 reinterpret_cast<content::BrowserContext*>(browser_context_id);
356 if (!ExtensionsBrowserClient::Get()->IsValidContext(browser_context))
357 return;
359 scoped_ptr<base::ListValue> event_args(new base::ListValue);
360 event_args->Append(event_argument.release());
362 EventRouter* event_router = EventRouter::Get(browser_context);
364 EventFilteringInfo event_filtering_info;
366 events::HistogramValue histogram_value = events::UNKNOWN;
367 std::string event_name;
368 // The instance ID uniquely identifies a <webview> instance within an embedder
369 // process. We use a filter here so that only event listeners for a particular
370 // <webview> will fire.
371 if (is_web_view_guest) {
372 event_filtering_info.SetInstanceID(web_view_info.instance_id);
373 histogram_value = events::WEB_VIEW_INTERNAL_ON_MESSAGE;
374 event_name = webview::kEventMessage;
375 } else {
376 histogram_value = events::DECLARATIVE_WEB_REQUEST_ON_MESSAGE;
377 event_name = declarative_keys::kOnMessage;
380 scoped_ptr<Event> event(new Event(
381 histogram_value, event_name, event_args.Pass(), browser_context, GURL(),
382 EventRouter::USER_GESTURE_UNKNOWN, event_filtering_info));
383 event_router->DispatchEventToExtension(extension_id, event.Pass());
386 void RemoveEventListenerOnIOThread(
387 void* browser_context,
388 const std::string& extension_id,
389 const std::string& sub_event_name,
390 int embedder_process_id,
391 int web_view_instance_id) {
392 DCHECK_CURRENTLY_ON(BrowserThread::IO);
393 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(
394 browser_context, extension_id, sub_event_name,
395 embedder_process_id, web_view_instance_id);
398 events::HistogramValue GetEventHistogramValue(const std::string& event_name) {
399 // Event names will either be webRequest events, or guest view (probably web
400 // view) events that map to webRequest events. Check webRequest first.
401 static struct ValueAndName {
402 events::HistogramValue histogram_value;
403 const char* const event_name;
404 } values_and_names[] = {
405 {events::WEB_REQUEST_ON_BEFORE_REDIRECT, keys::kOnBeforeRedirectEvent},
406 {events::WEB_REQUEST_ON_BEFORE_REQUEST,
407 web_request::OnBeforeRequest::kEventName},
408 {events::WEB_REQUEST_ON_BEFORE_SEND_HEADERS,
409 keys::kOnBeforeSendHeadersEvent},
410 {events::WEB_REQUEST_ON_COMPLETED, keys::kOnCompletedEvent},
411 {events::WEB_REQUEST_ON_ERROR_OCCURRED,
412 web_request::OnErrorOccurred::kEventName},
413 {events::WEB_REQUEST_ON_SEND_HEADERS, keys::kOnSendHeadersEvent},
414 {events::WEB_REQUEST_ON_AUTH_REQUIRED, keys::kOnAuthRequiredEvent},
415 {events::WEB_REQUEST_ON_RESPONSE_STARTED, keys::kOnResponseStartedEvent},
416 {events::WEB_REQUEST_ON_HEADERS_RECEIVED, keys::kOnHeadersReceivedEvent}};
417 COMPILE_ASSERT(arraysize(kWebRequestEvents) == arraysize(values_and_names),
418 "kWebRequestEvents and values_and_names must be the same");
419 for (const ValueAndName& value_and_name : values_and_names) {
420 if (value_and_name.event_name == event_name)
421 return value_and_name.histogram_value;
424 // If there is no webRequest event, it might be a guest view webRequest event.
425 events::HistogramValue guest_view_histogram_value =
426 guest_view_events::GetEventHistogramValue(event_name);
427 if (guest_view_histogram_value != events::UNKNOWN)
428 return guest_view_histogram_value;
430 // There is no histogram value for this event name. It should be added to
431 // either the mapping here, or in guest_view_events.
432 NOTREACHED() << "Event " << event_name << " must have a histogram value";
433 return events::UNKNOWN;
436 // We hide events from the system context as well as sensitive requests.
437 bool ShouldHideEvent(void* browser_context,
438 const InfoMap* extension_info_map,
439 const net::URLRequest* request) {
440 return (!browser_context ||
441 WebRequestPermissions::HideRequest(extension_info_map, request));
444 } // namespace
446 WebRequestAPI::WebRequestAPI(content::BrowserContext* context)
447 : browser_context_(context) {
448 EventRouter* event_router = EventRouter::Get(browser_context_);
449 for (size_t i = 0; i < arraysize(kWebRequestEvents); ++i) {
450 // Observe the webRequest event.
451 std::string event_name = kWebRequestEvents[i];
452 event_router->RegisterObserver(this, event_name);
454 // Also observe the corresponding webview event.
455 event_name.replace(
456 0, sizeof(kWebRequestEventPrefix) - 1, webview::kWebViewEventPrefix);
457 event_router->RegisterObserver(this, event_name);
461 WebRequestAPI::~WebRequestAPI() {
462 EventRouter::Get(browser_context_)->UnregisterObserver(this);
465 static base::LazyInstance<BrowserContextKeyedAPIFactory<WebRequestAPI> >
466 g_factory = LAZY_INSTANCE_INITIALIZER;
468 // static
469 BrowserContextKeyedAPIFactory<WebRequestAPI>*
470 WebRequestAPI::GetFactoryInstance() {
471 return g_factory.Pointer();
474 void WebRequestAPI::OnListenerRemoved(const EventListenerInfo& details) {
475 DCHECK_CURRENTLY_ON(BrowserThread::UI);
476 // Note that details.event_name includes the sub-event details (e.g. "/123").
477 // TODO(fsamuel): <webview> events will not be removed through this code path.
478 // <webview> events will be removed in RemoveWebViewEventListeners. Ideally,
479 // this code should be decoupled from extensions, we should use the host ID
480 // instead, and not have two different code paths. This is a huge undertaking
481 // unfortunately, so we'll resort to two code paths for now.
482 BrowserThread::PostTask(BrowserThread::IO,
483 FROM_HERE,
484 base::Bind(&RemoveEventListenerOnIOThread,
485 details.browser_context,
486 details.extension_id,
487 details.event_name,
488 0 /* embedder_process_id (ignored) */,
489 0 /* web_view_instance_id */));
492 // Represents a single unique listener to an event, along with whatever filter
493 // parameters and extra_info_spec were specified at the time the listener was
494 // added.
495 // NOTE(benjhayden) New APIs should not use this sub_event_name trick! It does
496 // not play well with event pages. See downloads.onDeterminingFilename and
497 // ExtensionDownloadsEventRouter for an alternative approach.
498 struct ExtensionWebRequestEventRouter::EventListener {
499 std::string extension_id;
500 std::string extension_name;
501 events::HistogramValue histogram_value;
502 std::string sub_event_name;
503 RequestFilter filter;
504 int extra_info_spec;
505 int embedder_process_id;
506 int web_view_instance_id;
507 base::WeakPtr<IPC::Sender> ipc_sender;
508 mutable std::set<uint64_t> blocked_requests;
510 // Comparator to work with std::set.
511 bool operator<(const EventListener& that) const {
512 if (extension_id != that.extension_id)
513 return extension_id < that.extension_id;
515 if (sub_event_name != that.sub_event_name)
516 return sub_event_name < that.sub_event_name;
518 if (web_view_instance_id != that.web_view_instance_id)
519 return web_view_instance_id < that.web_view_instance_id;
521 if (web_view_instance_id == 0) {
522 // Do not filter by process ID for non-webviews, because this comparator
523 // is also used to find and remove an event listener when an extension is
524 // unloaded. At this point, the event listener cannot be mapped back to
525 // the original process, so 0 is used instead of the actual process ID.
526 DCHECK(embedder_process_id == 0 || that.embedder_process_id == 0);
527 return false;
530 if (embedder_process_id != that.embedder_process_id)
531 return embedder_process_id < that.embedder_process_id;
533 return false;
536 EventListener()
537 : histogram_value(events::UNKNOWN),
538 extra_info_spec(0),
539 embedder_process_id(0),
540 web_view_instance_id(0) {}
543 // Contains info about requests that are blocked waiting for a response from
544 // an extension.
545 struct ExtensionWebRequestEventRouter::BlockedRequest {
546 // The request that is being blocked.
547 net::URLRequest* request;
549 // Whether the request originates from an incognito tab.
550 bool is_incognito;
552 // The event that we're currently blocked on.
553 EventTypes event;
555 // The number of event handlers that we are awaiting a response from.
556 int num_handlers_blocking;
558 // Pointer to NetLog to report significant changes to the request for
559 // debugging.
560 const net::BoundNetLog* net_log;
562 // The callback to call when we get a response from all event handlers.
563 net::CompletionCallback callback;
565 // If non-empty, this contains the new URL that the request will redirect to.
566 // Only valid for OnBeforeRequest and OnHeadersReceived.
567 GURL* new_url;
569 // The request headers that will be issued along with this request. Only valid
570 // for OnBeforeSendHeaders.
571 net::HttpRequestHeaders* request_headers;
573 // The response headers that were received from the server. Only valid for
574 // OnHeadersReceived.
575 scoped_refptr<const net::HttpResponseHeaders> original_response_headers;
577 // Location where to override response headers. Only valid for
578 // OnHeadersReceived.
579 scoped_refptr<net::HttpResponseHeaders>* override_response_headers;
581 // If non-empty, this contains the auth credentials that may be filled in.
582 // Only valid for OnAuthRequired.
583 net::AuthCredentials* auth_credentials;
585 // The callback to invoke for auth. If |auth_callback.is_null()| is false,
586 // |callback| must be NULL.
587 // Only valid for OnAuthRequired.
588 net::NetworkDelegate::AuthCallback auth_callback;
590 // Time the request was paused. Used for logging purposes.
591 base::Time blocking_time;
593 // Changes requested by extensions.
594 helpers::EventResponseDeltas response_deltas;
596 // Provider of meta data about extensions, only used and non-NULL for events
597 // that are delayed until the rules registry is ready.
598 const InfoMap* extension_info_map;
600 BlockedRequest()
601 : request(NULL),
602 is_incognito(false),
603 event(kInvalidEvent),
604 num_handlers_blocking(0),
605 net_log(NULL),
606 new_url(NULL),
607 request_headers(NULL),
608 override_response_headers(NULL),
609 auth_credentials(NULL),
610 extension_info_map(NULL) {}
613 bool ExtensionWebRequestEventRouter::RequestFilter::InitFromValue(
614 const base::DictionaryValue& value, std::string* error) {
615 if (!value.HasKey("urls"))
616 return false;
618 for (base::DictionaryValue::Iterator it(value); !it.IsAtEnd(); it.Advance()) {
619 if (it.key() == "urls") {
620 const base::ListValue* urls_value = NULL;
621 if (!it.value().GetAsList(&urls_value))
622 return false;
623 for (size_t i = 0; i < urls_value->GetSize(); ++i) {
624 std::string url;
625 URLPattern pattern(
626 URLPattern::SCHEME_HTTP | URLPattern::SCHEME_HTTPS |
627 URLPattern::SCHEME_FTP | URLPattern::SCHEME_FILE |
628 URLPattern::SCHEME_EXTENSION);
629 if (!urls_value->GetString(i, &url) ||
630 pattern.Parse(url) != URLPattern::PARSE_SUCCESS) {
631 *error = ErrorUtils::FormatErrorMessage(
632 keys::kInvalidRequestFilterUrl, url);
633 return false;
635 urls.AddPattern(pattern);
637 } else if (it.key() == "types") {
638 const base::ListValue* types_value = NULL;
639 if (!it.value().GetAsList(&types_value))
640 return false;
641 for (size_t i = 0; i < types_value->GetSize(); ++i) {
642 std::string type_str;
643 ResourceType type;
644 if (!types_value->GetString(i, &type_str) ||
645 !helpers::ParseResourceType(type_str, &type)) {
646 return false;
648 types.push_back(type);
650 } else if (it.key() == "tabId") {
651 if (!it.value().GetAsInteger(&tab_id))
652 return false;
653 } else if (it.key() == "windowId") {
654 if (!it.value().GetAsInteger(&window_id))
655 return false;
656 } else {
657 return false;
660 return true;
663 // static
664 bool ExtensionWebRequestEventRouter::ExtraInfoSpec::InitFromValue(
665 const base::ListValue& value, int* extra_info_spec) {
666 *extra_info_spec = 0;
667 for (size_t i = 0; i < value.GetSize(); ++i) {
668 std::string str;
669 if (!value.GetString(i, &str))
670 return false;
672 if (str == "requestHeaders")
673 *extra_info_spec |= REQUEST_HEADERS;
674 else if (str == "responseHeaders")
675 *extra_info_spec |= RESPONSE_HEADERS;
676 else if (str == "blocking")
677 *extra_info_spec |= BLOCKING;
678 else if (str == "asyncBlocking")
679 *extra_info_spec |= ASYNC_BLOCKING;
680 else if (str == "requestBody")
681 *extra_info_spec |= REQUEST_BODY;
682 else
683 return false;
685 // BLOCKING and ASYNC_BLOCKING are mutually exclusive.
686 if ((*extra_info_spec & BLOCKING) && (*extra_info_spec & ASYNC_BLOCKING))
687 return false;
689 return true;
693 ExtensionWebRequestEventRouter::EventResponse::EventResponse(
694 const std::string& extension_id, const base::Time& extension_install_time)
695 : extension_id(extension_id),
696 extension_install_time(extension_install_time),
697 cancel(false) {
700 ExtensionWebRequestEventRouter::EventResponse::~EventResponse() {
703 ExtensionWebRequestEventRouter::RequestFilter::RequestFilter()
704 : tab_id(-1), window_id(-1) {
707 ExtensionWebRequestEventRouter::RequestFilter::~RequestFilter() {
711 // ExtensionWebRequestEventRouter
714 // static
715 ExtensionWebRequestEventRouter* ExtensionWebRequestEventRouter::GetInstance() {
716 return base::Singleton<ExtensionWebRequestEventRouter>::get();
719 ExtensionWebRequestEventRouter::ExtensionWebRequestEventRouter()
720 : request_time_tracker_(new ExtensionWebRequestTimeTracker) {
721 web_request_event_router_delegate_.reset(
722 ExtensionsAPIClient::Get()->CreateWebRequestEventRouterDelegate());
725 ExtensionWebRequestEventRouter::~ExtensionWebRequestEventRouter() {
728 void ExtensionWebRequestEventRouter::RegisterRulesRegistry(
729 void* browser_context,
730 int rules_registry_id,
731 scoped_refptr<WebRequestRulesRegistry> rules_registry) {
732 RulesRegistryKey key(browser_context, rules_registry_id);
733 if (rules_registry.get())
734 rules_registries_[key] = rules_registry;
735 else
736 rules_registries_.erase(key);
739 void ExtensionWebRequestEventRouter::ExtractRequestInfo(
740 const net::URLRequest* request,
741 base::DictionaryValue* out) {
742 bool is_main_frame = false;
743 int frame_id = -1;
744 bool parent_is_main_frame = false;
745 int parent_frame_id = -1;
746 int frame_id_for_extension = -1;
747 int parent_frame_id_for_extension = -1;
748 int render_process_host_id = -1;
749 int routing_id = -1;
750 ResourceType resource_type = content::RESOURCE_TYPE_LAST_TYPE;
751 ExtractRequestInfoDetails(request, &is_main_frame, &frame_id,
752 &parent_is_main_frame, &parent_frame_id,
753 &render_process_host_id, &routing_id,
754 &resource_type);
755 frame_id_for_extension = GetFrameId(is_main_frame, frame_id);
756 parent_frame_id_for_extension = GetFrameId(parent_is_main_frame,
757 parent_frame_id);
759 out->SetString(keys::kRequestIdKey,
760 base::Uint64ToString(request->identifier()));
761 out->SetString(keys::kUrlKey, request->url().spec());
762 out->SetString(keys::kMethodKey, request->method());
763 out->SetInteger(keys::kFrameIdKey, frame_id_for_extension);
764 out->SetInteger(keys::kParentFrameIdKey, parent_frame_id_for_extension);
765 out->SetString(keys::kTypeKey, helpers::ResourceTypeToString(resource_type));
766 out->SetDouble(keys::kTimeStampKey, base::Time::Now().ToDoubleT() * 1000);
767 if (web_request_event_router_delegate_) {
768 web_request_event_router_delegate_->ExtractExtraRequestDetails(
769 request, out);
773 int ExtensionWebRequestEventRouter::OnBeforeRequest(
774 void* browser_context,
775 const InfoMap* extension_info_map,
776 net::URLRequest* request,
777 const net::CompletionCallback& callback,
778 GURL* new_url) {
779 if (ShouldHideEvent(browser_context, extension_info_map, request))
780 return net::OK;
782 if (IsPageLoad(request))
783 NotifyPageLoad();
785 request_time_tracker_->LogRequestStartTime(request->identifier(),
786 base::Time::Now(),
787 request->url(),
788 browser_context);
790 // Whether to initialized |blocked_requests_|.
791 bool initialize_blocked_requests = false;
793 initialize_blocked_requests |=
794 ProcessDeclarativeRules(browser_context, extension_info_map,
795 web_request::OnBeforeRequest::kEventName, request,
796 ON_BEFORE_REQUEST, NULL);
798 int extra_info_spec = 0;
799 EventListeners listeners = GetMatchingListeners(
800 browser_context, extension_info_map,
801 web_request::OnBeforeRequest::kEventName, request, &extra_info_spec);
802 if (!listeners.empty() &&
803 !GetAndSetSignaled(request->identifier(), kOnBeforeRequest)) {
804 base::ListValue args;
805 base::DictionaryValue* dict = new base::DictionaryValue();
806 ExtractRequestInfo(request, dict);
807 if (extra_info_spec & ExtraInfoSpec::REQUEST_BODY)
808 ExtractRequestInfoBody(request, dict);
809 args.Append(dict);
811 initialize_blocked_requests |=
812 DispatchEvent(browser_context, request, listeners, args);
815 if (!initialize_blocked_requests)
816 return net::OK; // Nobody saw a reason for modifying the request.
818 BlockedRequest& blocked_request = blocked_requests_[request->identifier()];
819 blocked_request.event = kOnBeforeRequest;
820 blocked_request.is_incognito |= IsIncognitoBrowserContext(browser_context);
821 blocked_request.request = request;
822 blocked_request.callback = callback;
823 blocked_request.new_url = new_url;
824 blocked_request.net_log = &request->net_log();
826 if (blocked_request.num_handlers_blocking == 0) {
827 // If there are no blocking handlers, only the declarative rules tried
828 // to modify the request and we can respond synchronously.
829 return ExecuteDeltas(browser_context, request->identifier(),
830 false /* call_callback*/);
832 return net::ERR_IO_PENDING;
835 int ExtensionWebRequestEventRouter::OnBeforeSendHeaders(
836 void* browser_context,
837 const InfoMap* extension_info_map,
838 net::URLRequest* request,
839 const net::CompletionCallback& callback,
840 net::HttpRequestHeaders* headers) {
841 if (ShouldHideEvent(browser_context, extension_info_map, request))
842 return net::OK;
844 bool initialize_blocked_requests = false;
846 initialize_blocked_requests |= ProcessDeclarativeRules(
847 browser_context, extension_info_map, keys::kOnBeforeSendHeadersEvent,
848 request, ON_BEFORE_SEND_HEADERS, NULL);
850 int extra_info_spec = 0;
851 EventListeners listeners = GetMatchingListeners(
852 browser_context, extension_info_map, keys::kOnBeforeSendHeadersEvent,
853 request, &extra_info_spec);
854 if (!listeners.empty() &&
855 !GetAndSetSignaled(request->identifier(), kOnBeforeSendHeaders)) {
856 base::ListValue args;
857 base::DictionaryValue* dict = new base::DictionaryValue();
858 ExtractRequestInfo(request, dict);
859 if (extra_info_spec & ExtraInfoSpec::REQUEST_HEADERS)
860 dict->Set(keys::kRequestHeadersKey, GetRequestHeadersList(*headers));
861 args.Append(dict);
863 initialize_blocked_requests |=
864 DispatchEvent(browser_context, request, listeners, args);
867 if (!initialize_blocked_requests)
868 return net::OK; // Nobody saw a reason for modifying the request.
870 BlockedRequest& blocked_request = blocked_requests_[request->identifier()];
871 blocked_request.event = kOnBeforeSendHeaders;
872 blocked_request.is_incognito |= IsIncognitoBrowserContext(browser_context);
873 blocked_request.request = request;
874 blocked_request.callback = callback;
875 blocked_request.request_headers = headers;
876 blocked_request.net_log = &request->net_log();
878 if (blocked_request.num_handlers_blocking == 0) {
879 // If there are no blocking handlers, only the declarative rules tried
880 // to modify the request and we can respond synchronously.
881 return ExecuteDeltas(browser_context, request->identifier(),
882 false /* call_callback*/);
884 return net::ERR_IO_PENDING;
887 void ExtensionWebRequestEventRouter::OnSendHeaders(
888 void* browser_context,
889 const InfoMap* extension_info_map,
890 net::URLRequest* request,
891 const net::HttpRequestHeaders& headers) {
892 if (ShouldHideEvent(browser_context, extension_info_map, request))
893 return;
895 if (GetAndSetSignaled(request->identifier(), kOnSendHeaders))
896 return;
898 ClearSignaled(request->identifier(), kOnBeforeRedirect);
900 int extra_info_spec = 0;
901 EventListeners listeners = GetMatchingListeners(
902 browser_context, extension_info_map, keys::kOnSendHeadersEvent, request,
903 &extra_info_spec);
904 if (listeners.empty())
905 return;
907 base::ListValue args;
908 base::DictionaryValue* dict = new base::DictionaryValue();
909 ExtractRequestInfo(request, dict);
910 if (extra_info_spec & ExtraInfoSpec::REQUEST_HEADERS)
911 dict->Set(keys::kRequestHeadersKey, GetRequestHeadersList(headers));
912 args.Append(dict);
914 DispatchEvent(browser_context, request, listeners, args);
917 int ExtensionWebRequestEventRouter::OnHeadersReceived(
918 void* browser_context,
919 const InfoMap* extension_info_map,
920 net::URLRequest* request,
921 const net::CompletionCallback& callback,
922 const net::HttpResponseHeaders* original_response_headers,
923 scoped_refptr<net::HttpResponseHeaders>* override_response_headers,
924 GURL* allowed_unsafe_redirect_url) {
925 if (ShouldHideEvent(browser_context, extension_info_map, request))
926 return net::OK;
928 bool initialize_blocked_requests = false;
930 initialize_blocked_requests |= ProcessDeclarativeRules(
931 browser_context, extension_info_map, keys::kOnHeadersReceivedEvent,
932 request, ON_HEADERS_RECEIVED, original_response_headers);
934 int extra_info_spec = 0;
935 EventListeners listeners = GetMatchingListeners(
936 browser_context, extension_info_map, keys::kOnHeadersReceivedEvent,
937 request, &extra_info_spec);
939 if (!listeners.empty() &&
940 !GetAndSetSignaled(request->identifier(), kOnHeadersReceived)) {
941 base::ListValue args;
942 base::DictionaryValue* dict = new base::DictionaryValue();
943 ExtractRequestInfo(request, dict);
944 dict->SetString(keys::kStatusLineKey,
945 original_response_headers->GetStatusLine());
946 dict->SetInteger(keys::kStatusCodeKey,
947 original_response_headers->response_code());
948 if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
949 dict->Set(keys::kResponseHeadersKey,
950 GetResponseHeadersList(original_response_headers));
952 args.Append(dict);
954 initialize_blocked_requests |=
955 DispatchEvent(browser_context, request, listeners, args);
958 if (!initialize_blocked_requests)
959 return net::OK; // Nobody saw a reason for modifying the request.
961 BlockedRequest& blocked_request = blocked_requests_[request->identifier()];
962 blocked_request.event = kOnHeadersReceived;
963 blocked_request.is_incognito |= IsIncognitoBrowserContext(browser_context);
964 blocked_request.request = request;
965 blocked_request.callback = callback;
966 blocked_request.net_log = &request->net_log();
967 blocked_request.override_response_headers = override_response_headers;
968 blocked_request.original_response_headers = original_response_headers;
969 blocked_request.new_url = allowed_unsafe_redirect_url;
971 if (blocked_request.num_handlers_blocking == 0) {
972 // If there are no blocking handlers, only the declarative rules tried
973 // to modify the request and we can respond synchronously.
974 return ExecuteDeltas(browser_context, request->identifier(),
975 false /* call_callback*/);
977 return net::ERR_IO_PENDING;
980 net::NetworkDelegate::AuthRequiredResponse
981 ExtensionWebRequestEventRouter::OnAuthRequired(
982 void* browser_context,
983 const InfoMap* extension_info_map,
984 net::URLRequest* request,
985 const net::AuthChallengeInfo& auth_info,
986 const net::NetworkDelegate::AuthCallback& callback,
987 net::AuthCredentials* credentials) {
988 // No browser_context means that this is for authentication challenges in the
989 // system context. Skip in that case. Also skip sensitive requests.
990 if (!browser_context ||
991 WebRequestPermissions::HideRequest(extension_info_map, request)) {
992 return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION;
995 int extra_info_spec = 0;
996 EventListeners listeners = GetMatchingListeners(
997 browser_context, extension_info_map, keys::kOnAuthRequiredEvent, request,
998 &extra_info_spec);
999 if (listeners.empty())
1000 return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION;
1002 base::ListValue args;
1003 base::DictionaryValue* dict = new base::DictionaryValue();
1004 ExtractRequestInfo(request, dict);
1005 dict->SetBoolean(keys::kIsProxyKey, auth_info.is_proxy);
1006 if (!auth_info.scheme.empty())
1007 dict->SetString(keys::kSchemeKey, auth_info.scheme);
1008 if (!auth_info.realm.empty())
1009 dict->SetString(keys::kRealmKey, auth_info.realm);
1010 base::DictionaryValue* challenger = new base::DictionaryValue();
1011 challenger->SetString(keys::kHostKey, auth_info.challenger.host());
1012 challenger->SetInteger(keys::kPortKey, auth_info.challenger.port());
1013 dict->Set(keys::kChallengerKey, challenger);
1014 dict->Set(keys::kStatusLineKey, GetStatusLine(request->response_headers()));
1015 if (request->response_headers()) {
1016 dict->SetInteger(keys::kStatusCodeKey,
1017 request->response_headers()->response_code());
1019 if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
1020 dict->Set(keys::kResponseHeadersKey,
1021 GetResponseHeadersList(request->response_headers()));
1023 args.Append(dict);
1025 if (DispatchEvent(browser_context, request, listeners, args)) {
1026 BlockedRequest& blocked_request = blocked_requests_[request->identifier()];
1027 blocked_request.event = kOnAuthRequired;
1028 blocked_request.is_incognito |= IsIncognitoBrowserContext(browser_context);
1029 blocked_request.request = request;
1030 blocked_request.auth_callback = callback;
1031 blocked_request.auth_credentials = credentials;
1032 blocked_request.net_log = &request->net_log();
1033 return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_IO_PENDING;
1035 return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION;
1038 void ExtensionWebRequestEventRouter::OnBeforeRedirect(
1039 void* browser_context,
1040 const InfoMap* extension_info_map,
1041 net::URLRequest* request,
1042 const GURL& new_location) {
1043 if (ShouldHideEvent(browser_context, extension_info_map, request))
1044 return;
1046 if (GetAndSetSignaled(request->identifier(), kOnBeforeRedirect))
1047 return;
1049 ClearSignaled(request->identifier(), kOnBeforeRequest);
1050 ClearSignaled(request->identifier(), kOnBeforeSendHeaders);
1051 ClearSignaled(request->identifier(), kOnSendHeaders);
1052 ClearSignaled(request->identifier(), kOnHeadersReceived);
1054 int extra_info_spec = 0;
1055 EventListeners listeners = GetMatchingListeners(
1056 browser_context, extension_info_map, keys::kOnBeforeRedirectEvent,
1057 request, &extra_info_spec);
1058 if (listeners.empty())
1059 return;
1061 int http_status_code = request->GetResponseCode();
1063 std::string response_ip = request->GetSocketAddress().host();
1065 base::ListValue args;
1066 base::DictionaryValue* dict = new base::DictionaryValue();
1067 ExtractRequestInfo(request, dict);
1068 dict->SetString(keys::kRedirectUrlKey, new_location.spec());
1069 dict->SetInteger(keys::kStatusCodeKey, http_status_code);
1070 if (!response_ip.empty())
1071 dict->SetString(keys::kIpKey, response_ip);
1072 dict->SetBoolean(keys::kFromCache, request->was_cached());
1073 dict->Set(keys::kStatusLineKey, GetStatusLine(request->response_headers()));
1074 if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
1075 dict->Set(keys::kResponseHeadersKey,
1076 GetResponseHeadersList(request->response_headers()));
1078 args.Append(dict);
1080 DispatchEvent(browser_context, request, listeners, args);
1083 void ExtensionWebRequestEventRouter::OnResponseStarted(
1084 void* browser_context,
1085 const InfoMap* extension_info_map,
1086 net::URLRequest* request) {
1087 if (ShouldHideEvent(browser_context, extension_info_map, request))
1088 return;
1090 // OnResponseStarted is even triggered, when the request was cancelled.
1091 if (request->status().status() != net::URLRequestStatus::SUCCESS)
1092 return;
1094 int extra_info_spec = 0;
1095 EventListeners listeners = GetMatchingListeners(
1096 browser_context, extension_info_map, keys::kOnResponseStartedEvent,
1097 request, &extra_info_spec);
1098 if (listeners.empty())
1099 return;
1101 std::string response_ip = request->GetSocketAddress().host();
1103 base::ListValue args;
1104 base::DictionaryValue* dict = new base::DictionaryValue();
1105 ExtractRequestInfo(request, dict);
1106 if (!response_ip.empty())
1107 dict->SetString(keys::kIpKey, response_ip);
1108 dict->SetBoolean(keys::kFromCache, request->was_cached());
1109 dict->SetInteger(keys::kStatusCodeKey,
1110 GetResponseCodeWithDefault(request->response_headers()));
1111 dict->Set(keys::kStatusLineKey, GetStatusLine(request->response_headers()));
1112 if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
1113 dict->Set(keys::kResponseHeadersKey,
1114 GetResponseHeadersList(request->response_headers()));
1116 args.Append(dict);
1118 DispatchEvent(browser_context, request, listeners, args);
1121 void ExtensionWebRequestEventRouter::OnCompleted(
1122 void* browser_context,
1123 const InfoMap* extension_info_map,
1124 net::URLRequest* request) {
1125 // We hide events from the system context as well as sensitive requests.
1126 // However, if the request first became sensitive after redirecting we have
1127 // already signaled it and thus we have to signal the end of it. This is
1128 // risk-free because the handler cannot modify the request now.
1129 if (!browser_context ||
1130 (WebRequestPermissions::HideRequest(extension_info_map, request) &&
1131 !WasSignaled(*request))) {
1132 return;
1135 request_time_tracker_->LogRequestEndTime(request->identifier(),
1136 base::Time::Now());
1138 DCHECK(request->status().status() == net::URLRequestStatus::SUCCESS);
1140 DCHECK(!GetAndSetSignaled(request->identifier(), kOnCompleted));
1142 ClearPendingCallbacks(request);
1144 int extra_info_spec = 0;
1145 EventListeners listeners =
1146 GetMatchingListeners(browser_context, extension_info_map,
1147 keys::kOnCompletedEvent, request, &extra_info_spec);
1148 if (listeners.empty())
1149 return;
1151 std::string response_ip = request->GetSocketAddress().host();
1153 base::ListValue args;
1154 base::DictionaryValue* dict = new base::DictionaryValue();
1155 ExtractRequestInfo(request, dict);
1156 dict->SetInteger(keys::kStatusCodeKey,
1157 GetResponseCodeWithDefault(request->response_headers()));
1158 if (!response_ip.empty())
1159 dict->SetString(keys::kIpKey, response_ip);
1160 dict->SetBoolean(keys::kFromCache, request->was_cached());
1161 dict->Set(keys::kStatusLineKey, GetStatusLine(request->response_headers()));
1162 if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
1163 dict->Set(keys::kResponseHeadersKey,
1164 GetResponseHeadersList(request->response_headers()));
1166 args.Append(dict);
1168 DispatchEvent(browser_context, request, listeners, args);
1171 void ExtensionWebRequestEventRouter::OnErrorOccurred(
1172 void* browser_context,
1173 const InfoMap* extension_info_map,
1174 net::URLRequest* request,
1175 bool started) {
1176 // We hide events from the system context as well as sensitive requests.
1177 // However, if the request first became sensitive after redirecting we have
1178 // already signaled it and thus we have to signal the end of it. This is
1179 // risk-free because the handler cannot modify the request now.
1180 if (!browser_context ||
1181 (WebRequestPermissions::HideRequest(extension_info_map, request) &&
1182 !WasSignaled(*request))) {
1183 return;
1186 request_time_tracker_->LogRequestEndTime(request->identifier(),
1187 base::Time::Now());
1189 DCHECK(request->status().status() == net::URLRequestStatus::FAILED ||
1190 request->status().status() == net::URLRequestStatus::CANCELED);
1192 DCHECK(!GetAndSetSignaled(request->identifier(), kOnErrorOccurred));
1194 ClearPendingCallbacks(request);
1196 int extra_info_spec = 0;
1197 EventListeners listeners = GetMatchingListeners(
1198 browser_context, extension_info_map,
1199 web_request::OnErrorOccurred::kEventName, request, &extra_info_spec);
1200 if (listeners.empty())
1201 return;
1203 base::ListValue args;
1204 base::DictionaryValue* dict = new base::DictionaryValue();
1205 ExtractRequestInfo(request, dict);
1206 if (started) {
1207 std::string response_ip = request->GetSocketAddress().host();
1208 if (!response_ip.empty())
1209 dict->SetString(keys::kIpKey, response_ip);
1211 dict->SetBoolean(keys::kFromCache, request->was_cached());
1212 dict->SetString(keys::kErrorKey,
1213 net::ErrorToString(request->status().error()));
1214 args.Append(dict);
1216 DispatchEvent(browser_context, request, listeners, args);
1219 void ExtensionWebRequestEventRouter::OnURLRequestDestroyed(
1220 void* browser_context,
1221 const net::URLRequest* request) {
1222 ClearPendingCallbacks(request);
1224 signaled_requests_.erase(request->identifier());
1226 request_time_tracker_->LogRequestEndTime(request->identifier(),
1227 base::Time::Now());
1230 void ExtensionWebRequestEventRouter::OnURLRequestJobOrphaned(
1231 void* browser_context,
1232 const net::URLRequest* request) {
1233 // See https://crbug.com/289715. While a URLRequest is blocking on an
1234 // extension, it may not orphan jobs unless OnURLRequestDestroyed is called
1235 // first.
1237 // TODO(davidben): Remove this when the crash has been diagnosed.
1238 char url_buf[128];
1239 base::strlcpy(url_buf, request->url().spec().c_str(), arraysize(url_buf));
1240 base::debug::Alias(url_buf);
1241 CHECK_EQ(0u, blocked_requests_.count(request->identifier()));
1244 void ExtensionWebRequestEventRouter::ClearPendingCallbacks(
1245 const net::URLRequest* request) {
1246 blocked_requests_.erase(request->identifier());
1249 bool ExtensionWebRequestEventRouter::DispatchEvent(
1250 void* browser_context,
1251 net::URLRequest* request,
1252 const std::vector<const EventListener*>& listeners,
1253 const base::ListValue& args) {
1254 // TODO(mpcomplete): Consider consolidating common (extension_id,json_args)
1255 // pairs into a single message sent to a list of sub_event_names.
1256 int num_handlers_blocking = 0;
1257 for (const EventListener* listener : listeners) {
1258 // Filter out the optional keys that this listener didn't request.
1259 scoped_ptr<base::ListValue> args_filtered(args.DeepCopy());
1260 base::DictionaryValue* dict = NULL;
1261 CHECK(args_filtered->GetDictionary(0, &dict) && dict);
1262 if (!(listener->extra_info_spec & ExtraInfoSpec::REQUEST_HEADERS))
1263 dict->Remove(keys::kRequestHeadersKey, NULL);
1264 if (!(listener->extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS))
1265 dict->Remove(keys::kResponseHeadersKey, NULL);
1267 EventRouter::DispatchEventToSender(
1268 listener->ipc_sender.get(), browser_context, listener->extension_id,
1269 listener->histogram_value, listener->sub_event_name,
1270 args_filtered.Pass(), EventRouter::USER_GESTURE_UNKNOWN,
1271 EventFilteringInfo());
1272 if (listener->extra_info_spec &
1273 (ExtraInfoSpec::BLOCKING | ExtraInfoSpec::ASYNC_BLOCKING)) {
1274 listener->blocked_requests.insert(request->identifier());
1275 // If this is the first delegate blocking the request, go ahead and log
1276 // it.
1277 if (num_handlers_blocking == 0) {
1278 std::string delegate_info = l10n_util::GetStringFUTF8(
1279 IDS_LOAD_STATE_PARAMETER_EXTENSION,
1280 base::UTF8ToUTF16(listener->extension_name));
1281 // LobAndReport allows extensions that block requests to be displayed in
1282 // the load status bar.
1283 request->LogAndReportBlockedBy(delegate_info.c_str());
1285 ++num_handlers_blocking;
1289 if (num_handlers_blocking > 0) {
1290 BlockedRequest& blocked_request = blocked_requests_[request->identifier()];
1291 blocked_request.request = request;
1292 blocked_request.is_incognito |= IsIncognitoBrowserContext(browser_context);
1293 blocked_request.num_handlers_blocking += num_handlers_blocking;
1294 blocked_request.blocking_time = base::Time::Now();
1295 return true;
1298 return false;
1301 void ExtensionWebRequestEventRouter::OnEventHandled(
1302 void* browser_context,
1303 const std::string& extension_id,
1304 const std::string& event_name,
1305 const std::string& sub_event_name,
1306 uint64_t request_id,
1307 EventResponse* response) {
1308 // TODO(robwu): Does this also work with webviews? operator< (used by find)
1309 // takes the webview ID into account, which is not set on |listener|.
1310 EventListener listener;
1311 listener.extension_id = extension_id;
1312 listener.sub_event_name = sub_event_name;
1314 // The listener may have been removed (e.g. due to the process going away)
1315 // before we got here.
1316 std::set<EventListener>::iterator found =
1317 listeners_[browser_context][event_name].find(listener);
1318 if (found != listeners_[browser_context][event_name].end())
1319 found->blocked_requests.erase(request_id);
1321 DecrementBlockCount(
1322 browser_context, extension_id, event_name, request_id, response);
1325 bool ExtensionWebRequestEventRouter::AddEventListener(
1326 void* browser_context,
1327 const std::string& extension_id,
1328 const std::string& extension_name,
1329 events::HistogramValue histogram_value,
1330 const std::string& event_name,
1331 const std::string& sub_event_name,
1332 const RequestFilter& filter,
1333 int extra_info_spec,
1334 int embedder_process_id,
1335 int web_view_instance_id,
1336 base::WeakPtr<IPC::Sender> ipc_sender) {
1337 if (!IsWebRequestEvent(event_name))
1338 return false;
1340 EventListener listener;
1341 listener.extension_id = extension_id;
1342 listener.extension_name = extension_name;
1343 listener.histogram_value = histogram_value;
1344 listener.sub_event_name = sub_event_name;
1345 listener.filter = filter;
1346 listener.extra_info_spec = extra_info_spec;
1347 listener.ipc_sender = ipc_sender;
1348 listener.embedder_process_id = embedder_process_id;
1349 listener.web_view_instance_id = web_view_instance_id;
1350 if (listener.web_view_instance_id) {
1351 content::RecordAction(
1352 base::UserMetricsAction("WebView.WebRequest.AddListener"));
1355 if (ContainsKey(listeners_[browser_context][event_name], listener)) {
1356 // This is likely an abuse of the API by a malicious extension.
1357 return false;
1359 listeners_[browser_context][event_name].insert(listener);
1360 return true;
1363 void ExtensionWebRequestEventRouter::RemoveEventListener(
1364 void* browser_context,
1365 const std::string& extension_id,
1366 const std::string& sub_event_name,
1367 int embedder_process_id,
1368 int web_view_instance_id) {
1369 std::string event_name = EventRouter::GetBaseEventName(sub_event_name);
1370 DCHECK(IsWebRequestEvent(event_name));
1372 EventListener listener;
1373 listener.extension_id = extension_id;
1374 listener.sub_event_name = sub_event_name;
1375 listener.embedder_process_id = embedder_process_id;
1376 listener.web_view_instance_id = web_view_instance_id;
1378 std::set<EventListener>& event_listeners =
1379 listeners_[browser_context][event_name];
1380 // It's possible for AddEventListener to fail asynchronously. In that case,
1381 // the renderer believes the listener exists, while the browser does not.
1382 // Ignore a RemoveEventListener in that case.
1383 std::set<EventListener>::const_iterator it = event_listeners.find(listener);
1384 if (it == event_listeners.end())
1385 return;
1387 CHECK_EQ(event_listeners.count(listener), 1u) <<
1388 "extension=" << extension_id << " event=" << event_name;
1390 // Unblock any request that this event listener may have been blocking.
1391 for (uint64_t id : it->blocked_requests)
1392 DecrementBlockCount(browser_context, extension_id, event_name, id, NULL);
1394 event_listeners.erase(listener);
1396 helpers::ClearCacheOnNavigation();
1399 void ExtensionWebRequestEventRouter::RemoveWebViewEventListeners(
1400 void* browser_context,
1401 int embedder_process_id,
1402 int web_view_instance_id) {
1403 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1405 // Iterate over all listeners of all WebRequest events to delete
1406 // any listeners that belong to the provided <webview>.
1407 ListenerMapForBrowserContext& map_for_browser_context =
1408 listeners_[browser_context];
1409 for (const auto& event_iter : map_for_browser_context) {
1410 // Construct a listeners_to_delete vector so that we don't modify the set of
1411 // listeners as we iterate through it.
1412 std::vector<EventListener> listeners_to_delete;
1413 const std::set<EventListener>& listeners = event_iter.second;
1414 for (const auto& listener : listeners) {
1415 if (listener.embedder_process_id == embedder_process_id &&
1416 listener.web_view_instance_id == web_view_instance_id) {
1417 listeners_to_delete.push_back(listener);
1420 // Remove the listeners selected for deletion.
1421 for (const auto& listener : listeners_to_delete) {
1422 RemoveEventListenerOnIOThread(
1423 browser_context,
1424 listener.extension_id,
1425 listener.sub_event_name,
1426 listener.embedder_process_id,
1427 listener.web_view_instance_id);
1432 void ExtensionWebRequestEventRouter::OnOTRBrowserContextCreated(
1433 void* original_browser_context, void* otr_browser_context) {
1434 cross_browser_context_map_[original_browser_context] =
1435 std::make_pair(false, otr_browser_context);
1436 cross_browser_context_map_[otr_browser_context] =
1437 std::make_pair(true, original_browser_context);
1440 void ExtensionWebRequestEventRouter::OnOTRBrowserContextDestroyed(
1441 void* original_browser_context, void* otr_browser_context) {
1442 cross_browser_context_map_.erase(otr_browser_context);
1443 cross_browser_context_map_.erase(original_browser_context);
1446 void ExtensionWebRequestEventRouter::AddCallbackForPageLoad(
1447 const base::Closure& callback) {
1448 callbacks_for_page_load_.push_back(callback);
1451 bool ExtensionWebRequestEventRouter::IsPageLoad(
1452 const net::URLRequest* request) const {
1453 bool is_main_frame = false;
1454 int frame_id = -1;
1455 bool parent_is_main_frame = false;
1456 int parent_frame_id = -1;
1457 int render_process_host_id = -1;
1458 int routing_id = -1;
1459 ResourceType resource_type = content::RESOURCE_TYPE_LAST_TYPE;
1461 ExtractRequestInfoDetails(request, &is_main_frame, &frame_id,
1462 &parent_is_main_frame, &parent_frame_id,
1463 &render_process_host_id,
1464 &routing_id, &resource_type);
1466 return resource_type == content::RESOURCE_TYPE_MAIN_FRAME;
1469 void ExtensionWebRequestEventRouter::NotifyPageLoad() {
1470 for (const auto& callback : callbacks_for_page_load_)
1471 callback.Run();
1472 callbacks_for_page_load_.clear();
1475 void* ExtensionWebRequestEventRouter::GetCrossBrowserContext(
1476 void* browser_context) const {
1477 CrossBrowserContextMap::const_iterator cross_browser_context =
1478 cross_browser_context_map_.find(browser_context);
1479 if (cross_browser_context == cross_browser_context_map_.end())
1480 return NULL;
1481 return cross_browser_context->second.second;
1484 bool ExtensionWebRequestEventRouter::IsIncognitoBrowserContext(
1485 void* browser_context) const {
1486 CrossBrowserContextMap::const_iterator cross_browser_context =
1487 cross_browser_context_map_.find(browser_context);
1488 if (cross_browser_context == cross_browser_context_map_.end())
1489 return false;
1490 return cross_browser_context->second.first;
1493 bool ExtensionWebRequestEventRouter::WasSignaled(
1494 const net::URLRequest& request) const {
1495 SignaledRequestMap::const_iterator flag =
1496 signaled_requests_.find(request.identifier());
1497 return (flag != signaled_requests_.end()) && (flag->second != 0);
1500 void ExtensionWebRequestEventRouter::GetMatchingListenersImpl(
1501 void* browser_context,
1502 const net::URLRequest* request,
1503 const InfoMap* extension_info_map,
1504 bool crosses_incognito,
1505 const std::string& event_name,
1506 const GURL& url,
1507 int render_process_host_id,
1508 int routing_id,
1509 ResourceType resource_type,
1510 bool is_async_request,
1511 bool is_request_from_extension,
1512 int* extra_info_spec,
1513 EventListeners* matching_listeners) {
1514 std::string web_request_event_name(event_name);
1515 WebViewRendererState::WebViewInfo web_view_info;
1516 bool is_web_view_guest = WebViewRendererState::GetInstance()->GetInfo(
1517 render_process_host_id, routing_id, &web_view_info);
1518 if (is_web_view_guest) {
1519 web_request_event_name.replace(
1520 0, sizeof(kWebRequestEventPrefix) - 1, webview::kWebViewEventPrefix);
1523 std::set<EventListener>& listeners =
1524 listeners_[browser_context][web_request_event_name];
1525 for (const EventListener& listener : listeners) {
1526 if (!listener.ipc_sender.get()) {
1527 // The IPC sender has been deleted. This listener will be removed soon
1528 // via a call to RemoveEventListener. For now, just skip it.
1529 continue;
1532 if (is_web_view_guest &&
1533 (listener.embedder_process_id != web_view_info.embedder_process_id ||
1534 listener.web_view_instance_id != web_view_info.instance_id)) {
1535 continue;
1538 // Filter requests from other extensions / apps. This does not work for
1539 // content scripts, or extension pages in non-extension processes.
1540 if (is_request_from_extension &&
1541 listener.embedder_process_id != render_process_host_id) {
1542 continue;
1545 if (!listener.filter.urls.is_empty() &&
1546 !listener.filter.urls.MatchesURL(url)) {
1547 continue;
1550 if (web_request_event_router_delegate_ &&
1551 web_request_event_router_delegate_->OnGetMatchingListenersImplCheck(
1552 listener.filter.tab_id, listener.filter.window_id, request)) {
1553 continue;
1556 const std::vector<content::ResourceType>& types = listener.filter.types;
1557 if (!types.empty() &&
1558 std::find(types.begin(), types.end(), resource_type) == types.end()) {
1559 continue;
1562 if (!is_web_view_guest &&
1563 !WebRequestPermissions::CanExtensionAccessURL(
1564 extension_info_map, listener.extension_id, url, crosses_incognito,
1565 WebRequestPermissions::REQUIRE_HOST_PERMISSION)) {
1566 continue;
1569 bool blocking_listener =
1570 (listener.extra_info_spec &
1571 (ExtraInfoSpec::BLOCKING | ExtraInfoSpec::ASYNC_BLOCKING)) != 0;
1573 // We do not want to notify extensions about XHR requests that are
1574 // triggered by themselves. This is a workaround to prevent deadlocks
1575 // in case of synchronous XHR requests that block the extension renderer
1576 // and therefore prevent the extension from processing the request
1577 // handler. This is only a problem for blocking listeners.
1578 // http://crbug.com/105656
1579 bool synchronous_xhr_from_extension =
1580 !is_async_request && is_request_from_extension &&
1581 resource_type == content::RESOURCE_TYPE_XHR;
1583 // Only send webRequest events for URLs the extension has access to.
1584 if (blocking_listener && synchronous_xhr_from_extension)
1585 continue;
1587 matching_listeners->push_back(&listener);
1588 *extra_info_spec |= listener.extra_info_spec;
1592 ExtensionWebRequestEventRouter::EventListeners
1593 ExtensionWebRequestEventRouter::GetMatchingListeners(
1594 void* browser_context,
1595 const InfoMap* extension_info_map,
1596 const std::string& event_name,
1597 const net::URLRequest* request,
1598 int* extra_info_spec) {
1599 // TODO(mpcomplete): handle browser_context == NULL (should collect all
1600 // listeners).
1601 *extra_info_spec = 0;
1603 bool is_main_frame = false;
1604 int frame_id = -1;
1605 bool parent_is_main_frame = false;
1606 int parent_frame_id = -1;
1607 int render_process_host_id = -1;
1608 int routing_id = -1;
1609 ResourceType resource_type = content::RESOURCE_TYPE_LAST_TYPE;
1610 const GURL& url = request->url();
1612 ExtractRequestInfoDetails(request, &is_main_frame, &frame_id,
1613 &parent_is_main_frame, &parent_frame_id,
1614 &render_process_host_id,
1615 &routing_id, &resource_type);
1617 bool is_request_from_extension =
1618 IsRequestFromExtension(request, extension_info_map);
1620 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
1621 // We are conservative here and assume requests are asynchronous in case
1622 // we don't have an info object. We don't want to risk a deadlock.
1623 bool is_async_request = !info || info->IsAsync();
1625 EventListeners matching_listeners;
1626 GetMatchingListenersImpl(
1627 browser_context, request, extension_info_map, false, event_name,
1628 url, render_process_host_id, routing_id, resource_type,
1629 is_async_request, is_request_from_extension, extra_info_spec,
1630 &matching_listeners);
1631 void* cross_browser_context = GetCrossBrowserContext(browser_context);
1632 if (cross_browser_context) {
1633 GetMatchingListenersImpl(
1634 cross_browser_context, request, extension_info_map, true, event_name,
1635 url, render_process_host_id, routing_id, resource_type,
1636 is_async_request, is_request_from_extension, extra_info_spec,
1637 &matching_listeners);
1640 return matching_listeners;
1643 namespace {
1645 helpers::EventResponseDelta* CalculateDelta(
1646 ExtensionWebRequestEventRouter::BlockedRequest* blocked_request,
1647 ExtensionWebRequestEventRouter::EventResponse* response) {
1648 switch (blocked_request->event) {
1649 case ExtensionWebRequestEventRouter::kOnBeforeRequest:
1650 return helpers::CalculateOnBeforeRequestDelta(
1651 response->extension_id, response->extension_install_time,
1652 response->cancel, response->new_url);
1653 case ExtensionWebRequestEventRouter::kOnBeforeSendHeaders: {
1654 net::HttpRequestHeaders* old_headers = blocked_request->request_headers;
1655 net::HttpRequestHeaders* new_headers = response->request_headers.get();
1656 return helpers::CalculateOnBeforeSendHeadersDelta(
1657 response->extension_id, response->extension_install_time,
1658 response->cancel, old_headers, new_headers);
1660 case ExtensionWebRequestEventRouter::kOnHeadersReceived: {
1661 const net::HttpResponseHeaders* old_headers =
1662 blocked_request->original_response_headers.get();
1663 helpers::ResponseHeaders* new_headers =
1664 response->response_headers.get();
1665 return helpers::CalculateOnHeadersReceivedDelta(
1666 response->extension_id,
1667 response->extension_install_time,
1668 response->cancel,
1669 response->new_url,
1670 old_headers,
1671 new_headers);
1673 case ExtensionWebRequestEventRouter::kOnAuthRequired:
1674 return helpers::CalculateOnAuthRequiredDelta(
1675 response->extension_id, response->extension_install_time,
1676 response->cancel, &response->auth_credentials);
1677 default:
1678 NOTREACHED();
1679 return nullptr;
1683 base::Value* SerializeResponseHeaders(const helpers::ResponseHeaders& headers) {
1684 scoped_ptr<base::ListValue> serialized_headers(new base::ListValue());
1685 for (const auto& it : headers) {
1686 serialized_headers->Append(
1687 helpers::CreateHeaderDictionary(it.first, it.second));
1689 return serialized_headers.release();
1692 // Convert a RequestCookieModifications/ResponseCookieModifications object to a
1693 // base::ListValue which summarizes the changes made. This is templated since
1694 // the two types (request/response) are different but contain essentially the
1695 // same fields.
1696 template <typename CookieType>
1697 base::ListValue* SummarizeCookieModifications(
1698 const std::vector<linked_ptr<CookieType>>& modifications) {
1699 scoped_ptr<base::ListValue> cookie_modifications(new base::ListValue());
1700 for (const auto& it : modifications) {
1701 scoped_ptr<base::DictionaryValue> summary(new base::DictionaryValue());
1702 const CookieType& mod = *(it.get());
1703 switch (mod.type) {
1704 case helpers::ADD:
1705 summary->SetString(activity_log::kCookieModificationTypeKey,
1706 activity_log::kCookieModificationAdd);
1707 break;
1708 case helpers::EDIT:
1709 summary->SetString(activity_log::kCookieModificationTypeKey,
1710 activity_log::kCookieModificationEdit);
1711 break;
1712 case helpers::REMOVE:
1713 summary->SetString(activity_log::kCookieModificationTypeKey,
1714 activity_log::kCookieModificationRemove);
1715 break;
1717 if (mod.filter) {
1718 if (mod.filter->name) {
1719 summary->SetString(activity_log::kCookieFilterNameKey,
1720 *mod.modification->name);
1722 if (mod.filter->domain) {
1723 summary->SetString(activity_log::kCookieFilterDomainKey,
1724 *mod.modification->name);
1727 if (mod.modification) {
1728 if (mod.modification->name) {
1729 summary->SetString(activity_log::kCookieModDomainKey,
1730 *mod.modification->name);
1732 if (mod.modification->domain) {
1733 summary->SetString(activity_log::kCookieModDomainKey,
1734 *mod.modification->name);
1737 cookie_modifications->Append(summary.release());
1739 return cookie_modifications.release();
1742 // Converts an EventResponseDelta object to a dictionary value suitable for the
1743 // activity log.
1744 scoped_ptr<base::DictionaryValue> SummarizeResponseDelta(
1745 const std::string& event_name,
1746 const helpers::EventResponseDelta& delta) {
1747 scoped_ptr<base::DictionaryValue> details(new base::DictionaryValue());
1748 if (delta.cancel)
1749 details->SetBoolean(activity_log::kCancelKey, true);
1750 if (!delta.new_url.is_empty())
1751 details->SetString(activity_log::kNewUrlKey, delta.new_url.spec());
1753 scoped_ptr<base::ListValue> modified_headers(new base::ListValue());
1754 net::HttpRequestHeaders::Iterator iter(delta.modified_request_headers);
1755 while (iter.GetNext()) {
1756 modified_headers->Append(
1757 helpers::CreateHeaderDictionary(iter.name(), iter.value()));
1759 if (!modified_headers->empty()) {
1760 details->Set(activity_log::kModifiedRequestHeadersKey,
1761 modified_headers.release());
1764 scoped_ptr<base::ListValue> deleted_headers(new base::ListValue());
1765 deleted_headers->AppendStrings(delta.deleted_request_headers);
1766 if (!deleted_headers->empty()) {
1767 details->Set(activity_log::kDeletedRequestHeadersKey,
1768 deleted_headers.release());
1771 if (!delta.added_response_headers.empty()) {
1772 details->Set(activity_log::kAddedRequestHeadersKey,
1773 SerializeResponseHeaders(delta.added_response_headers));
1775 if (!delta.deleted_response_headers.empty()) {
1776 details->Set(activity_log::kDeletedResponseHeadersKey,
1777 SerializeResponseHeaders(delta.deleted_response_headers));
1779 if (delta.auth_credentials) {
1780 details->SetString(
1781 activity_log::kAuthCredentialsKey,
1782 base::UTF16ToUTF8(delta.auth_credentials->username()) + ":*");
1785 if (!delta.response_cookie_modifications.empty()) {
1786 details->Set(
1787 activity_log::kResponseCookieModificationsKey,
1788 SummarizeCookieModifications(delta.response_cookie_modifications));
1791 return details.Pass();
1794 } // namespace
1796 void ExtensionWebRequestEventRouter::LogExtensionActivity(
1797 void* browser_context_id,
1798 bool is_incognito,
1799 const std::string& extension_id,
1800 const GURL& url,
1801 const std::string& api_call,
1802 scoped_ptr<base::DictionaryValue> details) {
1803 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
1804 BrowserThread::PostTask(
1805 BrowserThread::UI,
1806 FROM_HERE,
1807 base::Bind(&ExtensionWebRequestEventRouter::LogExtensionActivity,
1808 base::Unretained(this),
1809 browser_context_id,
1810 is_incognito,
1811 extension_id,
1812 url,
1813 api_call,
1814 base::Passed(&details)));
1815 } else {
1816 if (web_request_event_router_delegate_) {
1817 web_request_event_router_delegate_->LogExtensionActivity(
1818 reinterpret_cast<content::BrowserContext*>(browser_context_id),
1819 is_incognito, extension_id, url, api_call, details.Pass());
1824 void ExtensionWebRequestEventRouter::DecrementBlockCount(
1825 void* browser_context,
1826 const std::string& extension_id,
1827 const std::string& event_name,
1828 uint64_t request_id,
1829 EventResponse* response) {
1830 scoped_ptr<EventResponse> response_scoped(response);
1832 // It's possible that this request was deleted, or cancelled by a previous
1833 // event handler. If so, ignore this response.
1834 auto it = blocked_requests_.find(request_id);
1835 if (it == blocked_requests_.end())
1836 return;
1838 BlockedRequest& blocked_request = it->second;
1839 int num_handlers_blocking = --blocked_request.num_handlers_blocking;
1840 CHECK_GE(num_handlers_blocking, 0);
1842 if (response) {
1843 helpers::EventResponseDelta* delta =
1844 CalculateDelta(&blocked_request, response);
1846 LogExtensionActivity(browser_context,
1847 blocked_request.is_incognito,
1848 extension_id,
1849 blocked_request.request->url(),
1850 event_name,
1851 SummarizeResponseDelta(event_name, *delta));
1853 blocked_request.response_deltas.push_back(
1854 linked_ptr<helpers::EventResponseDelta>(delta));
1857 base::TimeDelta block_time =
1858 base::Time::Now() - blocked_request.blocking_time;
1859 if (!extension_id.empty()) {
1860 request_time_tracker_->IncrementExtensionBlockTime(
1861 extension_id, request_id, block_time);
1862 } else {
1863 // |extension_id| is empty for requests blocked on startup waiting for the
1864 // declarative rules to be read from disk.
1865 UMA_HISTOGRAM_TIMES("Extensions.NetworkDelayStartup", block_time);
1868 if (num_handlers_blocking == 0) {
1869 blocked_request.request->LogUnblocked();
1870 ExecuteDeltas(browser_context, request_id, true);
1871 } else {
1872 // Update the URLRequest to make sure it's tagged with an extension that's
1873 // still blocking it. This may end up being the same extension as before.
1874 std::set<EventListener>& listeners =
1875 listeners_[browser_context][event_name];
1877 for (const auto& listener : listeners) {
1878 if (!ContainsKey(listener.blocked_requests, request_id))
1879 continue;
1880 std::string delegate_info =
1881 l10n_util::GetStringFUTF8(IDS_LOAD_STATE_PARAMETER_EXTENSION,
1882 base::UTF8ToUTF16(listener.extension_name));
1883 blocked_request.request->LogAndReportBlockedBy(delegate_info.c_str());
1884 break;
1889 void ExtensionWebRequestEventRouter::SendMessages(
1890 void* browser_context,
1891 const BlockedRequest& blocked_request) {
1892 const helpers::EventResponseDeltas& deltas = blocked_request.response_deltas;
1893 for (const auto& delta : deltas) {
1894 const std::set<std::string>& messages = delta->messages_to_extension;
1895 for (const std::string& message : messages) {
1896 scoped_ptr<base::DictionaryValue> argument(new base::DictionaryValue);
1897 ExtractRequestInfo(blocked_request.request, argument.get());
1898 WebViewRendererState::WebViewInfo web_view_info;
1899 bool is_web_view_guest = GetWebViewInfo(blocked_request.request,
1900 &web_view_info);
1901 argument->SetString(keys::kMessageKey, message);
1902 argument->SetString(keys::kStageKey,
1903 GetRequestStageAsString(blocked_request.event));
1905 BrowserThread::PostTask(
1906 BrowserThread::UI, FROM_HERE,
1907 base::Bind(&SendOnMessageEventOnUI, browser_context,
1908 delta->extension_id, is_web_view_guest, web_view_info,
1909 base::Passed(&argument)));
1914 int ExtensionWebRequestEventRouter::ExecuteDeltas(void* browser_context,
1915 uint64_t request_id,
1916 bool call_callback) {
1917 BlockedRequest& blocked_request = blocked_requests_[request_id];
1918 CHECK_EQ(0, blocked_request.num_handlers_blocking);
1919 helpers::EventResponseDeltas& deltas = blocked_request.response_deltas;
1920 base::TimeDelta block_time =
1921 base::Time::Now() - blocked_request.blocking_time;
1922 request_time_tracker_->IncrementTotalBlockTime(request_id, block_time);
1924 bool credentials_set = false;
1926 deltas.sort(&helpers::InDecreasingExtensionInstallationTimeOrder);
1928 bool canceled = false;
1929 helpers::MergeCancelOfResponses(blocked_request.response_deltas, &canceled,
1930 blocked_request.net_log);
1932 WarningSet warnings;
1933 if (blocked_request.event == kOnBeforeRequest) {
1934 CHECK(!blocked_request.callback.is_null());
1935 helpers::MergeOnBeforeRequestResponses(
1936 blocked_request.response_deltas,
1937 blocked_request.new_url,
1938 &warnings,
1939 blocked_request.net_log);
1940 } else if (blocked_request.event == kOnBeforeSendHeaders) {
1941 CHECK(!blocked_request.callback.is_null());
1942 helpers::MergeOnBeforeSendHeadersResponses(
1943 blocked_request.response_deltas,
1944 blocked_request.request_headers,
1945 &warnings,
1946 blocked_request.net_log);
1947 } else if (blocked_request.event == kOnHeadersReceived) {
1948 CHECK(!blocked_request.callback.is_null());
1949 helpers::MergeOnHeadersReceivedResponses(
1950 blocked_request.response_deltas,
1951 blocked_request.original_response_headers.get(),
1952 blocked_request.override_response_headers,
1953 blocked_request.new_url,
1954 &warnings,
1955 blocked_request.net_log);
1956 } else if (blocked_request.event == kOnAuthRequired) {
1957 CHECK(blocked_request.callback.is_null());
1958 CHECK(!blocked_request.auth_callback.is_null());
1959 credentials_set = helpers::MergeOnAuthRequiredResponses(
1960 blocked_request.response_deltas,
1961 blocked_request.auth_credentials,
1962 &warnings,
1963 blocked_request.net_log);
1964 } else {
1965 NOTREACHED();
1968 SendMessages(browser_context, blocked_request);
1970 if (!warnings.empty()) {
1971 BrowserThread::PostTask(
1972 BrowserThread::UI,
1973 FROM_HERE,
1974 base::Bind(&WarningService::NotifyWarningsOnUI,
1975 browser_context, warnings));
1978 if (canceled) {
1979 request_time_tracker_->SetRequestCanceled(request_id);
1980 } else if (blocked_request.new_url &&
1981 !blocked_request.new_url->is_empty()) {
1982 request_time_tracker_->SetRequestRedirected(request_id);
1985 // This triggers onErrorOccurred if canceled is true.
1986 int rv = canceled ? net::ERR_BLOCKED_BY_CLIENT : net::OK;
1988 if (!blocked_request.callback.is_null()) {
1989 net::CompletionCallback callback = blocked_request.callback;
1990 // Ensure that request is removed before callback because the callback
1991 // might trigger the next event.
1992 blocked_requests_.erase(request_id);
1993 if (call_callback)
1994 callback.Run(rv);
1995 } else if (!blocked_request.auth_callback.is_null()) {
1996 net::NetworkDelegate::AuthRequiredResponse response;
1997 if (canceled)
1998 response = net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_CANCEL_AUTH;
1999 else if (credentials_set)
2000 response = net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_SET_AUTH;
2001 else
2002 response = net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION;
2004 net::NetworkDelegate::AuthCallback callback = blocked_request.auth_callback;
2005 blocked_requests_.erase(request_id);
2006 if (call_callback)
2007 callback.Run(response);
2008 } else {
2009 blocked_requests_.erase(request_id);
2011 return rv;
2014 bool ExtensionWebRequestEventRouter::ProcessDeclarativeRules(
2015 void* browser_context,
2016 const InfoMap* extension_info_map,
2017 const std::string& event_name,
2018 net::URLRequest* request,
2019 RequestStage request_stage,
2020 const net::HttpResponseHeaders* original_response_headers) {
2021 WebViewRendererState::WebViewInfo web_view_info;
2022 bool is_web_view_guest = GetWebViewInfo(request, &web_view_info);
2023 int rules_registry_id = is_web_view_guest
2024 ? web_view_info.rules_registry_id
2025 : RulesRegistryService::kDefaultRulesRegistryID;
2027 RulesRegistryKey rules_key(browser_context, rules_registry_id);
2028 // If this check fails, check that the active stages are up-to-date in
2029 // extensions/browser/api/declarative_webrequest/request_stage.h .
2030 DCHECK(request_stage & kActiveStages);
2032 // Rules of the current |browser_context| may apply but we need to check also
2033 // whether there are applicable rules from extensions whose background page
2034 // spans from regular to incognito mode.
2036 // First parameter identifies the registry, the second indicates whether the
2037 // registry belongs to the cross browser_context.
2038 using RelevantRegistry = std::pair<WebRequestRulesRegistry*, bool>;
2039 std::vector<RelevantRegistry> relevant_registries;
2041 auto rules_key_it = rules_registries_.find(rules_key);
2042 if (rules_key_it != rules_registries_.end()) {
2043 relevant_registries.push_back(
2044 std::make_pair(rules_key_it->second.get(), false));
2047 void* cross_browser_context = GetCrossBrowserContext(browser_context);
2048 RulesRegistryKey cross_browser_context_rules_key(cross_browser_context,
2049 rules_registry_id);
2050 if (cross_browser_context) {
2051 auto it = rules_registries_.find(cross_browser_context_rules_key);
2052 if (it != rules_registries_.end())
2053 relevant_registries.push_back(std::make_pair(it->second.get(), true));
2056 // The following block is experimentally enabled and its impact on load time
2057 // logged with UMA Extensions.NetworkDelayRegistryLoad. crbug.com/175961
2058 for (auto it : relevant_registries) {
2059 WebRequestRulesRegistry* rules_registry = it.first;
2060 if (rules_registry->ready().is_signaled())
2061 continue;
2063 // The rules registry is still loading. Block this request until it
2064 // finishes.
2065 rules_registry->ready().Post(
2066 FROM_HERE,
2067 base::Bind(&ExtensionWebRequestEventRouter::OnRulesRegistryReady,
2068 AsWeakPtr(), browser_context, event_name,
2069 request->identifier(), request_stage));
2070 BlockedRequest& blocked_request = blocked_requests_[request->identifier()];
2071 blocked_request.num_handlers_blocking++;
2072 blocked_request.request = request;
2073 blocked_request.is_incognito |= IsIncognitoBrowserContext(browser_context);
2074 blocked_request.blocking_time = base::Time::Now();
2075 blocked_request.original_response_headers = original_response_headers;
2076 blocked_request.extension_info_map = extension_info_map;
2077 return true;
2080 base::Time start = base::Time::Now();
2082 bool deltas_created = false;
2083 for (const auto& it : relevant_registries) {
2084 WebRequestRulesRegistry* rules_registry = it.first;
2085 helpers::EventResponseDeltas result = rules_registry->CreateDeltas(
2086 extension_info_map,
2087 WebRequestData(request, request_stage, original_response_headers),
2088 it.second);
2090 if (!result.empty()) {
2091 helpers::EventResponseDeltas& deltas =
2092 blocked_requests_[request->identifier()].response_deltas;
2093 deltas.insert(deltas.end(), result.begin(), result.end());
2094 deltas_created = true;
2098 base::TimeDelta elapsed_time = start - base::Time::Now();
2099 UMA_HISTOGRAM_TIMES("Extensions.DeclarativeWebRequestNetworkDelay",
2100 elapsed_time);
2102 return deltas_created;
2105 void ExtensionWebRequestEventRouter::OnRulesRegistryReady(
2106 void* browser_context,
2107 const std::string& event_name,
2108 uint64_t request_id,
2109 RequestStage request_stage) {
2110 // It's possible that this request was deleted, or cancelled by a previous
2111 // event handler. If so, ignore this response.
2112 auto it = blocked_requests_.find(request_id);
2113 if (it == blocked_requests_.end())
2114 return;
2116 BlockedRequest& blocked_request = it->second;
2117 base::TimeDelta block_time =
2118 base::Time::Now() - blocked_request.blocking_time;
2119 UMA_HISTOGRAM_TIMES("Extensions.NetworkDelayRegistryLoad", block_time);
2121 ProcessDeclarativeRules(browser_context,
2122 blocked_request.extension_info_map,
2123 event_name,
2124 blocked_request.request,
2125 request_stage,
2126 blocked_request.original_response_headers.get());
2127 // Reset to NULL so that nobody relies on this being set.
2128 blocked_request.extension_info_map = NULL;
2129 DecrementBlockCount(
2130 browser_context, std::string(), event_name, request_id, NULL);
2133 bool ExtensionWebRequestEventRouter::GetAndSetSignaled(uint64_t request_id,
2134 EventTypes event_type) {
2135 SignaledRequestMap::iterator iter = signaled_requests_.find(request_id);
2136 if (iter == signaled_requests_.end()) {
2137 signaled_requests_[request_id] = event_type;
2138 return false;
2140 bool was_signaled_before = (iter->second & event_type) != 0;
2141 iter->second |= event_type;
2142 return was_signaled_before;
2145 void ExtensionWebRequestEventRouter::ClearSignaled(uint64_t request_id,
2146 EventTypes event_type) {
2147 SignaledRequestMap::iterator iter = signaled_requests_.find(request_id);
2148 if (iter == signaled_requests_.end())
2149 return;
2150 iter->second &= ~event_type;
2153 // Special QuotaLimitHeuristic for WebRequestHandlerBehaviorChangedFunction.
2155 // Each call of webRequest.handlerBehaviorChanged() clears the in-memory cache
2156 // of WebKit at the time of the next page load (top level navigation event).
2157 // This quota heuristic is intended to limit the number of times the cache is
2158 // cleared by an extension.
2160 // As we want to account for the number of times the cache is really cleared
2161 // (opposed to the number of times webRequest.handlerBehaviorChanged() is
2162 // called), we cannot decide whether a call of
2163 // webRequest.handlerBehaviorChanged() should trigger a quota violation at the
2164 // time it is called. Instead we only decrement the bucket counter at the time
2165 // when the cache is cleared (when page loads happen).
2166 class ClearCacheQuotaHeuristic : public QuotaLimitHeuristic {
2167 public:
2168 ClearCacheQuotaHeuristic(const Config& config, BucketMapper* map)
2169 : QuotaLimitHeuristic(
2170 config,
2171 map,
2172 "MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES"),
2173 callback_registered_(false),
2174 weak_ptr_factory_(this) {}
2175 ~ClearCacheQuotaHeuristic() override {}
2176 bool Apply(Bucket* bucket, const base::TimeTicks& event_time) override;
2178 private:
2179 // Callback that is triggered by the ExtensionWebRequestEventRouter on a page
2180 // load.
2182 // We don't need to take care of the life time of |bucket|: It is owned by the
2183 // BucketMapper of our base class in |QuotaLimitHeuristic::bucket_mapper_|. As
2184 // long as |this| exists, the respective BucketMapper and its bucket will
2185 // exist as well.
2186 void OnPageLoad(Bucket* bucket);
2188 // Flag to prevent that we register more than one call back in-between
2189 // clearing the cache.
2190 bool callback_registered_;
2192 base::WeakPtrFactory<ClearCacheQuotaHeuristic> weak_ptr_factory_;
2194 DISALLOW_COPY_AND_ASSIGN(ClearCacheQuotaHeuristic);
2197 bool ClearCacheQuotaHeuristic::Apply(Bucket* bucket,
2198 const base::TimeTicks& event_time) {
2199 if (event_time > bucket->expiration())
2200 bucket->Reset(config(), event_time);
2202 // Call bucket->DeductToken() on a new page load, this is when
2203 // webRequest.handlerBehaviorChanged() clears the cache.
2204 if (!callback_registered_) {
2205 ExtensionWebRequestEventRouter::GetInstance()->AddCallbackForPageLoad(
2206 base::Bind(&ClearCacheQuotaHeuristic::OnPageLoad,
2207 weak_ptr_factory_.GetWeakPtr(),
2208 bucket));
2209 callback_registered_ = true;
2212 // We only check whether tokens are left here. Deducting a token happens in
2213 // OnPageLoad().
2214 return bucket->has_tokens();
2217 void ClearCacheQuotaHeuristic::OnPageLoad(Bucket* bucket) {
2218 callback_registered_ = false;
2219 bucket->DeductToken();
2222 bool WebRequestInternalAddEventListenerFunction::RunSync() {
2223 // Argument 0 is the callback, which we don't use here.
2224 ExtensionWebRequestEventRouter::RequestFilter filter;
2225 base::DictionaryValue* value = NULL;
2226 error_.clear();
2227 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &value));
2228 // Failure + an empty error string means a fatal error.
2229 EXTENSION_FUNCTION_VALIDATE(filter.InitFromValue(*value, &error_) ||
2230 !error_.empty());
2231 if (!error_.empty())
2232 return false;
2234 int extra_info_spec = 0;
2235 if (HasOptionalArgument(2)) {
2236 base::ListValue* value = NULL;
2237 EXTENSION_FUNCTION_VALIDATE(args_->GetList(2, &value));
2238 EXTENSION_FUNCTION_VALIDATE(
2239 ExtensionWebRequestEventRouter::ExtraInfoSpec::InitFromValue(
2240 *value, &extra_info_spec));
2243 std::string event_name;
2244 EXTENSION_FUNCTION_VALIDATE(args_->GetString(3, &event_name));
2246 std::string sub_event_name;
2247 EXTENSION_FUNCTION_VALIDATE(args_->GetString(4, &sub_event_name));
2249 int web_view_instance_id = 0;
2250 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(5, &web_view_instance_id));
2252 base::WeakPtr<IOThreadExtensionMessageFilter> ipc_sender = ipc_sender_weak();
2253 int embedder_process_id = ipc_sender ? ipc_sender->render_process_id() : 0;
2255 const Extension* extension =
2256 extension_info_map()->extensions().GetByID(extension_id_safe());
2257 std::string extension_name =
2258 extension ? extension->name() : extension_id_safe();
2260 if (!web_view_instance_id) {
2261 // We check automatically whether the extension has the 'webRequest'
2262 // permission. For blocking calls we require the additional permission
2263 // 'webRequestBlocking'.
2264 if ((extra_info_spec &
2265 (ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING |
2266 ExtensionWebRequestEventRouter::ExtraInfoSpec::ASYNC_BLOCKING)) &&
2267 !extension->permissions_data()->HasAPIPermission(
2268 APIPermission::kWebRequestBlocking)) {
2269 error_ = keys::kBlockingPermissionRequired;
2270 return false;
2273 // We allow to subscribe to patterns that are broader than the host
2274 // permissions. E.g., we could subscribe to http://www.example.com/*
2275 // while having host permissions for http://www.example.com/foo/* and
2276 // http://www.example.com/bar/*.
2277 // For this reason we do only a coarse check here to warn the extension
2278 // developer if he does something obviously wrong.
2279 if (extension->permissions_data()
2280 ->GetEffectiveHostPermissions()
2281 .is_empty()) {
2282 error_ = keys::kHostPermissionsRequired;
2283 return false;
2287 bool success =
2288 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
2289 profile_id(), extension_id_safe(), extension_name,
2290 GetEventHistogramValue(event_name), event_name, sub_event_name,
2291 filter, extra_info_spec, embedder_process_id, web_view_instance_id,
2292 ipc_sender_weak());
2293 EXTENSION_FUNCTION_VALIDATE(success);
2295 helpers::ClearCacheOnNavigation();
2297 if (!extension_id_safe().empty()) {
2298 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
2299 base::Bind(&helpers::NotifyWebRequestAPIUsed,
2300 profile_id(), extension_id_safe()));
2303 return true;
2306 void WebRequestInternalEventHandledFunction::RespondWithError(
2307 const std::string& event_name,
2308 const std::string& sub_event_name,
2309 uint64_t request_id,
2310 scoped_ptr<ExtensionWebRequestEventRouter::EventResponse> response,
2311 const std::string& error) {
2312 error_ = error;
2313 ExtensionWebRequestEventRouter::GetInstance()->OnEventHandled(
2314 profile_id(),
2315 extension_id_safe(),
2316 event_name,
2317 sub_event_name,
2318 request_id,
2319 response.release());
2322 bool WebRequestInternalEventHandledFunction::RunSync() {
2323 std::string event_name;
2324 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &event_name));
2326 std::string sub_event_name;
2327 EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &sub_event_name));
2329 std::string request_id_str;
2330 EXTENSION_FUNCTION_VALIDATE(args_->GetString(2, &request_id_str));
2331 uint64_t request_id;
2332 EXTENSION_FUNCTION_VALIDATE(base::StringToUint64(request_id_str,
2333 &request_id));
2335 scoped_ptr<ExtensionWebRequestEventRouter::EventResponse> response;
2336 if (HasOptionalArgument(3)) {
2337 base::DictionaryValue* value = NULL;
2338 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(3, &value));
2340 if (!value->empty()) {
2341 base::Time install_time =
2342 extension_info_map()->GetInstallTime(extension_id_safe());
2343 response.reset(new ExtensionWebRequestEventRouter::EventResponse(
2344 extension_id_safe(), install_time));
2347 if (value->HasKey("cancel")) {
2348 // Don't allow cancel mixed with other keys.
2349 if (value->size() != 1) {
2350 RespondWithError(event_name,
2351 sub_event_name,
2352 request_id,
2353 response.Pass(),
2354 keys::kInvalidBlockingResponse);
2355 return false;
2358 bool cancel = false;
2359 EXTENSION_FUNCTION_VALIDATE(value->GetBoolean("cancel", &cancel));
2360 response->cancel = cancel;
2363 if (value->HasKey("redirectUrl")) {
2364 std::string new_url_str;
2365 EXTENSION_FUNCTION_VALIDATE(value->GetString("redirectUrl",
2366 &new_url_str));
2367 response->new_url = GURL(new_url_str);
2368 if (!response->new_url.is_valid()) {
2369 RespondWithError(event_name,
2370 sub_event_name,
2371 request_id,
2372 response.Pass(),
2373 ErrorUtils::FormatErrorMessage(
2374 keys::kInvalidRedirectUrl, new_url_str));
2375 return false;
2379 const bool has_request_headers = value->HasKey("requestHeaders");
2380 const bool has_response_headers = value->HasKey("responseHeaders");
2381 if (has_request_headers || has_response_headers) {
2382 if (has_request_headers && has_response_headers) {
2383 // Allow only one of the keys, not both.
2384 RespondWithError(event_name,
2385 sub_event_name,
2386 request_id,
2387 response.Pass(),
2388 keys::kInvalidHeaderKeyCombination);
2389 return false;
2392 base::ListValue* headers_value = NULL;
2393 scoped_ptr<net::HttpRequestHeaders> request_headers;
2394 scoped_ptr<helpers::ResponseHeaders> response_headers;
2395 if (has_request_headers) {
2396 request_headers.reset(new net::HttpRequestHeaders());
2397 EXTENSION_FUNCTION_VALIDATE(value->GetList(keys::kRequestHeadersKey,
2398 &headers_value));
2399 } else {
2400 response_headers.reset(new helpers::ResponseHeaders());
2401 EXTENSION_FUNCTION_VALIDATE(value->GetList(keys::kResponseHeadersKey,
2402 &headers_value));
2405 for (size_t i = 0; i < headers_value->GetSize(); ++i) {
2406 base::DictionaryValue* header_value = NULL;
2407 std::string name;
2408 std::string value;
2409 EXTENSION_FUNCTION_VALIDATE(
2410 headers_value->GetDictionary(i, &header_value));
2411 if (!FromHeaderDictionary(header_value, &name, &value)) {
2412 std::string serialized_header;
2413 base::JSONWriter::Write(*header_value, &serialized_header);
2414 RespondWithError(event_name,
2415 sub_event_name,
2416 request_id,
2417 response.Pass(),
2418 ErrorUtils::FormatErrorMessage(keys::kInvalidHeader,
2419 serialized_header));
2420 return false;
2422 if (!net::HttpUtil::IsValidHeaderName(name)) {
2423 RespondWithError(event_name,
2424 sub_event_name,
2425 request_id,
2426 response.Pass(),
2427 keys::kInvalidHeaderName);
2428 return false;
2430 if (!net::HttpUtil::IsValidHeaderValue(value)) {
2431 RespondWithError(event_name,
2432 sub_event_name,
2433 request_id,
2434 response.Pass(),
2435 ErrorUtils::FormatErrorMessage(
2436 keys::kInvalidHeaderValue, name));
2437 return false;
2439 if (has_request_headers)
2440 request_headers->SetHeader(name, value);
2441 else
2442 response_headers->push_back(helpers::ResponseHeader(name, value));
2444 if (has_request_headers)
2445 response->request_headers.reset(request_headers.release());
2446 else
2447 response->response_headers.reset(response_headers.release());
2450 if (value->HasKey(keys::kAuthCredentialsKey)) {
2451 base::DictionaryValue* credentials_value = NULL;
2452 EXTENSION_FUNCTION_VALIDATE(value->GetDictionary(
2453 keys::kAuthCredentialsKey,
2454 &credentials_value));
2455 base::string16 username;
2456 base::string16 password;
2457 EXTENSION_FUNCTION_VALIDATE(
2458 credentials_value->GetString(keys::kUsernameKey, &username));
2459 EXTENSION_FUNCTION_VALIDATE(
2460 credentials_value->GetString(keys::kPasswordKey, &password));
2461 response->auth_credentials.reset(
2462 new net::AuthCredentials(username, password));
2466 ExtensionWebRequestEventRouter::GetInstance()->OnEventHandled(
2467 profile_id(), extension_id_safe(), event_name, sub_event_name, request_id,
2468 response.release());
2470 return true;
2473 void WebRequestHandlerBehaviorChangedFunction::GetQuotaLimitHeuristics(
2474 QuotaLimitHeuristics* heuristics) const {
2475 QuotaLimitHeuristic::Config config = {
2476 // See web_request.json for current value.
2477 web_request::MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES,
2478 base::TimeDelta::FromMinutes(10)};
2479 QuotaLimitHeuristic::BucketMapper* bucket_mapper =
2480 new QuotaLimitHeuristic::SingletonBucketMapper();
2481 ClearCacheQuotaHeuristic* heuristic =
2482 new ClearCacheQuotaHeuristic(config, bucket_mapper);
2483 heuristics->push_back(heuristic);
2486 void WebRequestHandlerBehaviorChangedFunction::OnQuotaExceeded(
2487 const std::string& violation_error) {
2488 // Post warning message.
2489 WarningSet warnings;
2490 warnings.insert(
2491 Warning::CreateRepeatedCacheFlushesWarning(extension_id_safe()));
2492 BrowserThread::PostTask(
2493 BrowserThread::UI,
2494 FROM_HERE,
2495 base::Bind(&WarningService::NotifyWarningsOnUI, profile_id(), warnings));
2497 // Continue gracefully.
2498 RunSync();
2501 bool WebRequestHandlerBehaviorChangedFunction::RunSync() {
2502 helpers::ClearCacheOnNavigation();
2503 return true;
2506 } // namespace extensions