Simplify WebNavigationApi by using RenderFrameHost internally.
[chromium-blink-merge.git] / chrome / browser / extensions / api / web_request / web_request_api.cc
bloba0628a51a7c59941c47f89d8d37950ae4ea609b2
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 "chrome/browser/extensions/api/web_request/web_request_api.h"
7 #include <algorithm>
9 #include "base/bind.h"
10 #include "base/bind_helpers.h"
11 #include "base/json/json_writer.h"
12 #include "base/lazy_instance.h"
13 #include "base/metrics/histogram.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/string_util.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "base/time/time.h"
18 #include "base/values.h"
19 #include "chrome/browser/browser_process.h"
20 #include "chrome/browser/chrome_content_browser_client.h"
21 #include "chrome/browser/extensions/activity_log/activity_action_constants.h"
22 #include "chrome/browser/extensions/activity_log/activity_actions.h"
23 #include "chrome/browser/extensions/activity_log/activity_log.h"
24 #include "chrome/browser/extensions/activity_log/web_request_constants.h"
25 #include "chrome/browser/extensions/api/declarative_webrequest/request_stage.h"
26 #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_constants.h"
27 #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry.h"
28 #include "chrome/browser/extensions/api/web_request/upload_data_presenter.h"
29 #include "chrome/browser/extensions/api/web_request/web_request_api_constants.h"
30 #include "chrome/browser/extensions/api/web_request/web_request_api_helpers.h"
31 #include "chrome/browser/extensions/api/web_request/web_request_time_tracker.h"
32 #include "chrome/browser/extensions/extension_renderer_state.h"
33 #include "chrome/browser/extensions/extension_warning_service.h"
34 #include "chrome/browser/extensions/extension_warning_set.h"
35 #include "chrome/browser/guest_view/web_view/web_view_constants.h"
36 #include "chrome/browser/guest_view/web_view/web_view_renderer_state.h"
37 #include "chrome/browser/profiles/profile.h"
38 #include "chrome/browser/profiles/profile_manager.h"
39 #include "chrome/common/extensions/api/web_request.h"
40 #include "chrome/common/extensions/extension_constants.h"
41 #include "chrome/common/url_constants.h"
42 #include "content/public/browser/browser_message_filter.h"
43 #include "content/public/browser/browser_thread.h"
44 #include "content/public/browser/render_frame_host.h"
45 #include "content/public/browser/render_process_host.h"
46 #include "content/public/browser/resource_request_info.h"
47 #include "content/public/browser/user_metrics.h"
48 #include "extensions/browser/event_router.h"
49 #include "extensions/browser/extension_message_filter.h"
50 #include "extensions/browser/extension_prefs.h"
51 #include "extensions/browser/extension_registry.h"
52 #include "extensions/browser/extension_system.h"
53 #include "extensions/browser/info_map.h"
54 #include "extensions/browser/runtime_data.h"
55 #include "extensions/common/error_utils.h"
56 #include "extensions/common/event_filtering_info.h"
57 #include "extensions/common/extension.h"
58 #include "extensions/common/extension_messages.h"
59 #include "extensions/common/extension_set.h"
60 #include "extensions/common/features/feature.h"
61 #include "extensions/common/permissions/permissions_data.h"
62 #include "extensions/common/url_pattern.h"
63 #include "grit/generated_resources.h"
64 #include "net/base/auth.h"
65 #include "net/base/net_errors.h"
66 #include "net/base/upload_data_stream.h"
67 #include "net/http/http_response_headers.h"
68 #include "net/url_request/url_request.h"
69 #include "ui/base/l10n/l10n_util.h"
70 #include "url/gurl.h"
72 using base::DictionaryValue;
73 using base::ListValue;
74 using base::StringValue;
75 using content::BrowserMessageFilter;
76 using content::BrowserThread;
77 using content::ResourceRequestInfo;
78 using content::ResourceType;
79 using extensions::ErrorUtils;
80 using extensions::Extension;
81 using extensions::ExtensionWarning;
82 using extensions::ExtensionWarningService;
83 using extensions::ExtensionWarningSet;
84 using extensions::InfoMap;
85 using extensions::Feature;
86 using extensions::RulesRegistryService;
88 namespace helpers = extension_web_request_api_helpers;
89 namespace keys = extension_web_request_api_constants;
90 namespace web_request = extensions::api::web_request;
91 namespace declarative_keys = extensions::declarative_webrequest_constants;
92 namespace activitylog = activity_log_web_request_constants;
94 namespace {
96 const char kWebRequestEventPrefix[] = "webRequest.";
98 // List of all the webRequest events.
99 const char* const kWebRequestEvents[] = {
100 keys::kOnBeforeRedirectEvent,
101 web_request::OnBeforeRequest::kEventName,
102 keys::kOnBeforeSendHeadersEvent,
103 keys::kOnCompletedEvent,
104 web_request::OnErrorOccurred::kEventName,
105 keys::kOnSendHeadersEvent,
106 keys::kOnAuthRequiredEvent,
107 keys::kOnResponseStartedEvent,
108 keys::kOnHeadersReceivedEvent,
111 #define ARRAYEND(array) (array + arraysize(array))
113 const char* GetRequestStageAsString(
114 ExtensionWebRequestEventRouter::EventTypes type) {
115 switch (type) {
116 case ExtensionWebRequestEventRouter::kInvalidEvent:
117 return "Invalid";
118 case ExtensionWebRequestEventRouter::kOnBeforeRequest:
119 return keys::kOnBeforeRequest;
120 case ExtensionWebRequestEventRouter::kOnBeforeSendHeaders:
121 return keys::kOnBeforeSendHeaders;
122 case ExtensionWebRequestEventRouter::kOnSendHeaders:
123 return keys::kOnSendHeaders;
124 case ExtensionWebRequestEventRouter::kOnHeadersReceived:
125 return keys::kOnHeadersReceived;
126 case ExtensionWebRequestEventRouter::kOnBeforeRedirect:
127 return keys::kOnBeforeRedirect;
128 case ExtensionWebRequestEventRouter::kOnAuthRequired:
129 return keys::kOnAuthRequired;
130 case ExtensionWebRequestEventRouter::kOnResponseStarted:
131 return keys::kOnResponseStarted;
132 case ExtensionWebRequestEventRouter::kOnErrorOccurred:
133 return keys::kOnErrorOccurred;
134 case ExtensionWebRequestEventRouter::kOnCompleted:
135 return keys::kOnCompleted;
137 NOTREACHED();
138 return "Not reached";
141 // TODO(dcheng): Fix plumbing. Frame ID is not an int64--it's just an int.
142 int GetFrameId(bool is_main_frame, int64 frame_id) {
143 return is_main_frame ? 0 : static_cast<int>(frame_id);
146 bool IsWebRequestEvent(const std::string& event_name) {
147 std::string web_request_event_name(event_name);
148 if (StartsWithASCII(
149 web_request_event_name, webview::kWebViewEventPrefix, true)) {
150 web_request_event_name.replace(
151 0, strlen(webview::kWebViewEventPrefix), kWebRequestEventPrefix);
153 return std::find(kWebRequestEvents, ARRAYEND(kWebRequestEvents),
154 web_request_event_name) != ARRAYEND(kWebRequestEvents);
157 // Returns whether |request| has been triggered by an extension in
158 // |extension_info_map|.
159 bool IsRequestFromExtension(const net::URLRequest* request,
160 const InfoMap* extension_info_map) {
161 // |extension_info_map| is NULL for system-level requests.
162 if (!extension_info_map)
163 return false;
165 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
167 // If this request was not created by the ResourceDispatcher, |info| is NULL.
168 // All requests from extensions are created by the ResourceDispatcher.
169 if (!info)
170 return false;
172 return extension_info_map->process_map().Contains(info->GetChildID());
175 void ExtractRequestRoutingInfo(net::URLRequest* request,
176 int* render_process_host_id,
177 int* routing_id) {
178 if (!request->GetUserData(NULL))
179 return;
180 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
181 *render_process_host_id = info->GetChildID();
182 *routing_id = info->GetRouteID();
185 // Given a |request|, this function determines whether it originated from
186 // a <webview> guest process or not. If it is from a <webview> guest process,
187 // then |web_view_info| is returned with information about the instance ID
188 // that uniquely identifies the <webview> and its embedder.
189 bool GetWebViewInfo(net::URLRequest* request,
190 WebViewRendererState::WebViewInfo* web_view_info) {
191 int render_process_host_id = -1;
192 int routing_id = -1;
193 ExtractRequestRoutingInfo(request, &render_process_host_id, &routing_id);
194 return WebViewRendererState::GetInstance()->
195 GetInfo(render_process_host_id, routing_id, web_view_info);
198 void ExtractRequestInfoDetails(net::URLRequest* request,
199 bool* is_main_frame,
200 int64* frame_id,
201 bool* parent_is_main_frame,
202 int64* parent_frame_id,
203 int* tab_id,
204 int* window_id,
205 int* render_process_host_id,
206 int* routing_id,
207 ResourceType::Type* resource_type) {
208 if (!request->GetUserData(NULL))
209 return;
211 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
212 ExtensionRendererState::GetInstance()->GetTabAndWindowId(
213 info, tab_id, window_id);
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 = ResourceType::LAST_TYPE;
228 // Extracts from |request| information for the keys requestId, url, method,
229 // frameId, tabId, type, and timeStamp and writes these into |out| to be passed
230 // on to extensions.
231 void ExtractRequestInfo(net::URLRequest* request, base::DictionaryValue* out) {
232 bool is_main_frame = false;
233 int64 frame_id = -1;
234 bool parent_is_main_frame = false;
235 int64 parent_frame_id = -1;
236 int frame_id_for_extension = -1;
237 int parent_frame_id_for_extension = -1;
238 int tab_id = -1;
239 int window_id = -1;
240 int render_process_host_id = -1;
241 int routing_id = -1;
242 ResourceType::Type resource_type = ResourceType::LAST_TYPE;
243 ExtractRequestInfoDetails(request, &is_main_frame, &frame_id,
244 &parent_is_main_frame, &parent_frame_id, &tab_id,
245 &window_id, &render_process_host_id, &routing_id,
246 &resource_type);
247 frame_id_for_extension = GetFrameId(is_main_frame, frame_id);
248 parent_frame_id_for_extension = GetFrameId(parent_is_main_frame,
249 parent_frame_id);
251 out->SetString(keys::kRequestIdKey,
252 base::Uint64ToString(request->identifier()));
253 out->SetString(keys::kUrlKey, request->url().spec());
254 out->SetString(keys::kMethodKey, request->method());
255 out->SetInteger(keys::kFrameIdKey, frame_id_for_extension);
256 out->SetInteger(keys::kParentFrameIdKey, parent_frame_id_for_extension);
257 out->SetInteger(keys::kTabIdKey, tab_id);
258 out->SetString(keys::kTypeKey, helpers::ResourceTypeToString(resource_type));
259 out->SetDouble(keys::kTimeStampKey, base::Time::Now().ToDoubleT() * 1000);
262 // Extracts the body from |request| and writes the data into |out|.
263 void ExtractRequestInfoBody(const net::URLRequest* request,
264 base::DictionaryValue* out) {
265 const net::UploadDataStream* upload_data = request->get_upload();
266 if (!upload_data ||
267 (request->method() != "POST" && request->method() != "PUT"))
268 return; // Need to exit without "out->Set(keys::kRequestBodyKey, ...);" .
270 base::DictionaryValue* requestBody = new base::DictionaryValue();
271 out->Set(keys::kRequestBodyKey, requestBody);
273 // Get the data presenters, ordered by how specific they are.
274 extensions::ParsedDataPresenter parsed_data_presenter(*request);
275 extensions::RawDataPresenter raw_data_presenter;
276 extensions::UploadDataPresenter* const presenters[] = {
277 &parsed_data_presenter, // 1: any parseable forms? (Specific to forms.)
278 &raw_data_presenter // 2: any data at all? (Non-specific.)
280 // Keys for the results of the corresponding presenters.
281 static const char* const kKeys[] = {
282 keys::kRequestBodyFormDataKey,
283 keys::kRequestBodyRawKey
286 const ScopedVector<net::UploadElementReader>& readers =
287 upload_data->element_readers();
288 bool some_succeeded = false;
289 for (size_t i = 0; !some_succeeded && i < arraysize(presenters); ++i) {
290 ScopedVector<net::UploadElementReader>::const_iterator reader;
291 for (reader = readers.begin(); reader != readers.end(); ++reader)
292 presenters[i]->FeedNext(**reader);
293 if (presenters[i]->Succeeded()) {
294 requestBody->Set(kKeys[i], presenters[i]->Result().release());
295 some_succeeded = true;
298 if (!some_succeeded)
299 requestBody->SetString(keys::kRequestBodyErrorKey, "Unknown error.");
302 // Converts a HttpHeaders dictionary to a |name|, |value| pair. Returns
303 // true if successful.
304 bool FromHeaderDictionary(const base::DictionaryValue* header_value,
305 std::string* name,
306 std::string* value) {
307 if (!header_value->GetString(keys::kHeaderNameKey, name))
308 return false;
310 // We require either a "value" or a "binaryValue" entry.
311 if (!(header_value->HasKey(keys::kHeaderValueKey) ^
312 header_value->HasKey(keys::kHeaderBinaryValueKey)))
313 return false;
315 if (header_value->HasKey(keys::kHeaderValueKey)) {
316 if (!header_value->GetString(keys::kHeaderValueKey, value)) {
317 return false;
319 } else if (header_value->HasKey(keys::kHeaderBinaryValueKey)) {
320 const base::ListValue* list = NULL;
321 if (!header_value->HasKey(keys::kHeaderBinaryValueKey)) {
322 *value = "";
323 } else if (!header_value->GetList(keys::kHeaderBinaryValueKey, &list) ||
324 !helpers::CharListToString(list, value)) {
325 return false;
328 return true;
331 // Converts the |name|, |value| pair of a http header to a HttpHeaders
332 // dictionary. Ownership is passed to the caller.
333 base::DictionaryValue* ToHeaderDictionary(const std::string& name,
334 const std::string& value) {
335 base::DictionaryValue* header = new base::DictionaryValue();
336 header->SetString(keys::kHeaderNameKey, name);
337 if (base::IsStringUTF8(value)) {
338 header->SetString(keys::kHeaderValueKey, value);
339 } else {
340 header->Set(keys::kHeaderBinaryValueKey,
341 helpers::StringToCharList(value));
343 return header;
346 // Creates a list of HttpHeaders (see the extension API JSON). If |headers| is
347 // NULL, the list is empty. Ownership is passed to the caller.
348 base::ListValue* GetResponseHeadersList(
349 const net::HttpResponseHeaders* headers) {
350 base::ListValue* headers_value = new base::ListValue();
351 if (headers) {
352 void* iter = NULL;
353 std::string name;
354 std::string value;
355 while (headers->EnumerateHeaderLines(&iter, &name, &value))
356 headers_value->Append(ToHeaderDictionary(name, value));
358 return headers_value;
361 base::ListValue* GetRequestHeadersList(const net::HttpRequestHeaders& headers) {
362 base::ListValue* headers_value = new base::ListValue();
363 for (net::HttpRequestHeaders::Iterator it(headers); it.GetNext(); )
364 headers_value->Append(ToHeaderDictionary(it.name(), it.value()));
365 return headers_value;
368 // Creates a base::StringValue with the status line of |headers|. If |headers|
369 // is NULL, an empty string is returned. Ownership is passed to the caller.
370 base::StringValue* GetStatusLine(net::HttpResponseHeaders* headers) {
371 return new base::StringValue(
372 headers ? headers->GetStatusLine() : std::string());
375 void RemoveEventListenerOnUI(
376 void* profile_id,
377 const std::string& event_name,
378 int process_id,
379 const std::string& extension_id) {
380 DCHECK_CURRENTLY_ON(BrowserThread::UI);
382 Profile* profile = reinterpret_cast<Profile*>(profile_id);
383 if (!g_browser_process->profile_manager()->IsValidProfile(profile))
384 return;
386 extensions::EventRouter* event_router = extensions::EventRouter::Get(profile);
387 if (!event_router)
388 return;
390 content::RenderProcessHost* process =
391 content::RenderProcessHost::FromID(process_id);
392 if (!process)
393 return;
395 event_router->RemoveEventListener(event_name, process, extension_id);
398 // Sends an event to subscribers of chrome.declarativeWebRequest.onMessage or
399 // to subscribers of webview.onMessage if the action is being operated upon
400 // a <webview> guest renderer.
401 // |extension_id| identifies the extension that sends and receives the event.
402 // |is_web_view_guest| indicates whether the action is for a <webview>.
403 // |web_view_info| is a struct containing information about the <webview>
404 // embedder.
405 // |event_argument| is passed to the event listener.
406 void SendOnMessageEventOnUI(
407 void* profile_id,
408 const std::string& extension_id,
409 bool is_web_view_guest,
410 const WebViewRendererState::WebViewInfo& web_view_info,
411 scoped_ptr<base::DictionaryValue> event_argument) {
412 DCHECK_CURRENTLY_ON(BrowserThread::UI);
414 Profile* profile = reinterpret_cast<Profile*>(profile_id);
415 if (!g_browser_process->profile_manager()->IsValidProfile(profile))
416 return;
418 scoped_ptr<base::ListValue> event_args(new base::ListValue);
419 event_args->Append(event_argument.release());
421 extensions::EventRouter* event_router = extensions::EventRouter::Get(profile);
423 extensions::EventFilteringInfo event_filtering_info;
425 std::string event_name;
426 // The instance ID uniquely identifies a <webview> instance within an embedder
427 // process. We use a filter here so that only event listeners for a particular
428 // <webview> will fire.
429 if (is_web_view_guest) {
430 event_filtering_info.SetInstanceID(web_view_info.instance_id);
431 event_name = webview::kEventMessage;
432 } else {
433 event_name = declarative_keys::kOnMessage;
436 scoped_ptr<extensions::Event> event(new extensions::Event(
437 event_name,
438 event_args.Pass(), profile, GURL(),
439 extensions::EventRouter::USER_GESTURE_UNKNOWN,
440 event_filtering_info));
441 event_router->DispatchEventToExtension(extension_id, event.Pass());
444 void RemoveEventListenerOnIOThread(
445 content::BrowserContext* browser_context,
446 const std::string& extension_id,
447 const std::string& sub_event_name) {
448 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(
449 browser_context, extension_id, sub_event_name);
452 } // namespace
454 namespace extensions {
456 WebRequestAPI::WebRequestAPI(content::BrowserContext* context)
457 : browser_context_(context) {
458 EventRouter* event_router = EventRouter::Get(browser_context_);
459 for (size_t i = 0; i < arraysize(kWebRequestEvents); ++i) {
460 // Observe the webRequest event.
461 std::string event_name = kWebRequestEvents[i];
462 event_router->RegisterObserver(this, event_name);
464 // Also observe the corresponding webview event.
465 event_name.replace(
466 0, sizeof(kWebRequestEventPrefix) - 1, webview::kWebViewEventPrefix);
467 event_router->RegisterObserver(this, event_name);
471 WebRequestAPI::~WebRequestAPI() {
472 EventRouter::Get(browser_context_)->UnregisterObserver(this);
475 static base::LazyInstance<BrowserContextKeyedAPIFactory<WebRequestAPI> >
476 g_factory = LAZY_INSTANCE_INITIALIZER;
478 // static
479 BrowserContextKeyedAPIFactory<WebRequestAPI>*
480 WebRequestAPI::GetFactoryInstance() {
481 return g_factory.Pointer();
484 void WebRequestAPI::OnListenerRemoved(const EventListenerInfo& details) {
485 DCHECK_CURRENTLY_ON(BrowserThread::UI);
486 // Note that details.event_name includes the sub-event details (e.g. "/123").
487 BrowserThread::PostTask(BrowserThread::IO,
488 FROM_HERE,
489 base::Bind(&RemoveEventListenerOnIOThread,
490 details.browser_context,
491 details.extension_id,
492 details.event_name));
495 } // namespace extensions
497 // Represents a single unique listener to an event, along with whatever filter
498 // parameters and extra_info_spec were specified at the time the listener was
499 // added.
500 // NOTE(benjhayden) New APIs should not use this sub_event_name trick! It does
501 // not play well with event pages. See downloads.onDeterminingFilename and
502 // ExtensionDownloadsEventRouter for an alternative approach.
503 struct ExtensionWebRequestEventRouter::EventListener {
504 std::string extension_id;
505 std::string extension_name;
506 std::string sub_event_name;
507 RequestFilter filter;
508 int extra_info_spec;
509 int embedder_process_id;
510 int webview_instance_id;
511 base::WeakPtr<IPC::Sender> ipc_sender;
512 mutable std::set<uint64> blocked_requests;
514 // Comparator to work with std::set.
515 bool operator<(const EventListener& that) const {
516 if (extension_id < that.extension_id)
517 return true;
518 if (extension_id == that.extension_id &&
519 sub_event_name < that.sub_event_name)
520 return true;
521 return false;
524 EventListener() : extra_info_spec(0) {}
527 // Contains info about requests that are blocked waiting for a response from
528 // an extension.
529 struct ExtensionWebRequestEventRouter::BlockedRequest {
530 // The request that is being blocked.
531 net::URLRequest* request;
533 // Whether the request originates from an incognito tab.
534 bool is_incognito;
536 // The event that we're currently blocked on.
537 EventTypes event;
539 // The number of event handlers that we are awaiting a response from.
540 int num_handlers_blocking;
542 // Pointer to NetLog to report significant changes to the request for
543 // debugging.
544 const net::BoundNetLog* net_log;
546 // The callback to call when we get a response from all event handlers.
547 net::CompletionCallback callback;
549 // If non-empty, this contains the new URL that the request will redirect to.
550 // Only valid for OnBeforeRequest and OnHeadersReceived.
551 GURL* new_url;
553 // The request headers that will be issued along with this request. Only valid
554 // for OnBeforeSendHeaders.
555 net::HttpRequestHeaders* request_headers;
557 // The response headers that were received from the server. Only valid for
558 // OnHeadersReceived.
559 scoped_refptr<const net::HttpResponseHeaders> original_response_headers;
561 // Location where to override response headers. Only valid for
562 // OnHeadersReceived.
563 scoped_refptr<net::HttpResponseHeaders>* override_response_headers;
565 // If non-empty, this contains the auth credentials that may be filled in.
566 // Only valid for OnAuthRequired.
567 net::AuthCredentials* auth_credentials;
569 // The callback to invoke for auth. If |auth_callback.is_null()| is false,
570 // |callback| must be NULL.
571 // Only valid for OnAuthRequired.
572 net::NetworkDelegate::AuthCallback auth_callback;
574 // Time the request was paused. Used for logging purposes.
575 base::Time blocking_time;
577 // Changes requested by extensions.
578 helpers::EventResponseDeltas response_deltas;
580 // Provider of meta data about extensions, only used and non-NULL for events
581 // that are delayed until the rules registry is ready.
582 InfoMap* extension_info_map;
584 BlockedRequest()
585 : request(NULL),
586 is_incognito(false),
587 event(kInvalidEvent),
588 num_handlers_blocking(0),
589 net_log(NULL),
590 new_url(NULL),
591 request_headers(NULL),
592 override_response_headers(NULL),
593 auth_credentials(NULL),
594 extension_info_map(NULL) {}
597 bool ExtensionWebRequestEventRouter::RequestFilter::InitFromValue(
598 const base::DictionaryValue& value, std::string* error) {
599 if (!value.HasKey("urls"))
600 return false;
602 for (base::DictionaryValue::Iterator it(value); !it.IsAtEnd(); it.Advance()) {
603 if (it.key() == "urls") {
604 const base::ListValue* urls_value = NULL;
605 if (!it.value().GetAsList(&urls_value))
606 return false;
607 for (size_t i = 0; i < urls_value->GetSize(); ++i) {
608 std::string url;
609 URLPattern pattern(
610 URLPattern::SCHEME_HTTP | URLPattern::SCHEME_HTTPS |
611 URLPattern::SCHEME_FTP | URLPattern::SCHEME_FILE |
612 URLPattern::SCHEME_EXTENSION);
613 if (!urls_value->GetString(i, &url) ||
614 pattern.Parse(url) != URLPattern::PARSE_SUCCESS) {
615 *error = ErrorUtils::FormatErrorMessage(
616 keys::kInvalidRequestFilterUrl, url);
617 return false;
619 urls.AddPattern(pattern);
621 } else if (it.key() == "types") {
622 const base::ListValue* types_value = NULL;
623 if (!it.value().GetAsList(&types_value))
624 return false;
625 for (size_t i = 0; i < types_value->GetSize(); ++i) {
626 std::string type_str;
627 ResourceType::Type type;
628 if (!types_value->GetString(i, &type_str) ||
629 !helpers::ParseResourceType(type_str, &type))
630 return false;
631 types.push_back(type);
633 } else if (it.key() == "tabId") {
634 if (!it.value().GetAsInteger(&tab_id))
635 return false;
636 } else if (it.key() == "windowId") {
637 if (!it.value().GetAsInteger(&window_id))
638 return false;
639 } else {
640 return false;
643 return true;
646 // static
647 bool ExtensionWebRequestEventRouter::ExtraInfoSpec::InitFromValue(
648 const base::ListValue& value, int* extra_info_spec) {
649 *extra_info_spec = 0;
650 for (size_t i = 0; i < value.GetSize(); ++i) {
651 std::string str;
652 if (!value.GetString(i, &str))
653 return false;
655 if (str == "requestHeaders")
656 *extra_info_spec |= REQUEST_HEADERS;
657 else if (str == "responseHeaders")
658 *extra_info_spec |= RESPONSE_HEADERS;
659 else if (str == "blocking")
660 *extra_info_spec |= BLOCKING;
661 else if (str == "asyncBlocking")
662 *extra_info_spec |= ASYNC_BLOCKING;
663 else if (str == "requestBody")
664 *extra_info_spec |= REQUEST_BODY;
665 else
666 return false;
668 // BLOCKING and ASYNC_BLOCKING are mutually exclusive.
669 if ((*extra_info_spec & BLOCKING) && (*extra_info_spec & ASYNC_BLOCKING))
670 return false;
672 return true;
676 ExtensionWebRequestEventRouter::EventResponse::EventResponse(
677 const std::string& extension_id, const base::Time& extension_install_time)
678 : extension_id(extension_id),
679 extension_install_time(extension_install_time),
680 cancel(false) {
683 ExtensionWebRequestEventRouter::EventResponse::~EventResponse() {
687 ExtensionWebRequestEventRouter::RequestFilter::RequestFilter()
688 : tab_id(-1), window_id(-1) {
691 ExtensionWebRequestEventRouter::RequestFilter::~RequestFilter() {
695 // ExtensionWebRequestEventRouter
698 // static
699 ExtensionWebRequestEventRouter* ExtensionWebRequestEventRouter::GetInstance() {
700 return Singleton<ExtensionWebRequestEventRouter>::get();
703 ExtensionWebRequestEventRouter::ExtensionWebRequestEventRouter()
704 : request_time_tracker_(new ExtensionWebRequestTimeTracker) {
707 ExtensionWebRequestEventRouter::~ExtensionWebRequestEventRouter() {
710 void ExtensionWebRequestEventRouter::RegisterRulesRegistry(
711 void* profile,
712 const RulesRegistryService::WebViewKey& webview_key,
713 scoped_refptr<extensions::WebRequestRulesRegistry> rules_registry) {
714 RulesRegistryKey key(profile, webview_key);
715 if (rules_registry.get())
716 rules_registries_[key] = rules_registry;
717 else
718 rules_registries_.erase(key);
721 int ExtensionWebRequestEventRouter::OnBeforeRequest(
722 void* profile,
723 InfoMap* extension_info_map,
724 net::URLRequest* request,
725 const net::CompletionCallback& callback,
726 GURL* new_url) {
727 // We hide events from the system context as well as sensitive requests.
728 if (!profile ||
729 WebRequestPermissions::HideRequest(extension_info_map, request))
730 return net::OK;
732 if (IsPageLoad(request))
733 NotifyPageLoad();
735 request_time_tracker_->LogRequestStartTime(request->identifier(),
736 base::Time::Now(),
737 request->url(),
738 profile);
740 // Whether to initialized blocked_requests_.
741 bool initialize_blocked_requests = false;
743 initialize_blocked_requests |=
744 ProcessDeclarativeRules(profile, extension_info_map,
745 web_request::OnBeforeRequest::kEventName, request,
746 extensions::ON_BEFORE_REQUEST, NULL);
748 int extra_info_spec = 0;
749 std::vector<const EventListener*> listeners =
750 GetMatchingListeners(profile, extension_info_map,
751 web_request::OnBeforeRequest::kEventName, request,
752 &extra_info_spec);
753 if (!listeners.empty() &&
754 !GetAndSetSignaled(request->identifier(), kOnBeforeRequest)) {
755 base::ListValue args;
756 base::DictionaryValue* dict = new base::DictionaryValue();
757 ExtractRequestInfo(request, dict);
758 if (extra_info_spec & ExtraInfoSpec::REQUEST_BODY)
759 ExtractRequestInfoBody(request, dict);
760 args.Append(dict);
762 initialize_blocked_requests |=
763 DispatchEvent(profile, request, listeners, args);
766 if (!initialize_blocked_requests)
767 return net::OK; // Nobody saw a reason for modifying the request.
769 blocked_requests_[request->identifier()].event = kOnBeforeRequest;
770 blocked_requests_[request->identifier()].is_incognito |=
771 IsIncognitoProfile(profile);
772 blocked_requests_[request->identifier()].request = request;
773 blocked_requests_[request->identifier()].callback = callback;
774 blocked_requests_[request->identifier()].new_url = new_url;
775 blocked_requests_[request->identifier()].net_log = &request->net_log();
777 if (blocked_requests_[request->identifier()].num_handlers_blocking == 0) {
778 // If there are no blocking handlers, only the declarative rules tried
779 // to modify the request and we can respond synchronously.
780 return ExecuteDeltas(profile, request->identifier(),
781 false /* call_callback*/);
782 } else {
783 return net::ERR_IO_PENDING;
787 int ExtensionWebRequestEventRouter::OnBeforeSendHeaders(
788 void* profile,
789 InfoMap* extension_info_map,
790 net::URLRequest* request,
791 const net::CompletionCallback& callback,
792 net::HttpRequestHeaders* headers) {
793 // We hide events from the system context as well as sensitive requests.
794 if (!profile ||
795 WebRequestPermissions::HideRequest(extension_info_map, request))
796 return net::OK;
798 bool initialize_blocked_requests = false;
800 initialize_blocked_requests |=
801 ProcessDeclarativeRules(profile, extension_info_map,
802 keys::kOnBeforeSendHeadersEvent, request,
803 extensions::ON_BEFORE_SEND_HEADERS, NULL);
805 int extra_info_spec = 0;
806 std::vector<const EventListener*> listeners =
807 GetMatchingListeners(profile, extension_info_map,
808 keys::kOnBeforeSendHeadersEvent, request,
809 &extra_info_spec);
810 if (!listeners.empty() &&
811 !GetAndSetSignaled(request->identifier(), kOnBeforeSendHeaders)) {
812 base::ListValue args;
813 base::DictionaryValue* dict = new base::DictionaryValue();
814 ExtractRequestInfo(request, dict);
815 if (extra_info_spec & ExtraInfoSpec::REQUEST_HEADERS)
816 dict->Set(keys::kRequestHeadersKey, GetRequestHeadersList(*headers));
817 args.Append(dict);
819 initialize_blocked_requests |=
820 DispatchEvent(profile, request, listeners, args);
823 if (!initialize_blocked_requests)
824 return net::OK; // Nobody saw a reason for modifying the request.
826 blocked_requests_[request->identifier()].event = kOnBeforeSendHeaders;
827 blocked_requests_[request->identifier()].is_incognito |=
828 IsIncognitoProfile(profile);
829 blocked_requests_[request->identifier()].request = request;
830 blocked_requests_[request->identifier()].callback = callback;
831 blocked_requests_[request->identifier()].request_headers = headers;
832 blocked_requests_[request->identifier()].net_log = &request->net_log();
834 if (blocked_requests_[request->identifier()].num_handlers_blocking == 0) {
835 // If there are no blocking handlers, only the declarative rules tried
836 // to modify the request and we can respond synchronously.
837 return ExecuteDeltas(profile, request->identifier(),
838 false /* call_callback*/);
839 } else {
840 return net::ERR_IO_PENDING;
844 void ExtensionWebRequestEventRouter::OnSendHeaders(
845 void* profile,
846 InfoMap* extension_info_map,
847 net::URLRequest* request,
848 const net::HttpRequestHeaders& headers) {
849 // We hide events from the system context as well as sensitive requests.
850 if (!profile ||
851 WebRequestPermissions::HideRequest(extension_info_map, request))
852 return;
854 if (GetAndSetSignaled(request->identifier(), kOnSendHeaders))
855 return;
857 ClearSignaled(request->identifier(), kOnBeforeRedirect);
859 int extra_info_spec = 0;
860 std::vector<const EventListener*> listeners =
861 GetMatchingListeners(profile, extension_info_map,
862 keys::kOnSendHeadersEvent, request,
863 &extra_info_spec);
864 if (listeners.empty())
865 return;
867 base::ListValue args;
868 base::DictionaryValue* dict = new base::DictionaryValue();
869 ExtractRequestInfo(request, dict);
870 if (extra_info_spec & ExtraInfoSpec::REQUEST_HEADERS)
871 dict->Set(keys::kRequestHeadersKey, GetRequestHeadersList(headers));
872 args.Append(dict);
874 DispatchEvent(profile, request, listeners, args);
877 int ExtensionWebRequestEventRouter::OnHeadersReceived(
878 void* profile,
879 InfoMap* extension_info_map,
880 net::URLRequest* request,
881 const net::CompletionCallback& callback,
882 const net::HttpResponseHeaders* original_response_headers,
883 scoped_refptr<net::HttpResponseHeaders>* override_response_headers,
884 GURL* allowed_unsafe_redirect_url) {
885 // We hide events from the system context as well as sensitive requests.
886 if (!profile ||
887 WebRequestPermissions::HideRequest(extension_info_map, request))
888 return net::OK;
890 bool initialize_blocked_requests = false;
892 initialize_blocked_requests |=
893 ProcessDeclarativeRules(profile, extension_info_map,
894 keys::kOnHeadersReceivedEvent, request,
895 extensions::ON_HEADERS_RECEIVED,
896 original_response_headers);
898 int extra_info_spec = 0;
899 std::vector<const EventListener*> listeners =
900 GetMatchingListeners(profile, extension_info_map,
901 keys::kOnHeadersReceivedEvent, request,
902 &extra_info_spec);
904 if (!listeners.empty() &&
905 !GetAndSetSignaled(request->identifier(), kOnHeadersReceived)) {
906 base::ListValue args;
907 base::DictionaryValue* dict = new base::DictionaryValue();
908 ExtractRequestInfo(request, dict);
909 dict->SetString(keys::kStatusLineKey,
910 original_response_headers->GetStatusLine());
911 if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
912 dict->Set(keys::kResponseHeadersKey,
913 GetResponseHeadersList(original_response_headers));
915 args.Append(dict);
917 initialize_blocked_requests |=
918 DispatchEvent(profile, request, listeners, args);
921 if (!initialize_blocked_requests)
922 return net::OK; // Nobody saw a reason for modifying the request.
924 blocked_requests_[request->identifier()].event = kOnHeadersReceived;
925 blocked_requests_[request->identifier()].is_incognito |=
926 IsIncognitoProfile(profile);
927 blocked_requests_[request->identifier()].request = request;
928 blocked_requests_[request->identifier()].callback = callback;
929 blocked_requests_[request->identifier()].net_log = &request->net_log();
930 blocked_requests_[request->identifier()].override_response_headers =
931 override_response_headers;
932 blocked_requests_[request->identifier()].original_response_headers =
933 original_response_headers;
934 blocked_requests_[request->identifier()].new_url =
935 allowed_unsafe_redirect_url;
937 if (blocked_requests_[request->identifier()].num_handlers_blocking == 0) {
938 // If there are no blocking handlers, only the declarative rules tried
939 // to modify the request and we can respond synchronously.
940 return ExecuteDeltas(profile, request->identifier(),
941 false /* call_callback*/);
942 } else {
943 return net::ERR_IO_PENDING;
947 net::NetworkDelegate::AuthRequiredResponse
948 ExtensionWebRequestEventRouter::OnAuthRequired(
949 void* profile,
950 InfoMap* extension_info_map,
951 net::URLRequest* request,
952 const net::AuthChallengeInfo& auth_info,
953 const net::NetworkDelegate::AuthCallback& callback,
954 net::AuthCredentials* credentials) {
955 // No profile means that this is for authentication challenges in the
956 // system context. Skip in that case. Also skip sensitive requests.
957 if (!profile ||
958 WebRequestPermissions::HideRequest(extension_info_map, request))
959 return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION;
961 int extra_info_spec = 0;
962 std::vector<const EventListener*> listeners =
963 GetMatchingListeners(profile, extension_info_map,
964 keys::kOnAuthRequiredEvent, request,
965 &extra_info_spec);
966 if (listeners.empty())
967 return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION;
969 base::ListValue args;
970 base::DictionaryValue* dict = new base::DictionaryValue();
971 ExtractRequestInfo(request, dict);
972 dict->SetBoolean(keys::kIsProxyKey, auth_info.is_proxy);
973 if (!auth_info.scheme.empty())
974 dict->SetString(keys::kSchemeKey, auth_info.scheme);
975 if (!auth_info.realm.empty())
976 dict->SetString(keys::kRealmKey, auth_info.realm);
977 base::DictionaryValue* challenger = new base::DictionaryValue();
978 challenger->SetString(keys::kHostKey, auth_info.challenger.host());
979 challenger->SetInteger(keys::kPortKey, auth_info.challenger.port());
980 dict->Set(keys::kChallengerKey, challenger);
981 dict->Set(keys::kStatusLineKey, GetStatusLine(request->response_headers()));
982 if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
983 dict->Set(keys::kResponseHeadersKey,
984 GetResponseHeadersList(request->response_headers()));
986 args.Append(dict);
988 if (DispatchEvent(profile, request, listeners, args)) {
989 blocked_requests_[request->identifier()].event = kOnAuthRequired;
990 blocked_requests_[request->identifier()].is_incognito |=
991 IsIncognitoProfile(profile);
992 blocked_requests_[request->identifier()].request = request;
993 blocked_requests_[request->identifier()].auth_callback = callback;
994 blocked_requests_[request->identifier()].auth_credentials = credentials;
995 blocked_requests_[request->identifier()].net_log = &request->net_log();
996 return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_IO_PENDING;
998 return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION;
1001 void ExtensionWebRequestEventRouter::OnBeforeRedirect(
1002 void* profile,
1003 InfoMap* extension_info_map,
1004 net::URLRequest* request,
1005 const GURL& new_location) {
1006 // We hide events from the system context as well as sensitive requests.
1007 if (!profile ||
1008 WebRequestPermissions::HideRequest(extension_info_map, request))
1009 return;
1011 if (GetAndSetSignaled(request->identifier(), kOnBeforeRedirect))
1012 return;
1014 ClearSignaled(request->identifier(), kOnBeforeRequest);
1015 ClearSignaled(request->identifier(), kOnBeforeSendHeaders);
1016 ClearSignaled(request->identifier(), kOnSendHeaders);
1017 ClearSignaled(request->identifier(), kOnHeadersReceived);
1019 int extra_info_spec = 0;
1020 std::vector<const EventListener*> listeners =
1021 GetMatchingListeners(profile, extension_info_map,
1022 keys::kOnBeforeRedirectEvent, request,
1023 &extra_info_spec);
1024 if (listeners.empty())
1025 return;
1027 int http_status_code = request->GetResponseCode();
1029 std::string response_ip = request->GetSocketAddress().host();
1031 base::ListValue args;
1032 base::DictionaryValue* dict = new base::DictionaryValue();
1033 ExtractRequestInfo(request, dict);
1034 dict->SetString(keys::kRedirectUrlKey, new_location.spec());
1035 dict->SetInteger(keys::kStatusCodeKey, http_status_code);
1036 if (!response_ip.empty())
1037 dict->SetString(keys::kIpKey, response_ip);
1038 dict->SetBoolean(keys::kFromCache, request->was_cached());
1039 dict->Set(keys::kStatusLineKey, GetStatusLine(request->response_headers()));
1040 if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
1041 dict->Set(keys::kResponseHeadersKey,
1042 GetResponseHeadersList(request->response_headers()));
1044 args.Append(dict);
1046 DispatchEvent(profile, request, listeners, args);
1049 void ExtensionWebRequestEventRouter::OnResponseStarted(
1050 void* profile,
1051 InfoMap* extension_info_map,
1052 net::URLRequest* request) {
1053 // We hide events from the system context as well as sensitive requests.
1054 if (!profile ||
1055 WebRequestPermissions::HideRequest(extension_info_map, request))
1056 return;
1058 // OnResponseStarted is even triggered, when the request was cancelled.
1059 if (request->status().status() != net::URLRequestStatus::SUCCESS)
1060 return;
1062 int extra_info_spec = 0;
1063 std::vector<const EventListener*> listeners =
1064 GetMatchingListeners(profile, extension_info_map,
1065 keys::kOnResponseStartedEvent, request,
1066 &extra_info_spec);
1067 if (listeners.empty())
1068 return;
1070 // UrlRequestFileJobs do not send headers, so we simulate their behavior.
1071 int response_code = 200;
1072 if (request->response_headers())
1073 response_code = request->response_headers()->response_code();
1075 std::string response_ip = request->GetSocketAddress().host();
1077 base::ListValue args;
1078 base::DictionaryValue* dict = new base::DictionaryValue();
1079 ExtractRequestInfo(request, dict);
1080 if (!response_ip.empty())
1081 dict->SetString(keys::kIpKey, response_ip);
1082 dict->SetBoolean(keys::kFromCache, request->was_cached());
1083 dict->SetInteger(keys::kStatusCodeKey, response_code);
1084 dict->Set(keys::kStatusLineKey, GetStatusLine(request->response_headers()));
1085 if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
1086 dict->Set(keys::kResponseHeadersKey,
1087 GetResponseHeadersList(request->response_headers()));
1089 args.Append(dict);
1091 DispatchEvent(profile, request, listeners, args);
1094 void ExtensionWebRequestEventRouter::OnCompleted(void* profile,
1095 InfoMap* extension_info_map,
1096 net::URLRequest* request) {
1097 // We hide events from the system context as well as sensitive requests.
1098 // However, if the request first became sensitive after redirecting we have
1099 // already signaled it and thus we have to signal the end of it. This is
1100 // risk-free because the handler cannot modify the request now.
1101 if (!profile ||
1102 (WebRequestPermissions::HideRequest(extension_info_map, request) &&
1103 !WasSignaled(*request)))
1104 return;
1106 request_time_tracker_->LogRequestEndTime(request->identifier(),
1107 base::Time::Now());
1109 DCHECK(request->status().status() == net::URLRequestStatus::SUCCESS);
1111 DCHECK(!GetAndSetSignaled(request->identifier(), kOnCompleted));
1113 ClearPendingCallbacks(request);
1115 int extra_info_spec = 0;
1116 std::vector<const EventListener*> listeners =
1117 GetMatchingListeners(profile, extension_info_map,
1118 keys::kOnCompletedEvent, request, &extra_info_spec);
1119 if (listeners.empty())
1120 return;
1122 // UrlRequestFileJobs do not send headers, so we simulate their behavior.
1123 int response_code = 200;
1124 if (request->response_headers())
1125 response_code = request->response_headers()->response_code();
1127 std::string response_ip = request->GetSocketAddress().host();
1129 base::ListValue args;
1130 base::DictionaryValue* dict = new base::DictionaryValue();
1131 ExtractRequestInfo(request, dict);
1132 dict->SetInteger(keys::kStatusCodeKey, response_code);
1133 if (!response_ip.empty())
1134 dict->SetString(keys::kIpKey, response_ip);
1135 dict->SetBoolean(keys::kFromCache, request->was_cached());
1136 dict->Set(keys::kStatusLineKey, GetStatusLine(request->response_headers()));
1137 if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
1138 dict->Set(keys::kResponseHeadersKey,
1139 GetResponseHeadersList(request->response_headers()));
1141 args.Append(dict);
1143 DispatchEvent(profile, request, listeners, args);
1146 void ExtensionWebRequestEventRouter::OnErrorOccurred(
1147 void* profile,
1148 InfoMap* extension_info_map,
1149 net::URLRequest* request,
1150 bool started) {
1151 // We hide events from the system context as well as sensitive requests.
1152 // However, if the request first became sensitive after redirecting we have
1153 // already signaled it and thus we have to signal the end of it. This is
1154 // risk-free because the handler cannot modify the request now.
1155 if (!profile ||
1156 (WebRequestPermissions::HideRequest(extension_info_map, request) &&
1157 !WasSignaled(*request)))
1158 return;
1160 request_time_tracker_->LogRequestEndTime(request->identifier(),
1161 base::Time::Now());
1163 DCHECK(request->status().status() == net::URLRequestStatus::FAILED ||
1164 request->status().status() == net::URLRequestStatus::CANCELED);
1166 DCHECK(!GetAndSetSignaled(request->identifier(), kOnErrorOccurred));
1168 ClearPendingCallbacks(request);
1170 int extra_info_spec = 0;
1171 std::vector<const EventListener*> listeners =
1172 GetMatchingListeners(profile, extension_info_map,
1173 web_request::OnErrorOccurred::kEventName, request,
1174 &extra_info_spec);
1175 if (listeners.empty())
1176 return;
1178 base::ListValue args;
1179 base::DictionaryValue* dict = new base::DictionaryValue();
1180 ExtractRequestInfo(request, dict);
1181 if (started) {
1182 std::string response_ip = request->GetSocketAddress().host();
1183 if (!response_ip.empty())
1184 dict->SetString(keys::kIpKey, response_ip);
1186 dict->SetBoolean(keys::kFromCache, request->was_cached());
1187 dict->SetString(keys::kErrorKey,
1188 net::ErrorToString(request->status().error()));
1189 args.Append(dict);
1191 DispatchEvent(profile, request, listeners, args);
1194 void ExtensionWebRequestEventRouter::OnURLRequestDestroyed(
1195 void* profile, net::URLRequest* request) {
1196 ClearPendingCallbacks(request);
1198 signaled_requests_.erase(request->identifier());
1200 request_time_tracker_->LogRequestEndTime(request->identifier(),
1201 base::Time::Now());
1204 void ExtensionWebRequestEventRouter::ClearPendingCallbacks(
1205 net::URLRequest* request) {
1206 blocked_requests_.erase(request->identifier());
1209 bool ExtensionWebRequestEventRouter::DispatchEvent(
1210 void* profile_id,
1211 net::URLRequest* request,
1212 const std::vector<const EventListener*>& listeners,
1213 const base::ListValue& args) {
1214 // TODO(mpcomplete): Consider consolidating common (extension_id,json_args)
1215 // pairs into a single message sent to a list of sub_event_names.
1216 int num_handlers_blocking = 0;
1217 for (std::vector<const EventListener*>::const_iterator it = listeners.begin();
1218 it != listeners.end(); ++it) {
1219 // Filter out the optional keys that this listener didn't request.
1220 scoped_ptr<base::ListValue> args_filtered(args.DeepCopy());
1221 base::DictionaryValue* dict = NULL;
1222 CHECK(args_filtered->GetDictionary(0, &dict) && dict);
1223 if (!((*it)->extra_info_spec & ExtraInfoSpec::REQUEST_HEADERS))
1224 dict->Remove(keys::kRequestHeadersKey, NULL);
1225 if (!((*it)->extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS))
1226 dict->Remove(keys::kResponseHeadersKey, NULL);
1228 extensions::EventRouter::DispatchEvent(
1229 (*it)->ipc_sender.get(), profile_id,
1230 (*it)->extension_id, (*it)->sub_event_name,
1231 args_filtered.Pass(),
1232 extensions::EventRouter::USER_GESTURE_UNKNOWN,
1233 extensions::EventFilteringInfo());
1234 if ((*it)->extra_info_spec &
1235 (ExtraInfoSpec::BLOCKING | ExtraInfoSpec::ASYNC_BLOCKING)) {
1236 (*it)->blocked_requests.insert(request->identifier());
1237 // If this is the first delegate blocking the request, go ahead and log
1238 // it.
1239 if (num_handlers_blocking == 0) {
1240 std::string delegate_info =
1241 l10n_util::GetStringFUTF8(IDS_LOAD_STATE_PARAMETER_EXTENSION,
1242 base::UTF8ToUTF16((*it)->extension_name));
1243 // LobAndReport allows extensions that block requests to be displayed in
1244 // the load status bar.
1245 request->LogAndReportBlockedBy(delegate_info.c_str());
1247 ++num_handlers_blocking;
1251 if (num_handlers_blocking > 0) {
1252 blocked_requests_[request->identifier()].request = request;
1253 blocked_requests_[request->identifier()].is_incognito |=
1254 IsIncognitoProfile(profile_id);
1255 blocked_requests_[request->identifier()].num_handlers_blocking +=
1256 num_handlers_blocking;
1257 blocked_requests_[request->identifier()].blocking_time = base::Time::Now();
1259 return true;
1262 return false;
1265 void ExtensionWebRequestEventRouter::OnEventHandled(
1266 void* profile,
1267 const std::string& extension_id,
1268 const std::string& event_name,
1269 const std::string& sub_event_name,
1270 uint64 request_id,
1271 EventResponse* response) {
1272 EventListener listener;
1273 listener.extension_id = extension_id;
1274 listener.sub_event_name = sub_event_name;
1276 // The listener may have been removed (e.g. due to the process going away)
1277 // before we got here.
1278 std::set<EventListener>::iterator found =
1279 listeners_[profile][event_name].find(listener);
1280 if (found != listeners_[profile][event_name].end())
1281 found->blocked_requests.erase(request_id);
1283 DecrementBlockCount(profile, extension_id, event_name, request_id, response);
1286 bool ExtensionWebRequestEventRouter::AddEventListener(
1287 void* profile,
1288 const std::string& extension_id,
1289 const std::string& extension_name,
1290 const std::string& event_name,
1291 const std::string& sub_event_name,
1292 const RequestFilter& filter,
1293 int extra_info_spec,
1294 int embedder_process_id,
1295 int webview_instance_id,
1296 base::WeakPtr<IPC::Sender> ipc_sender) {
1297 if (!IsWebRequestEvent(event_name))
1298 return false;
1300 EventListener listener;
1301 listener.extension_id = extension_id;
1302 listener.extension_name = extension_name;
1303 listener.sub_event_name = sub_event_name;
1304 listener.filter = filter;
1305 listener.extra_info_spec = extra_info_spec;
1306 listener.ipc_sender = ipc_sender;
1307 listener.embedder_process_id = embedder_process_id;
1308 listener.webview_instance_id = webview_instance_id;
1309 if (listener.webview_instance_id) {
1310 content::RecordAction(
1311 base::UserMetricsAction("WebView.WebRequest.AddListener"));
1314 if (listeners_[profile][event_name].count(listener) != 0u) {
1315 // This is likely an abuse of the API by a malicious extension.
1316 return false;
1318 listeners_[profile][event_name].insert(listener);
1319 return true;
1322 void ExtensionWebRequestEventRouter::RemoveEventListener(
1323 void* profile,
1324 const std::string& extension_id,
1325 const std::string& sub_event_name) {
1326 std::string event_name =
1327 extensions::EventRouter::GetBaseEventName(sub_event_name);
1328 DCHECK(IsWebRequestEvent(event_name));
1330 EventListener listener;
1331 listener.extension_id = extension_id;
1332 listener.sub_event_name = sub_event_name;
1334 // It's possible for AddEventListener to fail asynchronously. In that case,
1335 // the renderer believes the listener exists, while the browser does not.
1336 // Ignore a RemoveEventListener in that case.
1337 std::set<EventListener>::iterator found =
1338 listeners_[profile][event_name].find(listener);
1339 if (found == listeners_[profile][event_name].end())
1340 return;
1342 CHECK_EQ(listeners_[profile][event_name].count(listener), 1u) <<
1343 "extension=" << extension_id << " event=" << event_name;
1345 // Unblock any request that this event listener may have been blocking.
1346 for (std::set<uint64>::iterator it = found->blocked_requests.begin();
1347 it != found->blocked_requests.end(); ++it) {
1348 DecrementBlockCount(profile, extension_id, event_name, *it, NULL);
1351 listeners_[profile][event_name].erase(listener);
1353 helpers::ClearCacheOnNavigation();
1356 void ExtensionWebRequestEventRouter::RemoveWebViewEventListeners(
1357 void* profile,
1358 const std::string& extension_id,
1359 int embedder_process_id,
1360 int webview_instance_id) {
1361 // Iterate over all listeners of all WebRequest events to delete
1362 // any listeners that belong to the provided <webview>.
1363 ListenerMapForProfile& map_for_profile = listeners_[profile];
1364 for (ListenerMapForProfile::iterator event_iter = map_for_profile.begin();
1365 event_iter != map_for_profile.end(); ++event_iter) {
1366 std::vector<EventListener> listeners_to_delete;
1367 std::set<EventListener>& listeners = event_iter->second;
1368 for (std::set<EventListener>::iterator listener_iter = listeners.begin();
1369 listener_iter != listeners.end(); ++listener_iter) {
1370 const EventListener& listener = *listener_iter;
1371 if (listener.embedder_process_id == embedder_process_id &&
1372 listener.webview_instance_id == webview_instance_id)
1373 listeners_to_delete.push_back(listener);
1375 for (size_t i = 0; i < listeners_to_delete.size(); ++i) {
1376 EventListener& listener = listeners_to_delete[i];
1377 content::BrowserThread::PostTask(
1378 content::BrowserThread::UI,
1379 FROM_HERE,
1380 base::Bind(&RemoveEventListenerOnUI,
1381 profile,
1382 listener.sub_event_name,
1383 embedder_process_id,
1384 extension_id));
1389 void ExtensionWebRequestEventRouter::OnOTRProfileCreated(
1390 void* original_profile, void* otr_profile) {
1391 cross_profile_map_[original_profile] = std::make_pair(false, otr_profile);
1392 cross_profile_map_[otr_profile] = std::make_pair(true, original_profile);
1395 void ExtensionWebRequestEventRouter::OnOTRProfileDestroyed(
1396 void* original_profile, void* otr_profile) {
1397 cross_profile_map_.erase(otr_profile);
1398 cross_profile_map_.erase(original_profile);
1401 void ExtensionWebRequestEventRouter::AddCallbackForPageLoad(
1402 const base::Closure& callback) {
1403 callbacks_for_page_load_.push_back(callback);
1406 bool ExtensionWebRequestEventRouter::IsPageLoad(
1407 net::URLRequest* request) const {
1408 bool is_main_frame = false;
1409 int64 frame_id = -1;
1410 bool parent_is_main_frame = false;
1411 int64 parent_frame_id = -1;
1412 int tab_id = -1;
1413 int window_id = -1;
1414 int render_process_host_id = -1;
1415 int routing_id = -1;
1416 ResourceType::Type resource_type = ResourceType::LAST_TYPE;
1418 ExtractRequestInfoDetails(request, &is_main_frame, &frame_id,
1419 &parent_is_main_frame, &parent_frame_id,
1420 &tab_id, &window_id, &render_process_host_id,
1421 &routing_id, &resource_type);
1423 return resource_type == ResourceType::MAIN_FRAME;
1426 void ExtensionWebRequestEventRouter::NotifyPageLoad() {
1427 for (CallbacksForPageLoad::const_iterator i =
1428 callbacks_for_page_load_.begin();
1429 i != callbacks_for_page_load_.end(); ++i) {
1430 i->Run();
1432 callbacks_for_page_load_.clear();
1435 void* ExtensionWebRequestEventRouter::GetCrossProfile(void* profile) const {
1436 CrossProfileMap::const_iterator cross_profile =
1437 cross_profile_map_.find(profile);
1438 if (cross_profile == cross_profile_map_.end())
1439 return NULL;
1440 return cross_profile->second.second;
1443 bool ExtensionWebRequestEventRouter::IsIncognitoProfile(void* profile) const {
1444 CrossProfileMap::const_iterator cross_profile =
1445 cross_profile_map_.find(profile);
1446 if (cross_profile == cross_profile_map_.end())
1447 return false;
1448 return cross_profile->second.first;
1451 bool ExtensionWebRequestEventRouter::WasSignaled(
1452 const net::URLRequest& request) const {
1453 SignaledRequestMap::const_iterator flag =
1454 signaled_requests_.find(request.identifier());
1455 return (flag != signaled_requests_.end()) && (flag->second != 0);
1458 void ExtensionWebRequestEventRouter::GetMatchingListenersImpl(
1459 void* profile,
1460 InfoMap* extension_info_map,
1461 bool crosses_incognito,
1462 const std::string& event_name,
1463 const GURL& url,
1464 int tab_id,
1465 int window_id,
1466 int render_process_host_id,
1467 int routing_id,
1468 ResourceType::Type resource_type,
1469 bool is_async_request,
1470 bool is_request_from_extension,
1471 int* extra_info_spec,
1472 std::vector<const ExtensionWebRequestEventRouter::EventListener*>*
1473 matching_listeners) {
1474 std::string web_request_event_name(event_name);
1475 WebViewRendererState::WebViewInfo web_view_info;
1476 bool is_web_view_guest = WebViewRendererState::GetInstance()->
1477 GetInfo(render_process_host_id, routing_id, &web_view_info);
1478 if (is_web_view_guest) {
1479 web_request_event_name.replace(
1480 0, sizeof(kWebRequestEventPrefix) - 1, webview::kWebViewEventPrefix);
1483 std::set<EventListener>& listeners =
1484 listeners_[profile][web_request_event_name];
1485 for (std::set<EventListener>::iterator it = listeners.begin();
1486 it != listeners.end(); ++it) {
1487 if (!it->ipc_sender.get()) {
1488 // The IPC sender has been deleted. This listener will be removed soon
1489 // via a call to RemoveEventListener. For now, just skip it.
1490 continue;
1493 if (is_web_view_guest &&
1494 (it->embedder_process_id != web_view_info.embedder_process_id ||
1495 it->webview_instance_id != web_view_info.instance_id))
1496 continue;
1498 if (!it->filter.urls.is_empty() && !it->filter.urls.MatchesURL(url))
1499 continue;
1500 if (it->filter.tab_id != -1 && tab_id != it->filter.tab_id)
1501 continue;
1502 if (it->filter.window_id != -1 && window_id != it->filter.window_id)
1503 continue;
1504 if (!it->filter.types.empty() &&
1505 std::find(it->filter.types.begin(), it->filter.types.end(),
1506 resource_type) == it->filter.types.end())
1507 continue;
1509 if (!is_web_view_guest && !WebRequestPermissions::CanExtensionAccessURL(
1510 extension_info_map, it->extension_id, url, crosses_incognito,
1511 WebRequestPermissions::REQUIRE_HOST_PERMISSION))
1512 continue;
1514 bool blocking_listener =
1515 (it->extra_info_spec &
1516 (ExtraInfoSpec::BLOCKING | ExtraInfoSpec::ASYNC_BLOCKING)) != 0;
1518 // We do not want to notify extensions about XHR requests that are
1519 // triggered by themselves. This is a workaround to prevent deadlocks
1520 // in case of synchronous XHR requests that block the extension renderer
1521 // and therefore prevent the extension from processing the request
1522 // handler. This is only a problem for blocking listeners.
1523 // http://crbug.com/105656
1524 bool synchronous_xhr_from_extension = !is_async_request &&
1525 is_request_from_extension && resource_type == ResourceType::XHR;
1527 // Only send webRequest events for URLs the extension has access to.
1528 if (blocking_listener && synchronous_xhr_from_extension)
1529 continue;
1531 matching_listeners->push_back(&(*it));
1532 *extra_info_spec |= it->extra_info_spec;
1536 std::vector<const ExtensionWebRequestEventRouter::EventListener*>
1537 ExtensionWebRequestEventRouter::GetMatchingListeners(
1538 void* profile,
1539 InfoMap* extension_info_map,
1540 const std::string& event_name,
1541 net::URLRequest* request,
1542 int* extra_info_spec) {
1543 // TODO(mpcomplete): handle profile == NULL (should collect all listeners).
1544 *extra_info_spec = 0;
1546 bool is_main_frame = false;
1547 int64 frame_id = -1;
1548 bool parent_is_main_frame = false;
1549 int64 parent_frame_id = -1;
1550 int tab_id = -1;
1551 int window_id = -1;
1552 int render_process_host_id = -1;
1553 int routing_id = -1;
1554 ResourceType::Type resource_type = ResourceType::LAST_TYPE;
1555 const GURL& url = request->url();
1557 ExtractRequestInfoDetails(request, &is_main_frame, &frame_id,
1558 &parent_is_main_frame, &parent_frame_id,
1559 &tab_id, &window_id, &render_process_host_id,
1560 &routing_id, &resource_type);
1562 std::vector<const ExtensionWebRequestEventRouter::EventListener*>
1563 matching_listeners;
1565 bool is_request_from_extension =
1566 IsRequestFromExtension(request, extension_info_map);
1568 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
1569 // We are conservative here and assume requests are asynchronous in case
1570 // we don't have an info object. We don't want to risk a deadlock.
1571 bool is_async_request = !info || info->IsAsync();
1573 GetMatchingListenersImpl(
1574 profile, extension_info_map, false, event_name, url,
1575 tab_id, window_id, render_process_host_id, routing_id, resource_type,
1576 is_async_request, is_request_from_extension, extra_info_spec,
1577 &matching_listeners);
1578 void* cross_profile = GetCrossProfile(profile);
1579 if (cross_profile) {
1580 GetMatchingListenersImpl(
1581 cross_profile, extension_info_map, true, event_name, url, tab_id,
1582 window_id, render_process_host_id, routing_id, resource_type,
1583 is_async_request, is_request_from_extension, extra_info_spec,
1584 &matching_listeners);
1587 return matching_listeners;
1590 namespace {
1592 helpers::EventResponseDelta* CalculateDelta(
1593 ExtensionWebRequestEventRouter::BlockedRequest* blocked_request,
1594 ExtensionWebRequestEventRouter::EventResponse* response) {
1595 switch (blocked_request->event) {
1596 case ExtensionWebRequestEventRouter::kOnBeforeRequest:
1597 return helpers::CalculateOnBeforeRequestDelta(
1598 response->extension_id, response->extension_install_time,
1599 response->cancel, response->new_url);
1600 case ExtensionWebRequestEventRouter::kOnBeforeSendHeaders: {
1601 net::HttpRequestHeaders* old_headers = blocked_request->request_headers;
1602 net::HttpRequestHeaders* new_headers = response->request_headers.get();
1603 return helpers::CalculateOnBeforeSendHeadersDelta(
1604 response->extension_id, response->extension_install_time,
1605 response->cancel, old_headers, new_headers);
1607 case ExtensionWebRequestEventRouter::kOnHeadersReceived: {
1608 const net::HttpResponseHeaders* old_headers =
1609 blocked_request->original_response_headers.get();
1610 helpers::ResponseHeaders* new_headers =
1611 response->response_headers.get();
1612 return helpers::CalculateOnHeadersReceivedDelta(
1613 response->extension_id,
1614 response->extension_install_time,
1615 response->cancel,
1616 response->new_url,
1617 old_headers,
1618 new_headers);
1620 case ExtensionWebRequestEventRouter::kOnAuthRequired:
1621 return helpers::CalculateOnAuthRequiredDelta(
1622 response->extension_id, response->extension_install_time,
1623 response->cancel, &response->auth_credentials);
1624 default:
1625 NOTREACHED();
1626 break;
1628 return NULL;
1631 base::Value* SerializeResponseHeaders(const helpers::ResponseHeaders& headers) {
1632 scoped_ptr<base::ListValue> serialized_headers(new base::ListValue());
1633 for (helpers::ResponseHeaders::const_iterator i = headers.begin();
1634 i != headers.end(); ++i) {
1635 serialized_headers->Append(ToHeaderDictionary(i->first, i->second));
1637 return serialized_headers.release();
1640 // Convert a RequestCookieModifications/ResponseCookieModifications object to a
1641 // base::ListValue which summarizes the changes made. This is templated since
1642 // the two types (request/response) are different but contain essentially the
1643 // same fields.
1644 template<typename CookieType>
1645 base::ListValue* SummarizeCookieModifications(
1646 const std::vector<linked_ptr<CookieType> >& modifications) {
1647 scoped_ptr<base::ListValue> cookie_modifications(new base::ListValue());
1648 for (typename std::vector<linked_ptr<CookieType> >::const_iterator i =
1649 modifications.begin();
1650 i != modifications.end(); ++i) {
1651 scoped_ptr<base::DictionaryValue> summary(new base::DictionaryValue());
1652 const CookieType& mod = *i->get();
1653 switch (mod.type) {
1654 case helpers::ADD:
1655 summary->SetString(activitylog::kCookieModificationTypeKey,
1656 activitylog::kCookieModificationAdd);
1657 break;
1658 case helpers::EDIT:
1659 summary->SetString(activitylog::kCookieModificationTypeKey,
1660 activitylog::kCookieModificationEdit);
1661 break;
1662 case helpers::REMOVE:
1663 summary->SetString(activitylog::kCookieModificationTypeKey,
1664 activitylog::kCookieModificationRemove);
1665 break;
1667 if (mod.filter) {
1668 if (mod.filter->name)
1669 summary->SetString(activitylog::kCookieFilterNameKey,
1670 *mod.modification->name);
1671 if (mod.filter->domain)
1672 summary->SetString(activitylog::kCookieFilterDomainKey,
1673 *mod.modification->name);
1675 if (mod.modification) {
1676 if (mod.modification->name)
1677 summary->SetString(activitylog::kCookieModDomainKey,
1678 *mod.modification->name);
1679 if (mod.modification->domain)
1680 summary->SetString(activitylog::kCookieModDomainKey,
1681 *mod.modification->name);
1683 cookie_modifications->Append(summary.release());
1685 return cookie_modifications.release();
1688 // Converts an EventResponseDelta object to a dictionary value suitable for the
1689 // activity log.
1690 scoped_ptr<base::DictionaryValue> SummarizeResponseDelta(
1691 const std::string& event_name,
1692 const helpers::EventResponseDelta& delta) {
1693 scoped_ptr<base::DictionaryValue> details(new base::DictionaryValue());
1694 if (delta.cancel) {
1695 details->SetBoolean(activitylog::kCancelKey, true);
1697 if (!delta.new_url.is_empty()) {
1698 details->SetString(activitylog::kNewUrlKey, delta.new_url.spec());
1701 scoped_ptr<base::ListValue> modified_headers(new base::ListValue());
1702 net::HttpRequestHeaders::Iterator iter(delta.modified_request_headers);
1703 while (iter.GetNext()) {
1704 modified_headers->Append(ToHeaderDictionary(iter.name(), iter.value()));
1706 if (!modified_headers->empty()) {
1707 details->Set(activitylog::kModifiedRequestHeadersKey,
1708 modified_headers.release());
1711 scoped_ptr<base::ListValue> deleted_headers(new base::ListValue());
1712 deleted_headers->AppendStrings(delta.deleted_request_headers);
1713 if (!deleted_headers->empty()) {
1714 details->Set(activitylog::kDeletedRequestHeadersKey,
1715 deleted_headers.release());
1718 if (!delta.added_response_headers.empty()) {
1719 details->Set(activitylog::kAddedRequestHeadersKey,
1720 SerializeResponseHeaders(delta.added_response_headers));
1722 if (!delta.deleted_response_headers.empty()) {
1723 details->Set(activitylog::kDeletedResponseHeadersKey,
1724 SerializeResponseHeaders(delta.deleted_response_headers));
1726 if (delta.auth_credentials) {
1727 details->SetString(activitylog::kAuthCredentialsKey,
1728 base::UTF16ToUTF8(
1729 delta.auth_credentials->username()) + ":*");
1732 if (!delta.response_cookie_modifications.empty()) {
1733 details->Set(
1734 activitylog::kResponseCookieModificationsKey,
1735 SummarizeCookieModifications(delta.response_cookie_modifications));
1738 return details.Pass();
1741 void LogExtensionActivity(void* profile_id,
1742 bool is_incognito,
1743 const std::string& extension_id,
1744 const GURL& url,
1745 const std::string& api_call,
1746 scoped_ptr<base::DictionaryValue> details) {
1747 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
1748 BrowserThread::PostTask(BrowserThread::UI,
1749 FROM_HERE,
1750 base::Bind(&LogExtensionActivity,
1751 profile_id,
1752 is_incognito,
1753 extension_id,
1754 url,
1755 api_call,
1756 base::Passed(&details)));
1757 } else {
1758 Profile* profile = static_cast<Profile*>(profile_id);
1759 if (!g_browser_process->profile_manager()->IsValidProfile(profile))
1760 return;
1761 scoped_refptr<extensions::Action> action =
1762 new extensions::Action(extension_id,
1763 base::Time::Now(),
1764 extensions::Action::ACTION_WEB_REQUEST,
1765 api_call);
1766 action->set_page_url(url);
1767 action->set_page_incognito(is_incognito);
1768 action->mutable_other()->Set(activity_log_constants::kActionWebRequest,
1769 details.release());
1770 extensions::ActivityLog::GetInstance(profile)->LogAction(action);
1774 } // namespace
1776 void ExtensionWebRequestEventRouter::DecrementBlockCount(
1777 void* profile,
1778 const std::string& extension_id,
1779 const std::string& event_name,
1780 uint64 request_id,
1781 EventResponse* response) {
1782 scoped_ptr<EventResponse> response_scoped(response);
1784 // It's possible that this request was deleted, or cancelled by a previous
1785 // event handler. If so, ignore this response.
1786 if (blocked_requests_.find(request_id) == blocked_requests_.end())
1787 return;
1789 BlockedRequest& blocked_request = blocked_requests_[request_id];
1790 int num_handlers_blocking = --blocked_request.num_handlers_blocking;
1791 CHECK_GE(num_handlers_blocking, 0);
1793 if (response) {
1794 helpers::EventResponseDelta* delta =
1795 CalculateDelta(&blocked_request, response);
1797 LogExtensionActivity(profile,
1798 blocked_request.is_incognito,
1799 extension_id,
1800 blocked_request.request->url(),
1801 event_name,
1802 SummarizeResponseDelta(event_name, *delta));
1804 blocked_request.response_deltas.push_back(
1805 linked_ptr<helpers::EventResponseDelta>(delta));
1808 base::TimeDelta block_time =
1809 base::Time::Now() - blocked_request.blocking_time;
1810 if (!extension_id.empty()) {
1811 request_time_tracker_->IncrementExtensionBlockTime(
1812 extension_id, request_id, block_time);
1813 } else {
1814 // |extension_id| is empty for requests blocked on startup waiting for the
1815 // declarative rules to be read from disk.
1816 UMA_HISTOGRAM_TIMES("Extensions.NetworkDelayStartup", block_time);
1819 if (num_handlers_blocking == 0) {
1820 blocked_request.request->LogUnblocked();
1821 ExecuteDeltas(profile, request_id, true);
1822 } else {
1823 // Update the URLRequest to make sure it's tagged with an extension that's
1824 // still blocking it. This may end up being the same extension as before.
1825 std::set<EventListener>& listeners = listeners_[profile][event_name];
1827 for (std::set<EventListener>::iterator it = listeners.begin();
1828 it != listeners.end(); ++it) {
1829 if (it->blocked_requests.count(request_id) == 0)
1830 continue;
1831 std::string delegate_info =
1832 l10n_util::GetStringFUTF8(IDS_LOAD_STATE_PARAMETER_EXTENSION,
1833 base::UTF8ToUTF16(it->extension_name));
1834 blocked_request.request->LogAndReportBlockedBy(delegate_info.c_str());
1835 break;
1840 void ExtensionWebRequestEventRouter::SendMessages(
1841 void* profile,
1842 const BlockedRequest& blocked_request) {
1843 const helpers::EventResponseDeltas& deltas = blocked_request.response_deltas;
1844 for (helpers::EventResponseDeltas::const_iterator delta = deltas.begin();
1845 delta != deltas.end(); ++delta) {
1846 const std::set<std::string>& messages = (*delta)->messages_to_extension;
1847 for (std::set<std::string>::const_iterator message = messages.begin();
1848 message != messages.end(); ++message) {
1849 scoped_ptr<base::DictionaryValue> argument(new base::DictionaryValue);
1850 ExtractRequestInfo(blocked_request.request, argument.get());
1851 WebViewRendererState::WebViewInfo web_view_info;
1852 bool is_web_view_guest = GetWebViewInfo(blocked_request.request,
1853 &web_view_info);
1854 argument->SetString(keys::kMessageKey, *message);
1855 argument->SetString(keys::kStageKey,
1856 GetRequestStageAsString(blocked_request.event));
1858 BrowserThread::PostTask(
1859 BrowserThread::UI,
1860 FROM_HERE,
1861 base::Bind(&SendOnMessageEventOnUI,
1862 profile,
1863 (*delta)->extension_id,
1864 is_web_view_guest,
1865 web_view_info,
1866 base::Passed(&argument)));
1871 int ExtensionWebRequestEventRouter::ExecuteDeltas(
1872 void* profile,
1873 uint64 request_id,
1874 bool call_callback) {
1875 BlockedRequest& blocked_request = blocked_requests_[request_id];
1876 CHECK(blocked_request.num_handlers_blocking == 0);
1877 helpers::EventResponseDeltas& deltas = blocked_request.response_deltas;
1878 base::TimeDelta block_time =
1879 base::Time::Now() - blocked_request.blocking_time;
1880 request_time_tracker_->IncrementTotalBlockTime(request_id, block_time);
1882 bool credentials_set = false;
1884 deltas.sort(&helpers::InDecreasingExtensionInstallationTimeOrder);
1885 ExtensionWarningSet warnings;
1887 bool canceled = false;
1888 helpers::MergeCancelOfResponses(
1889 blocked_request.response_deltas,
1890 &canceled,
1891 blocked_request.net_log);
1893 if (blocked_request.event == kOnBeforeRequest) {
1894 CHECK(!blocked_request.callback.is_null());
1895 helpers::MergeOnBeforeRequestResponses(
1896 blocked_request.response_deltas,
1897 blocked_request.new_url,
1898 &warnings,
1899 blocked_request.net_log);
1900 } else if (blocked_request.event == kOnBeforeSendHeaders) {
1901 CHECK(!blocked_request.callback.is_null());
1902 helpers::MergeOnBeforeSendHeadersResponses(
1903 blocked_request.response_deltas,
1904 blocked_request.request_headers,
1905 &warnings,
1906 blocked_request.net_log);
1907 } else if (blocked_request.event == kOnHeadersReceived) {
1908 CHECK(!blocked_request.callback.is_null());
1909 helpers::MergeOnHeadersReceivedResponses(
1910 blocked_request.response_deltas,
1911 blocked_request.original_response_headers.get(),
1912 blocked_request.override_response_headers,
1913 blocked_request.new_url,
1914 &warnings,
1915 blocked_request.net_log);
1916 } else if (blocked_request.event == kOnAuthRequired) {
1917 CHECK(blocked_request.callback.is_null());
1918 CHECK(!blocked_request.auth_callback.is_null());
1919 credentials_set = helpers::MergeOnAuthRequiredResponses(
1920 blocked_request.response_deltas,
1921 blocked_request.auth_credentials,
1922 &warnings,
1923 blocked_request.net_log);
1924 } else {
1925 NOTREACHED();
1928 SendMessages(profile, blocked_request);
1930 if (!warnings.empty()) {
1931 BrowserThread::PostTask(
1932 BrowserThread::UI,
1933 FROM_HERE,
1934 base::Bind(&ExtensionWarningService::NotifyWarningsOnUI,
1935 profile, warnings));
1938 if (canceled) {
1939 request_time_tracker_->SetRequestCanceled(request_id);
1940 } else if (blocked_request.new_url &&
1941 !blocked_request.new_url->is_empty()) {
1942 request_time_tracker_->SetRequestRedirected(request_id);
1945 // This triggers onErrorOccurred if canceled is true.
1946 int rv = canceled ? net::ERR_BLOCKED_BY_CLIENT : net::OK;
1948 if (!blocked_request.callback.is_null()) {
1949 net::CompletionCallback callback = blocked_request.callback;
1950 // Ensure that request is removed before callback because the callback
1951 // might trigger the next event.
1952 blocked_requests_.erase(request_id);
1953 if (call_callback)
1954 callback.Run(rv);
1955 } else if (!blocked_request.auth_callback.is_null()) {
1956 net::NetworkDelegate::AuthRequiredResponse response =
1957 net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION;
1958 if (canceled) {
1959 response = net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_CANCEL_AUTH;
1960 } else if (credentials_set) {
1961 response = net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_SET_AUTH;
1963 net::NetworkDelegate::AuthCallback callback = blocked_request.auth_callback;
1964 blocked_requests_.erase(request_id);
1965 if (call_callback)
1966 callback.Run(response);
1967 } else {
1968 blocked_requests_.erase(request_id);
1970 return rv;
1973 bool ExtensionWebRequestEventRouter::ProcessDeclarativeRules(
1974 void* profile,
1975 InfoMap* extension_info_map,
1976 const std::string& event_name,
1977 net::URLRequest* request,
1978 extensions::RequestStage request_stage,
1979 const net::HttpResponseHeaders* original_response_headers) {
1980 WebViewRendererState::WebViewInfo web_view_info;
1981 bool is_web_view_guest = GetWebViewInfo(request, &web_view_info);
1983 RulesRegistryService::WebViewKey webview_key(
1984 is_web_view_guest ? web_view_info.embedder_process_id : 0,
1985 is_web_view_guest ? web_view_info.instance_id : 0);
1986 RulesRegistryKey rules_key(profile, webview_key);
1987 // If this check fails, check that the active stages are up-to-date in
1988 // browser/extensions/api/declarative_webrequest/request_stage.h .
1989 DCHECK(request_stage & extensions::kActiveStages);
1991 // Rules of the current |profile| may apply but we need to check also whether
1992 // there are applicable rules from extensions whose background page
1993 // spans from regular to incognito mode.
1995 // First parameter identifies the registry, the second indicates whether the
1996 // registry belongs to the cross profile.
1997 typedef std::pair<extensions::WebRequestRulesRegistry*, bool>
1998 RelevantRegistry;
1999 typedef std::vector<RelevantRegistry> RelevantRegistries;
2000 RelevantRegistries relevant_registries;
2002 if (rules_registries_.find(rules_key) != rules_registries_.end()) {
2003 relevant_registries.push_back(
2004 std::make_pair(rules_registries_[rules_key].get(), false));
2007 void* cross_profile = GetCrossProfile(profile);
2008 RulesRegistryKey cross_profile_rules_key(cross_profile, webview_key);
2009 if (cross_profile &&
2010 rules_registries_.find(cross_profile_rules_key) !=
2011 rules_registries_.end()) {
2012 relevant_registries.push_back(
2013 std::make_pair(rules_registries_[cross_profile_rules_key].get(), true));
2016 // The following block is experimentally enabled and its impact on load time
2017 // logged with UMA Extensions.NetworkDelayRegistryLoad. crbug.com/175961
2018 for (RelevantRegistries::iterator i = relevant_registries.begin();
2019 i != relevant_registries.end(); ++i) {
2020 extensions::WebRequestRulesRegistry* rules_registry = i->first;
2021 if (!rules_registry->ready().is_signaled()) {
2022 // The rules registry is still loading. Block this request until it
2023 // finishes.
2024 rules_registry->ready().Post(
2025 FROM_HERE,
2026 base::Bind(&ExtensionWebRequestEventRouter::OnRulesRegistryReady,
2027 AsWeakPtr(),
2028 profile,
2029 event_name,
2030 request->identifier(),
2031 request_stage));
2032 blocked_requests_[request->identifier()].num_handlers_blocking++;
2033 blocked_requests_[request->identifier()].request = request;
2034 blocked_requests_[request->identifier()].is_incognito |=
2035 IsIncognitoProfile(profile);
2036 blocked_requests_[request->identifier()].blocking_time =
2037 base::Time::Now();
2038 blocked_requests_[request->identifier()].original_response_headers =
2039 original_response_headers;
2040 blocked_requests_[request->identifier()].extension_info_map =
2041 extension_info_map;
2042 return true;
2046 base::Time start = base::Time::Now();
2048 bool deltas_created = false;
2049 for (RelevantRegistries::iterator i = relevant_registries.begin();
2050 i != relevant_registries.end(); ++i) {
2051 extensions::WebRequestRulesRegistry* rules_registry =
2052 i->first;
2053 helpers::EventResponseDeltas result =
2054 rules_registry->CreateDeltas(
2055 extension_info_map,
2056 extensions::WebRequestData(
2057 request, request_stage, original_response_headers),
2058 i->second);
2060 if (!result.empty()) {
2061 helpers::EventResponseDeltas& deltas =
2062 blocked_requests_[request->identifier()].response_deltas;
2063 deltas.insert(deltas.end(), result.begin(), result.end());
2064 deltas_created = true;
2068 base::TimeDelta elapsed_time = start - base::Time::Now();
2069 UMA_HISTOGRAM_TIMES("Extensions.DeclarativeWebRequestNetworkDelay",
2070 elapsed_time);
2072 return deltas_created;
2075 void ExtensionWebRequestEventRouter::OnRulesRegistryReady(
2076 void* profile,
2077 const std::string& event_name,
2078 uint64 request_id,
2079 extensions::RequestStage request_stage) {
2080 // It's possible that this request was deleted, or cancelled by a previous
2081 // event handler. If so, ignore this response.
2082 if (blocked_requests_.find(request_id) == blocked_requests_.end())
2083 return;
2085 BlockedRequest& blocked_request = blocked_requests_[request_id];
2086 base::TimeDelta block_time =
2087 base::Time::Now() - blocked_request.blocking_time;
2088 UMA_HISTOGRAM_TIMES("Extensions.NetworkDelayRegistryLoad", block_time);
2090 ProcessDeclarativeRules(profile,
2091 blocked_request.extension_info_map,
2092 event_name,
2093 blocked_request.request,
2094 request_stage,
2095 blocked_request.original_response_headers.get());
2096 // Reset to NULL so that nobody relies on this being set.
2097 blocked_request.extension_info_map = NULL;
2098 DecrementBlockCount(profile, std::string(), event_name, request_id, NULL);
2101 bool ExtensionWebRequestEventRouter::GetAndSetSignaled(uint64 request_id,
2102 EventTypes event_type) {
2103 SignaledRequestMap::iterator iter = signaled_requests_.find(request_id);
2104 if (iter == signaled_requests_.end()) {
2105 signaled_requests_[request_id] = event_type;
2106 return false;
2108 bool was_signaled_before = (iter->second & event_type) != 0;
2109 iter->second |= event_type;
2110 return was_signaled_before;
2113 void ExtensionWebRequestEventRouter::ClearSignaled(uint64 request_id,
2114 EventTypes event_type) {
2115 SignaledRequestMap::iterator iter = signaled_requests_.find(request_id);
2116 if (iter == signaled_requests_.end())
2117 return;
2118 iter->second &= ~event_type;
2121 // Special QuotaLimitHeuristic for WebRequestHandlerBehaviorChangedFunction.
2123 // Each call of webRequest.handlerBehaviorChanged() clears the in-memory cache
2124 // of WebKit at the time of the next page load (top level navigation event).
2125 // This quota heuristic is intended to limit the number of times the cache is
2126 // cleared by an extension.
2128 // As we want to account for the number of times the cache is really cleared
2129 // (opposed to the number of times webRequest.handlerBehaviorChanged() is
2130 // called), we cannot decide whether a call of
2131 // webRequest.handlerBehaviorChanged() should trigger a quota violation at the
2132 // time it is called. Instead we only decrement the bucket counter at the time
2133 // when the cache is cleared (when page loads happen).
2134 class ClearCacheQuotaHeuristic : public extensions::QuotaLimitHeuristic {
2135 public:
2136 ClearCacheQuotaHeuristic(const Config& config, BucketMapper* map)
2137 : QuotaLimitHeuristic(
2138 config,
2139 map,
2140 "MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES"),
2141 callback_registered_(false),
2142 weak_ptr_factory_(this) {}
2143 virtual ~ClearCacheQuotaHeuristic() {}
2144 virtual bool Apply(Bucket* bucket,
2145 const base::TimeTicks& event_time) OVERRIDE;
2147 private:
2148 // Callback that is triggered by the ExtensionWebRequestEventRouter on a page
2149 // load.
2151 // We don't need to take care of the life time of |bucket|: It is owned by the
2152 // BucketMapper of our base class in |QuotaLimitHeuristic::bucket_mapper_|. As
2153 // long as |this| exists, the respective BucketMapper and its bucket will
2154 // exist as well.
2155 void OnPageLoad(Bucket* bucket);
2157 // Flag to prevent that we register more than one call back in-between
2158 // clearing the cache.
2159 bool callback_registered_;
2161 base::WeakPtrFactory<ClearCacheQuotaHeuristic> weak_ptr_factory_;
2163 DISALLOW_COPY_AND_ASSIGN(ClearCacheQuotaHeuristic);
2166 bool ClearCacheQuotaHeuristic::Apply(Bucket* bucket,
2167 const base::TimeTicks& event_time) {
2168 if (event_time > bucket->expiration())
2169 bucket->Reset(config(), event_time);
2171 // Call bucket->DeductToken() on a new page load, this is when
2172 // webRequest.handlerBehaviorChanged() clears the cache.
2173 if (!callback_registered_) {
2174 ExtensionWebRequestEventRouter::GetInstance()->AddCallbackForPageLoad(
2175 base::Bind(&ClearCacheQuotaHeuristic::OnPageLoad,
2176 weak_ptr_factory_.GetWeakPtr(),
2177 bucket));
2178 callback_registered_ = true;
2181 // We only check whether tokens are left here. Deducting a token happens in
2182 // OnPageLoad().
2183 return bucket->has_tokens();
2186 void ClearCacheQuotaHeuristic::OnPageLoad(Bucket* bucket) {
2187 callback_registered_ = false;
2188 bucket->DeductToken();
2191 bool WebRequestInternalAddEventListenerFunction::RunSync() {
2192 // Argument 0 is the callback, which we don't use here.
2193 ExtensionWebRequestEventRouter::RequestFilter filter;
2194 base::DictionaryValue* value = NULL;
2195 error_.clear();
2196 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &value));
2197 // Failure + an empty error string means a fatal error.
2198 EXTENSION_FUNCTION_VALIDATE(filter.InitFromValue(*value, &error_) ||
2199 !error_.empty());
2200 if (!error_.empty())
2201 return false;
2203 int extra_info_spec = 0;
2204 if (HasOptionalArgument(2)) {
2205 base::ListValue* value = NULL;
2206 EXTENSION_FUNCTION_VALIDATE(args_->GetList(2, &value));
2207 EXTENSION_FUNCTION_VALIDATE(
2208 ExtensionWebRequestEventRouter::ExtraInfoSpec::InitFromValue(
2209 *value, &extra_info_spec));
2212 std::string event_name;
2213 EXTENSION_FUNCTION_VALIDATE(args_->GetString(3, &event_name));
2215 std::string sub_event_name;
2216 EXTENSION_FUNCTION_VALIDATE(args_->GetString(4, &sub_event_name));
2218 int webview_instance_id = 0;
2219 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(5, &webview_instance_id));
2221 base::WeakPtr<extensions::ExtensionMessageFilter> ipc_sender =
2222 ipc_sender_weak();
2223 int embedder_process_id =
2224 ipc_sender.get() ? ipc_sender->render_process_id() : -1;
2226 const Extension* extension =
2227 extension_info_map()->extensions().GetByID(extension_id());
2228 std::string extension_name = extension ? extension->name() : extension_id();
2230 bool is_web_view_guest = webview_instance_id != 0;
2231 // We check automatically whether the extension has the 'webRequest'
2232 // permission. For blocking calls we require the additional permission
2233 // 'webRequestBlocking'.
2234 if ((!is_web_view_guest &&
2235 extra_info_spec &
2236 (ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING |
2237 ExtensionWebRequestEventRouter::ExtraInfoSpec::ASYNC_BLOCKING)) &&
2238 !extension->permissions_data()->HasAPIPermission(
2239 extensions::APIPermission::kWebRequestBlocking)) {
2240 error_ = keys::kBlockingPermissionRequired;
2241 return false;
2244 // We allow to subscribe to patterns that are broader than the host
2245 // permissions. E.g., we could subscribe to http://www.example.com/*
2246 // while having host permissions for http://www.example.com/foo/* and
2247 // http://www.example.com/bar/*.
2248 // For this reason we do only a coarse check here to warn the extension
2249 // developer if he does something obviously wrong.
2250 if (!is_web_view_guest &&
2251 extension->permissions_data()->GetEffectiveHostPermissions().is_empty()) {
2252 error_ = keys::kHostPermissionsRequired;
2253 return false;
2256 bool success =
2257 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
2258 profile_id(), extension_id(), extension_name,
2259 event_name, sub_event_name, filter, extra_info_spec,
2260 embedder_process_id, webview_instance_id, ipc_sender_weak());
2261 EXTENSION_FUNCTION_VALIDATE(success);
2263 helpers::ClearCacheOnNavigation();
2265 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
2266 &helpers::NotifyWebRequestAPIUsed,
2267 profile_id(), make_scoped_refptr(GetExtension())));
2269 return true;
2272 void WebRequestInternalEventHandledFunction::RespondWithError(
2273 const std::string& event_name,
2274 const std::string& sub_event_name,
2275 uint64 request_id,
2276 scoped_ptr<ExtensionWebRequestEventRouter::EventResponse> response,
2277 const std::string& error) {
2278 error_ = error;
2279 ExtensionWebRequestEventRouter::GetInstance()->OnEventHandled(
2280 profile_id(),
2281 extension_id(),
2282 event_name,
2283 sub_event_name,
2284 request_id,
2285 response.release());
2288 bool WebRequestInternalEventHandledFunction::RunSync() {
2289 std::string event_name;
2290 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &event_name));
2292 std::string sub_event_name;
2293 EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &sub_event_name));
2295 std::string request_id_str;
2296 EXTENSION_FUNCTION_VALIDATE(args_->GetString(2, &request_id_str));
2297 uint64 request_id;
2298 EXTENSION_FUNCTION_VALIDATE(base::StringToUint64(request_id_str,
2299 &request_id));
2301 scoped_ptr<ExtensionWebRequestEventRouter::EventResponse> response;
2302 if (HasOptionalArgument(3)) {
2303 base::DictionaryValue* value = NULL;
2304 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(3, &value));
2306 if (!value->empty()) {
2307 base::Time install_time =
2308 extension_info_map()->GetInstallTime(extension_id());
2309 response.reset(new ExtensionWebRequestEventRouter::EventResponse(
2310 extension_id(), install_time));
2313 if (value->HasKey("cancel")) {
2314 // Don't allow cancel mixed with other keys.
2315 if (value->size() != 1) {
2316 RespondWithError(event_name,
2317 sub_event_name,
2318 request_id,
2319 response.Pass(),
2320 keys::kInvalidBlockingResponse);
2321 return false;
2324 bool cancel = false;
2325 EXTENSION_FUNCTION_VALIDATE(value->GetBoolean("cancel", &cancel));
2326 response->cancel = cancel;
2329 if (value->HasKey("redirectUrl")) {
2330 std::string new_url_str;
2331 EXTENSION_FUNCTION_VALIDATE(value->GetString("redirectUrl",
2332 &new_url_str));
2333 response->new_url = GURL(new_url_str);
2334 if (!response->new_url.is_valid()) {
2335 RespondWithError(event_name,
2336 sub_event_name,
2337 request_id,
2338 response.Pass(),
2339 ErrorUtils::FormatErrorMessage(
2340 keys::kInvalidRedirectUrl, new_url_str));
2341 return false;
2345 const bool hasRequestHeaders = value->HasKey("requestHeaders");
2346 const bool hasResponseHeaders = value->HasKey("responseHeaders");
2347 if (hasRequestHeaders || hasResponseHeaders) {
2348 if (hasRequestHeaders && hasResponseHeaders) {
2349 // Allow only one of the keys, not both.
2350 RespondWithError(event_name,
2351 sub_event_name,
2352 request_id,
2353 response.Pass(),
2354 keys::kInvalidHeaderKeyCombination);
2355 return false;
2358 base::ListValue* headers_value = NULL;
2359 scoped_ptr<net::HttpRequestHeaders> request_headers;
2360 scoped_ptr<helpers::ResponseHeaders> response_headers;
2361 if (hasRequestHeaders) {
2362 request_headers.reset(new net::HttpRequestHeaders());
2363 EXTENSION_FUNCTION_VALIDATE(value->GetList(keys::kRequestHeadersKey,
2364 &headers_value));
2365 } else {
2366 response_headers.reset(new helpers::ResponseHeaders());
2367 EXTENSION_FUNCTION_VALIDATE(value->GetList(keys::kResponseHeadersKey,
2368 &headers_value));
2371 for (size_t i = 0; i < headers_value->GetSize(); ++i) {
2372 base::DictionaryValue* header_value = NULL;
2373 std::string name;
2374 std::string value;
2375 EXTENSION_FUNCTION_VALIDATE(
2376 headers_value->GetDictionary(i, &header_value));
2377 if (!FromHeaderDictionary(header_value, &name, &value)) {
2378 std::string serialized_header;
2379 base::JSONWriter::Write(header_value, &serialized_header);
2380 RespondWithError(event_name,
2381 sub_event_name,
2382 request_id,
2383 response.Pass(),
2384 ErrorUtils::FormatErrorMessage(keys::kInvalidHeader,
2385 serialized_header));
2386 return false;
2388 if (!helpers::IsValidHeaderName(name)) {
2389 RespondWithError(event_name,
2390 sub_event_name,
2391 request_id,
2392 response.Pass(),
2393 keys::kInvalidHeaderName);
2394 return false;
2396 if (!helpers::IsValidHeaderValue(value)) {
2397 RespondWithError(event_name,
2398 sub_event_name,
2399 request_id,
2400 response.Pass(),
2401 ErrorUtils::FormatErrorMessage(
2402 keys::kInvalidHeaderValue, name));
2403 return false;
2405 if (hasRequestHeaders)
2406 request_headers->SetHeader(name, value);
2407 else
2408 response_headers->push_back(helpers::ResponseHeader(name, value));
2410 if (hasRequestHeaders)
2411 response->request_headers.reset(request_headers.release());
2412 else
2413 response->response_headers.reset(response_headers.release());
2416 if (value->HasKey(keys::kAuthCredentialsKey)) {
2417 base::DictionaryValue* credentials_value = NULL;
2418 EXTENSION_FUNCTION_VALIDATE(value->GetDictionary(
2419 keys::kAuthCredentialsKey,
2420 &credentials_value));
2421 base::string16 username;
2422 base::string16 password;
2423 EXTENSION_FUNCTION_VALIDATE(
2424 credentials_value->GetString(keys::kUsernameKey, &username));
2425 EXTENSION_FUNCTION_VALIDATE(
2426 credentials_value->GetString(keys::kPasswordKey, &password));
2427 response->auth_credentials.reset(
2428 new net::AuthCredentials(username, password));
2432 ExtensionWebRequestEventRouter::GetInstance()->OnEventHandled(
2433 profile_id(), extension_id(), event_name, sub_event_name, request_id,
2434 response.release());
2436 return true;
2439 void WebRequestHandlerBehaviorChangedFunction::GetQuotaLimitHeuristics(
2440 extensions::QuotaLimitHeuristics* heuristics) const {
2441 extensions::QuotaLimitHeuristic::Config config = {
2442 // See web_request.json for current value.
2443 web_request::MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES,
2444 base::TimeDelta::FromMinutes(10)};
2445 extensions::QuotaLimitHeuristic::BucketMapper* bucket_mapper =
2446 new extensions::QuotaLimitHeuristic::SingletonBucketMapper();
2447 ClearCacheQuotaHeuristic* heuristic =
2448 new ClearCacheQuotaHeuristic(config, bucket_mapper);
2449 heuristics->push_back(heuristic);
2452 void WebRequestHandlerBehaviorChangedFunction::OnQuotaExceeded(
2453 const std::string& violation_error) {
2454 // Post warning message.
2455 ExtensionWarningSet warnings;
2456 warnings.insert(
2457 ExtensionWarning::CreateRepeatedCacheFlushesWarning(extension_id()));
2458 BrowserThread::PostTask(
2459 BrowserThread::UI,
2460 FROM_HERE,
2461 base::Bind(&ExtensionWarningService::NotifyWarningsOnUI,
2462 profile_id(), warnings));
2464 // Continue gracefully.
2465 RunSync();
2468 bool WebRequestHandlerBehaviorChangedFunction::RunSync() {
2469 helpers::ClearCacheOnNavigation();
2470 return true;
2473 void SendExtensionWebRequestStatusToHost(content::RenderProcessHost* host) {
2474 Profile* profile = Profile::FromBrowserContext(host->GetBrowserContext());
2475 if (!profile)
2476 return;
2478 bool webrequest_used = false;
2479 const extensions::ExtensionSet& extensions =
2480 extensions::ExtensionRegistry::Get(profile)->enabled_extensions();
2481 extensions::RuntimeData* runtime_data =
2482 extensions::ExtensionSystem::Get(profile)->runtime_data();
2483 for (extensions::ExtensionSet::const_iterator it = extensions.begin();
2484 !webrequest_used && it != extensions.end();
2485 ++it) {
2486 webrequest_used |= runtime_data->HasUsedWebRequest(it->get());
2489 host->Send(new ExtensionMsg_UsingWebRequestAPI(webrequest_used));