Add testing/scripts/OWNERS
[chromium-blink-merge.git] / extensions / browser / api / web_request / web_request_api.cc
blobc1e8f9d36ab0dd3bedd29b4500285cce82f14653
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "extensions/browser/api/web_request/web_request_api.h"
7 #include <algorithm>
9 #include "base/bind.h"
10 #include "base/bind_helpers.h"
11 #include "base/json/json_writer.h"
12 #include "base/lazy_instance.h"
13 #include "base/metrics/histogram.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/string_util.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "base/time/time.h"
18 #include "base/values.h"
19 #include "content/public/browser/browser_message_filter.h"
20 #include "content/public/browser/browser_thread.h"
21 #include "content/public/browser/render_frame_host.h"
22 #include "content/public/browser/render_process_host.h"
23 #include "content/public/browser/resource_request_info.h"
24 #include "content/public/browser/user_metrics.h"
25 #include "extensions/browser/api/activity_log/web_request_constants.h"
26 #include "extensions/browser/api/declarative_webrequest/request_stage.h"
27 #include "extensions/browser/api/declarative_webrequest/webrequest_constants.h"
28 #include "extensions/browser/api/declarative_webrequest/webrequest_rules_registry.h"
29 #include "extensions/browser/api/extensions_api_client.h"
30 #include "extensions/browser/api/web_request/upload_data_presenter.h"
31 #include "extensions/browser/api/web_request/web_request_api_constants.h"
32 #include "extensions/browser/api/web_request/web_request_api_helpers.h"
33 #include "extensions/browser/api/web_request/web_request_event_router_delegate.h"
34 #include "extensions/browser/api/web_request/web_request_time_tracker.h"
35 #include "extensions/browser/event_router.h"
36 #include "extensions/browser/extension_message_filter.h"
37 #include "extensions/browser/extension_prefs.h"
38 #include "extensions/browser/extension_registry.h"
39 #include "extensions/browser/extension_system.h"
40 #include "extensions/browser/extensions_browser_client.h"
41 #include "extensions/browser/guest_view/web_view/web_view_constants.h"
42 #include "extensions/browser/guest_view/web_view/web_view_renderer_state.h"
43 #include "extensions/browser/info_map.h"
44 #include "extensions/browser/runtime_data.h"
45 #include "extensions/browser/warning_service.h"
46 #include "extensions/browser/warning_set.h"
47 #include "extensions/common/api/web_request.h"
48 #include "extensions/common/error_utils.h"
49 #include "extensions/common/event_filtering_info.h"
50 #include "extensions/common/extension.h"
51 #include "extensions/common/features/feature.h"
52 #include "extensions/common/permissions/permissions_data.h"
53 #include "extensions/common/url_pattern.h"
54 #include "extensions/strings/grit/extensions_strings.h"
55 #include "net/base/auth.h"
56 #include "net/base/net_errors.h"
57 #include "net/base/upload_data_stream.h"
58 #include "net/http/http_response_headers.h"
59 #include "net/http/http_util.h"
60 #include "net/url_request/url_request.h"
61 #include "ui/base/l10n/l10n_util.h"
62 #include "url/gurl.h"
64 using base::DictionaryValue;
65 using base::ListValue;
66 using base::StringValue;
67 using content::BrowserMessageFilter;
68 using content::BrowserThread;
69 using content::ResourceRequestInfo;
70 using content::ResourceType;
71 using extensions::ErrorUtils;
72 using extensions::Extension;
73 using extensions::InfoMap;
74 using extensions::Feature;
75 using extensions::RulesRegistryService;
76 using extensions::Warning;
77 using extensions::WarningService;
78 using extensions::WarningSet;
80 namespace activitylog = activity_log_web_request_constants;
81 namespace helpers = extension_web_request_api_helpers;
82 namespace keys = extension_web_request_api_constants;
83 namespace web_request = extensions::core_api::web_request;
84 namespace declarative_keys = extensions::declarative_webrequest_constants;
86 namespace {
88 const char kWebRequestEventPrefix[] = "webRequest.";
90 // List of all the webRequest events.
91 const char* const kWebRequestEvents[] = {
92 keys::kOnBeforeRedirectEvent,
93 web_request::OnBeforeRequest::kEventName,
94 keys::kOnBeforeSendHeadersEvent,
95 keys::kOnCompletedEvent,
96 web_request::OnErrorOccurred::kEventName,
97 keys::kOnSendHeadersEvent,
98 keys::kOnAuthRequiredEvent,
99 keys::kOnResponseStartedEvent,
100 keys::kOnHeadersReceivedEvent,
103 const size_t kWebRequestEventsLength = arraysize(kWebRequestEvents);
105 const char* GetRequestStageAsString(
106 ExtensionWebRequestEventRouter::EventTypes type) {
107 switch (type) {
108 case ExtensionWebRequestEventRouter::kInvalidEvent:
109 return "Invalid";
110 case ExtensionWebRequestEventRouter::kOnBeforeRequest:
111 return keys::kOnBeforeRequest;
112 case ExtensionWebRequestEventRouter::kOnBeforeSendHeaders:
113 return keys::kOnBeforeSendHeaders;
114 case ExtensionWebRequestEventRouter::kOnSendHeaders:
115 return keys::kOnSendHeaders;
116 case ExtensionWebRequestEventRouter::kOnHeadersReceived:
117 return keys::kOnHeadersReceived;
118 case ExtensionWebRequestEventRouter::kOnBeforeRedirect:
119 return keys::kOnBeforeRedirect;
120 case ExtensionWebRequestEventRouter::kOnAuthRequired:
121 return keys::kOnAuthRequired;
122 case ExtensionWebRequestEventRouter::kOnResponseStarted:
123 return keys::kOnResponseStarted;
124 case ExtensionWebRequestEventRouter::kOnErrorOccurred:
125 return keys::kOnErrorOccurred;
126 case ExtensionWebRequestEventRouter::kOnCompleted:
127 return keys::kOnCompleted;
129 NOTREACHED();
130 return "Not reached";
133 int GetFrameId(bool is_main_frame, int frame_id) {
134 return is_main_frame ? 0 : frame_id;
137 bool IsWebRequestEvent(const std::string& event_name) {
138 std::string web_request_event_name(event_name);
139 if (StartsWithASCII(
140 web_request_event_name, webview::kWebViewEventPrefix, true)) {
141 web_request_event_name.replace(
142 0, strlen(webview::kWebViewEventPrefix), kWebRequestEventPrefix);
144 return std::find(
145 kWebRequestEvents,
146 kWebRequestEvents + kWebRequestEventsLength,
147 web_request_event_name) != (kWebRequestEvents + kWebRequestEventsLength);
150 // Returns whether |request| has been triggered by an extension in
151 // |extension_info_map|.
152 bool IsRequestFromExtension(const net::URLRequest* request,
153 const InfoMap* extension_info_map) {
154 // |extension_info_map| is NULL for system-level requests.
155 if (!extension_info_map)
156 return false;
158 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
160 // If this request was not created by the ResourceDispatcher, |info| is NULL.
161 // All requests from extensions are created by the ResourceDispatcher.
162 if (!info)
163 return false;
165 return extension_info_map->process_map().Contains(info->GetChildID());
168 void ExtractRequestRoutingInfo(net::URLRequest* request,
169 int* render_process_host_id,
170 int* routing_id) {
171 if (!request->GetUserData(NULL))
172 return;
173 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
174 *render_process_host_id = info->GetChildID();
175 *routing_id = info->GetRouteID();
178 // Given a |request|, this function determines whether it originated from
179 // a <webview> guest process or not. If it is from a <webview> guest process,
180 // then |web_view_info| is returned with information about the instance ID
181 // that uniquely identifies the <webview> and its embedder.
182 bool GetWebViewInfo(
183 net::URLRequest* request,
184 extensions::WebViewRendererState::WebViewInfo* web_view_info) {
185 int render_process_host_id = -1;
186 int routing_id = -1;
187 ExtractRequestRoutingInfo(request, &render_process_host_id, &routing_id);
188 return extensions::WebViewRendererState::GetInstance()->
189 GetInfo(render_process_host_id, routing_id, web_view_info);
192 void ExtractRequestInfoDetails(net::URLRequest* request,
193 bool* is_main_frame,
194 int* frame_id,
195 bool* parent_is_main_frame,
196 int* parent_frame_id,
197 int* render_process_host_id,
198 int* routing_id,
199 ResourceType* resource_type) {
200 if (!request->GetUserData(NULL))
201 return;
203 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
204 *frame_id = info->GetRenderFrameID();
205 *is_main_frame = info->IsMainFrame();
206 *parent_frame_id = info->GetParentRenderFrameID();
207 *parent_is_main_frame = info->ParentIsMainFrame();
208 *render_process_host_id = info->GetChildID();
209 *routing_id = info->GetRouteID();
211 // Restrict the resource type to the values we care about.
212 if (helpers::IsRelevantResourceType(info->GetResourceType()))
213 *resource_type = info->GetResourceType();
214 else
215 *resource_type = content::RESOURCE_TYPE_LAST_TYPE;
218 // Extracts the body from |request| and writes the data into |out|.
219 void ExtractRequestInfoBody(const net::URLRequest* request,
220 base::DictionaryValue* out) {
221 const net::UploadDataStream* upload_data = request->get_upload();
222 if (!upload_data ||
223 (request->method() != "POST" && request->method() != "PUT"))
224 return; // Need to exit without "out->Set(keys::kRequestBodyKey, ...);" .
226 base::DictionaryValue* request_body = new base::DictionaryValue();
227 out->Set(keys::kRequestBodyKey, request_body);
229 // Get the data presenters, ordered by how specific they are.
230 extensions::ParsedDataPresenter parsed_data_presenter(*request);
231 extensions::RawDataPresenter raw_data_presenter;
232 extensions::UploadDataPresenter* const presenters[] = {
233 &parsed_data_presenter, // 1: any parseable forms? (Specific to forms.)
234 &raw_data_presenter // 2: any data at all? (Non-specific.)
236 // Keys for the results of the corresponding presenters.
237 static const char* const kKeys[] = {
238 keys::kRequestBodyFormDataKey,
239 keys::kRequestBodyRawKey
242 const ScopedVector<net::UploadElementReader>* readers =
243 upload_data->GetElementReaders();
244 bool some_succeeded = false;
245 if (readers) {
246 for (size_t i = 0; !some_succeeded && i < arraysize(presenters); ++i) {
247 ScopedVector<net::UploadElementReader>::const_iterator reader;
248 for (reader = readers->begin(); reader != readers->end(); ++reader)
249 presenters[i]->FeedNext(**reader);
250 if (presenters[i]->Succeeded()) {
251 request_body->Set(kKeys[i], presenters[i]->Result().release());
252 some_succeeded = true;
256 if (!some_succeeded)
257 request_body->SetString(keys::kRequestBodyErrorKey, "Unknown error.");
260 // Converts a HttpHeaders dictionary to a |name|, |value| pair. Returns
261 // true if successful.
262 bool FromHeaderDictionary(const base::DictionaryValue* header_value,
263 std::string* name,
264 std::string* value) {
265 if (!header_value->GetString(keys::kHeaderNameKey, name))
266 return false;
268 // We require either a "value" or a "binaryValue" entry.
269 if (!(header_value->HasKey(keys::kHeaderValueKey) ^
270 header_value->HasKey(keys::kHeaderBinaryValueKey)))
271 return false;
273 if (header_value->HasKey(keys::kHeaderValueKey)) {
274 if (!header_value->GetString(keys::kHeaderValueKey, value)) {
275 return false;
277 } else if (header_value->HasKey(keys::kHeaderBinaryValueKey)) {
278 const base::ListValue* list = NULL;
279 if (!header_value->HasKey(keys::kHeaderBinaryValueKey)) {
280 *value = "";
281 } else if (!header_value->GetList(keys::kHeaderBinaryValueKey, &list) ||
282 !helpers::CharListToString(list, value)) {
283 return false;
286 return true;
289 // Creates a list of HttpHeaders (see the extension API JSON). If |headers| is
290 // NULL, the list is empty. Ownership is passed to the caller.
291 base::ListValue* GetResponseHeadersList(
292 const net::HttpResponseHeaders* headers) {
293 base::ListValue* headers_value = new base::ListValue();
294 if (headers) {
295 void* iter = NULL;
296 std::string name;
297 std::string value;
298 while (headers->EnumerateHeaderLines(&iter, &name, &value))
299 headers_value->Append(helpers::CreateHeaderDictionary(name, value));
301 return headers_value;
304 base::ListValue* GetRequestHeadersList(const net::HttpRequestHeaders& headers) {
305 base::ListValue* headers_value = new base::ListValue();
306 for (net::HttpRequestHeaders::Iterator it(headers); it.GetNext(); )
307 headers_value->Append(
308 helpers::CreateHeaderDictionary(it.name(), it.value()));
309 return headers_value;
312 // Creates a base::StringValue with the status line of |headers|. If |headers|
313 // is NULL, an empty string is returned. Ownership is passed to the caller.
314 base::StringValue* GetStatusLine(net::HttpResponseHeaders* headers) {
315 return new base::StringValue(
316 headers ? headers->GetStatusLine() : std::string());
319 void RemoveEventListenerOnUI(
320 void* browser_context_id,
321 const std::string& event_name,
322 int process_id,
323 const std::string& extension_id) {
324 DCHECK_CURRENTLY_ON(BrowserThread::UI);
326 content::BrowserContext* browser_context =
327 reinterpret_cast<content::BrowserContext*>(browser_context_id);
328 if (!extensions::ExtensionsBrowserClient::Get()->IsValidContext(
329 browser_context))
330 return;
332 extensions::EventRouter* event_router =
333 extensions::EventRouter::Get(browser_context);
334 if (!event_router)
335 return;
337 content::RenderProcessHost* process =
338 content::RenderProcessHost::FromID(process_id);
339 if (!process)
340 return;
342 event_router->RemoveEventListener(event_name, process, extension_id);
345 // Sends an event to subscribers of chrome.declarativeWebRequest.onMessage or
346 // to subscribers of webview.onMessage if the action is being operated upon
347 // a <webview> guest renderer.
348 // |extension_id| identifies the extension that sends and receives the event.
349 // |is_web_view_guest| indicates whether the action is for a <webview>.
350 // |web_view_info| is a struct containing information about the <webview>
351 // embedder.
352 // |event_argument| is passed to the event listener.
353 void SendOnMessageEventOnUI(
354 void* browser_context_id,
355 const std::string& extension_id,
356 bool is_web_view_guest,
357 const extensions::WebViewRendererState::WebViewInfo& web_view_info,
358 scoped_ptr<base::DictionaryValue> event_argument) {
359 DCHECK_CURRENTLY_ON(BrowserThread::UI);
361 content::BrowserContext* browser_context =
362 reinterpret_cast<content::BrowserContext*>(browser_context_id);
363 if (!extensions::ExtensionsBrowserClient::Get()->IsValidContext(
364 browser_context))
365 return;
367 scoped_ptr<base::ListValue> event_args(new base::ListValue);
368 event_args->Append(event_argument.release());
370 extensions::EventRouter* event_router =
371 extensions::EventRouter::Get(browser_context);
373 extensions::EventFilteringInfo event_filtering_info;
375 std::string event_name;
376 // The instance ID uniquely identifies a <webview> instance within an embedder
377 // process. We use a filter here so that only event listeners for a particular
378 // <webview> will fire.
379 if (is_web_view_guest) {
380 event_filtering_info.SetInstanceID(web_view_info.instance_id);
381 event_name = webview::kEventMessage;
382 } else {
383 event_name = declarative_keys::kOnMessage;
386 scoped_ptr<extensions::Event> event(new extensions::Event(
387 event_name,
388 event_args.Pass(), browser_context, GURL(),
389 extensions::EventRouter::USER_GESTURE_UNKNOWN,
390 event_filtering_info));
391 event_router->DispatchEventToExtension(extension_id, event.Pass());
394 void RemoveEventListenerOnIOThread(
395 content::BrowserContext* browser_context,
396 const std::string& extension_id,
397 const std::string& sub_event_name) {
398 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(
399 browser_context, extension_id, sub_event_name);
402 } // namespace
404 namespace extensions {
406 WebRequestAPI::WebRequestAPI(content::BrowserContext* context)
407 : browser_context_(context) {
408 EventRouter* event_router = EventRouter::Get(browser_context_);
409 for (size_t i = 0; i < arraysize(kWebRequestEvents); ++i) {
410 // Observe the webRequest event.
411 std::string event_name = kWebRequestEvents[i];
412 event_router->RegisterObserver(this, event_name);
414 // Also observe the corresponding webview event.
415 event_name.replace(
416 0, sizeof(kWebRequestEventPrefix) - 1, webview::kWebViewEventPrefix);
417 event_router->RegisterObserver(this, event_name);
421 WebRequestAPI::~WebRequestAPI() {
422 EventRouter::Get(browser_context_)->UnregisterObserver(this);
425 static base::LazyInstance<BrowserContextKeyedAPIFactory<WebRequestAPI> >
426 g_factory = LAZY_INSTANCE_INITIALIZER;
428 // static
429 BrowserContextKeyedAPIFactory<WebRequestAPI>*
430 WebRequestAPI::GetFactoryInstance() {
431 return g_factory.Pointer();
434 void WebRequestAPI::OnListenerRemoved(const EventListenerInfo& details) {
435 DCHECK_CURRENTLY_ON(BrowserThread::UI);
436 // Note that details.event_name includes the sub-event details (e.g. "/123").
437 BrowserThread::PostTask(BrowserThread::IO,
438 FROM_HERE,
439 base::Bind(&RemoveEventListenerOnIOThread,
440 details.browser_context,
441 details.extension_id,
442 details.event_name));
445 } // namespace extensions
447 // Represents a single unique listener to an event, along with whatever filter
448 // parameters and extra_info_spec were specified at the time the listener was
449 // added.
450 // NOTE(benjhayden) New APIs should not use this sub_event_name trick! It does
451 // not play well with event pages. See downloads.onDeterminingFilename and
452 // ExtensionDownloadsEventRouter for an alternative approach.
453 struct ExtensionWebRequestEventRouter::EventListener {
454 std::string extension_id;
455 std::string extension_name;
456 std::string sub_event_name;
457 RequestFilter filter;
458 int extra_info_spec;
459 int embedder_process_id;
460 int webview_instance_id;
461 base::WeakPtr<IPC::Sender> ipc_sender;
462 mutable std::set<uint64> blocked_requests;
464 // Comparator to work with std::set.
465 bool operator<(const EventListener& that) const {
466 if (extension_id < that.extension_id)
467 return true;
468 if (extension_id == that.extension_id &&
469 sub_event_name < that.sub_event_name)
470 return true;
471 return false;
474 EventListener() : extra_info_spec(0) {}
477 // Contains info about requests that are blocked waiting for a response from
478 // an extension.
479 struct ExtensionWebRequestEventRouter::BlockedRequest {
480 // The request that is being blocked.
481 net::URLRequest* request;
483 // Whether the request originates from an incognito tab.
484 bool is_incognito;
486 // The event that we're currently blocked on.
487 EventTypes event;
489 // The number of event handlers that we are awaiting a response from.
490 int num_handlers_blocking;
492 // Pointer to NetLog to report significant changes to the request for
493 // debugging.
494 const net::BoundNetLog* net_log;
496 // The callback to call when we get a response from all event handlers.
497 net::CompletionCallback callback;
499 // If non-empty, this contains the new URL that the request will redirect to.
500 // Only valid for OnBeforeRequest and OnHeadersReceived.
501 GURL* new_url;
503 // The request headers that will be issued along with this request. Only valid
504 // for OnBeforeSendHeaders.
505 net::HttpRequestHeaders* request_headers;
507 // The response headers that were received from the server. Only valid for
508 // OnHeadersReceived.
509 scoped_refptr<const net::HttpResponseHeaders> original_response_headers;
511 // Location where to override response headers. Only valid for
512 // OnHeadersReceived.
513 scoped_refptr<net::HttpResponseHeaders>* override_response_headers;
515 // If non-empty, this contains the auth credentials that may be filled in.
516 // Only valid for OnAuthRequired.
517 net::AuthCredentials* auth_credentials;
519 // The callback to invoke for auth. If |auth_callback.is_null()| is false,
520 // |callback| must be NULL.
521 // Only valid for OnAuthRequired.
522 net::NetworkDelegate::AuthCallback auth_callback;
524 // Time the request was paused. Used for logging purposes.
525 base::Time blocking_time;
527 // Changes requested by extensions.
528 helpers::EventResponseDeltas response_deltas;
530 // Provider of meta data about extensions, only used and non-NULL for events
531 // that are delayed until the rules registry is ready.
532 InfoMap* extension_info_map;
534 BlockedRequest()
535 : request(NULL),
536 is_incognito(false),
537 event(kInvalidEvent),
538 num_handlers_blocking(0),
539 net_log(NULL),
540 new_url(NULL),
541 request_headers(NULL),
542 override_response_headers(NULL),
543 auth_credentials(NULL),
544 extension_info_map(NULL) {}
547 bool ExtensionWebRequestEventRouter::RequestFilter::InitFromValue(
548 const base::DictionaryValue& value, std::string* error) {
549 if (!value.HasKey("urls"))
550 return false;
552 for (base::DictionaryValue::Iterator it(value); !it.IsAtEnd(); it.Advance()) {
553 if (it.key() == "urls") {
554 const base::ListValue* urls_value = NULL;
555 if (!it.value().GetAsList(&urls_value))
556 return false;
557 for (size_t i = 0; i < urls_value->GetSize(); ++i) {
558 std::string url;
559 URLPattern pattern(
560 URLPattern::SCHEME_HTTP | URLPattern::SCHEME_HTTPS |
561 URLPattern::SCHEME_FTP | URLPattern::SCHEME_FILE |
562 URLPattern::SCHEME_EXTENSION);
563 if (!urls_value->GetString(i, &url) ||
564 pattern.Parse(url) != URLPattern::PARSE_SUCCESS) {
565 *error = ErrorUtils::FormatErrorMessage(
566 keys::kInvalidRequestFilterUrl, url);
567 return false;
569 urls.AddPattern(pattern);
571 } else if (it.key() == "types") {
572 const base::ListValue* types_value = NULL;
573 if (!it.value().GetAsList(&types_value))
574 return false;
575 for (size_t i = 0; i < types_value->GetSize(); ++i) {
576 std::string type_str;
577 ResourceType type;
578 if (!types_value->GetString(i, &type_str) ||
579 !helpers::ParseResourceType(type_str, &type))
580 return false;
581 types.push_back(type);
583 } else if (it.key() == "tabId") {
584 if (!it.value().GetAsInteger(&tab_id))
585 return false;
586 } else if (it.key() == "windowId") {
587 if (!it.value().GetAsInteger(&window_id))
588 return false;
589 } else {
590 return false;
593 return true;
596 // static
597 bool ExtensionWebRequestEventRouter::ExtraInfoSpec::InitFromValue(
598 const base::ListValue& value, int* extra_info_spec) {
599 *extra_info_spec = 0;
600 for (size_t i = 0; i < value.GetSize(); ++i) {
601 std::string str;
602 if (!value.GetString(i, &str))
603 return false;
605 if (str == "requestHeaders")
606 *extra_info_spec |= REQUEST_HEADERS;
607 else if (str == "responseHeaders")
608 *extra_info_spec |= RESPONSE_HEADERS;
609 else if (str == "blocking")
610 *extra_info_spec |= BLOCKING;
611 else if (str == "asyncBlocking")
612 *extra_info_spec |= ASYNC_BLOCKING;
613 else if (str == "requestBody")
614 *extra_info_spec |= REQUEST_BODY;
615 else
616 return false;
618 // BLOCKING and ASYNC_BLOCKING are mutually exclusive.
619 if ((*extra_info_spec & BLOCKING) && (*extra_info_spec & ASYNC_BLOCKING))
620 return false;
622 return true;
626 ExtensionWebRequestEventRouter::EventResponse::EventResponse(
627 const std::string& extension_id, const base::Time& extension_install_time)
628 : extension_id(extension_id),
629 extension_install_time(extension_install_time),
630 cancel(false) {
633 ExtensionWebRequestEventRouter::EventResponse::~EventResponse() {
636 ExtensionWebRequestEventRouter::RequestFilter::RequestFilter()
637 : tab_id(-1), window_id(-1) {
640 ExtensionWebRequestEventRouter::RequestFilter::~RequestFilter() {
644 // ExtensionWebRequestEventRouter
647 // static
648 ExtensionWebRequestEventRouter* ExtensionWebRequestEventRouter::GetInstance() {
649 return Singleton<ExtensionWebRequestEventRouter>::get();
652 ExtensionWebRequestEventRouter::ExtensionWebRequestEventRouter()
653 : request_time_tracker_(new ExtensionWebRequestTimeTracker) {
654 web_request_event_router_delegate_.reset(
655 extensions::ExtensionsAPIClient::Get()->
656 CreateWebRequestEventRouterDelegate());
659 ExtensionWebRequestEventRouter::~ExtensionWebRequestEventRouter() {
662 void ExtensionWebRequestEventRouter::RegisterRulesRegistry(
663 void* browser_context,
664 const extensions::RulesRegistry::WebViewKey& webview_key,
665 scoped_refptr<extensions::WebRequestRulesRegistry> rules_registry) {
666 RulesRegistryKey key(browser_context, webview_key);
667 if (rules_registry.get())
668 rules_registries_[key] = rules_registry;
669 else
670 rules_registries_.erase(key);
673 void ExtensionWebRequestEventRouter::ExtractRequestInfo(
674 net::URLRequest* request, base::DictionaryValue* out) {
675 bool is_main_frame = false;
676 int frame_id = -1;
677 bool parent_is_main_frame = false;
678 int parent_frame_id = -1;
679 int frame_id_for_extension = -1;
680 int parent_frame_id_for_extension = -1;
681 int render_process_host_id = -1;
682 int routing_id = -1;
683 ResourceType resource_type = content::RESOURCE_TYPE_LAST_TYPE;
684 ExtractRequestInfoDetails(request, &is_main_frame, &frame_id,
685 &parent_is_main_frame, &parent_frame_id,
686 &render_process_host_id, &routing_id,
687 &resource_type);
688 frame_id_for_extension = GetFrameId(is_main_frame, frame_id);
689 parent_frame_id_for_extension = GetFrameId(parent_is_main_frame,
690 parent_frame_id);
692 out->SetString(keys::kRequestIdKey,
693 base::Uint64ToString(request->identifier()));
694 out->SetString(keys::kUrlKey, request->url().spec());
695 out->SetString(keys::kMethodKey, request->method());
696 out->SetInteger(keys::kFrameIdKey, frame_id_for_extension);
697 out->SetInteger(keys::kParentFrameIdKey, parent_frame_id_for_extension);
698 out->SetString(keys::kTypeKey, helpers::ResourceTypeToString(resource_type));
699 out->SetDouble(keys::kTimeStampKey, base::Time::Now().ToDoubleT() * 1000);
700 if (web_request_event_router_delegate_) {
701 web_request_event_router_delegate_->ExtractExtraRequestDetails(
702 request, out);
706 int ExtensionWebRequestEventRouter::OnBeforeRequest(
707 void* browser_context,
708 InfoMap* extension_info_map,
709 net::URLRequest* request,
710 const net::CompletionCallback& callback,
711 GURL* new_url) {
712 // We hide events from the system context as well as sensitive requests.
713 if (!browser_context ||
714 WebRequestPermissions::HideRequest(extension_info_map, request))
715 return net::OK;
717 if (IsPageLoad(request))
718 NotifyPageLoad();
720 request_time_tracker_->LogRequestStartTime(request->identifier(),
721 base::Time::Now(),
722 request->url(),
723 browser_context);
725 // Whether to initialized blocked_requests_.
726 bool initialize_blocked_requests = false;
728 initialize_blocked_requests |=
729 ProcessDeclarativeRules(browser_context, extension_info_map,
730 web_request::OnBeforeRequest::kEventName, request,
731 extensions::ON_BEFORE_REQUEST, NULL);
733 int extra_info_spec = 0;
734 std::vector<const EventListener*> listeners =
735 GetMatchingListeners(browser_context, extension_info_map,
736 web_request::OnBeforeRequest::kEventName, request,
737 &extra_info_spec);
738 if (!listeners.empty() &&
739 !GetAndSetSignaled(request->identifier(), kOnBeforeRequest)) {
740 base::ListValue args;
741 base::DictionaryValue* dict = new base::DictionaryValue();
742 ExtractRequestInfo(request, dict);
743 if (extra_info_spec & ExtraInfoSpec::REQUEST_BODY)
744 ExtractRequestInfoBody(request, dict);
745 args.Append(dict);
747 initialize_blocked_requests |=
748 DispatchEvent(browser_context, request, listeners, args);
751 if (!initialize_blocked_requests)
752 return net::OK; // Nobody saw a reason for modifying the request.
754 blocked_requests_[request->identifier()].event = kOnBeforeRequest;
755 blocked_requests_[request->identifier()].is_incognito |=
756 IsIncognitoBrowserContext(browser_context);
757 blocked_requests_[request->identifier()].request = request;
758 blocked_requests_[request->identifier()].callback = callback;
759 blocked_requests_[request->identifier()].new_url = new_url;
760 blocked_requests_[request->identifier()].net_log = &request->net_log();
762 if (blocked_requests_[request->identifier()].num_handlers_blocking == 0) {
763 // If there are no blocking handlers, only the declarative rules tried
764 // to modify the request and we can respond synchronously.
765 return ExecuteDeltas(browser_context, request->identifier(),
766 false /* call_callback*/);
767 } else {
768 return net::ERR_IO_PENDING;
772 int ExtensionWebRequestEventRouter::OnBeforeSendHeaders(
773 void* browser_context,
774 InfoMap* extension_info_map,
775 net::URLRequest* request,
776 const net::CompletionCallback& callback,
777 net::HttpRequestHeaders* headers) {
778 // We hide events from the system context as well as sensitive requests.
779 if (!browser_context ||
780 WebRequestPermissions::HideRequest(extension_info_map, request))
781 return net::OK;
783 bool initialize_blocked_requests = false;
785 initialize_blocked_requests |=
786 ProcessDeclarativeRules(browser_context, extension_info_map,
787 keys::kOnBeforeSendHeadersEvent, request,
788 extensions::ON_BEFORE_SEND_HEADERS, NULL);
790 int extra_info_spec = 0;
791 std::vector<const EventListener*> listeners =
792 GetMatchingListeners(browser_context, extension_info_map,
793 keys::kOnBeforeSendHeadersEvent, request,
794 &extra_info_spec);
795 if (!listeners.empty() &&
796 !GetAndSetSignaled(request->identifier(), kOnBeforeSendHeaders)) {
797 base::ListValue args;
798 base::DictionaryValue* dict = new base::DictionaryValue();
799 ExtractRequestInfo(request, dict);
800 if (extra_info_spec & ExtraInfoSpec::REQUEST_HEADERS)
801 dict->Set(keys::kRequestHeadersKey, GetRequestHeadersList(*headers));
802 args.Append(dict);
804 initialize_blocked_requests |=
805 DispatchEvent(browser_context, request, listeners, args);
808 if (!initialize_blocked_requests)
809 return net::OK; // Nobody saw a reason for modifying the request.
811 blocked_requests_[request->identifier()].event = kOnBeforeSendHeaders;
812 blocked_requests_[request->identifier()].is_incognito |=
813 IsIncognitoBrowserContext(browser_context);
814 blocked_requests_[request->identifier()].request = request;
815 blocked_requests_[request->identifier()].callback = callback;
816 blocked_requests_[request->identifier()].request_headers = headers;
817 blocked_requests_[request->identifier()].net_log = &request->net_log();
819 if (blocked_requests_[request->identifier()].num_handlers_blocking == 0) {
820 // If there are no blocking handlers, only the declarative rules tried
821 // to modify the request and we can respond synchronously.
822 return ExecuteDeltas(browser_context, request->identifier(),
823 false /* call_callback*/);
824 } else {
825 return net::ERR_IO_PENDING;
829 void ExtensionWebRequestEventRouter::OnSendHeaders(
830 void* browser_context,
831 InfoMap* extension_info_map,
832 net::URLRequest* request,
833 const net::HttpRequestHeaders& headers) {
834 // We hide events from the system context as well as sensitive requests.
835 if (!browser_context ||
836 WebRequestPermissions::HideRequest(extension_info_map, request))
837 return;
839 if (GetAndSetSignaled(request->identifier(), kOnSendHeaders))
840 return;
842 ClearSignaled(request->identifier(), kOnBeforeRedirect);
844 int extra_info_spec = 0;
845 std::vector<const EventListener*> listeners =
846 GetMatchingListeners(browser_context, extension_info_map,
847 keys::kOnSendHeadersEvent, request,
848 &extra_info_spec);
849 if (listeners.empty())
850 return;
852 base::ListValue args;
853 base::DictionaryValue* dict = new base::DictionaryValue();
854 ExtractRequestInfo(request, dict);
855 if (extra_info_spec & ExtraInfoSpec::REQUEST_HEADERS)
856 dict->Set(keys::kRequestHeadersKey, GetRequestHeadersList(headers));
857 args.Append(dict);
859 DispatchEvent(browser_context, request, listeners, args);
862 int ExtensionWebRequestEventRouter::OnHeadersReceived(
863 void* browser_context,
864 InfoMap* extension_info_map,
865 net::URLRequest* request,
866 const net::CompletionCallback& callback,
867 const net::HttpResponseHeaders* original_response_headers,
868 scoped_refptr<net::HttpResponseHeaders>* override_response_headers,
869 GURL* allowed_unsafe_redirect_url) {
870 // We hide events from the system context as well as sensitive requests.
871 if (!browser_context ||
872 WebRequestPermissions::HideRequest(extension_info_map, request))
873 return net::OK;
875 bool initialize_blocked_requests = false;
877 initialize_blocked_requests |=
878 ProcessDeclarativeRules(browser_context, extension_info_map,
879 keys::kOnHeadersReceivedEvent, request,
880 extensions::ON_HEADERS_RECEIVED,
881 original_response_headers);
883 int extra_info_spec = 0;
884 std::vector<const EventListener*> listeners =
885 GetMatchingListeners(browser_context, extension_info_map,
886 keys::kOnHeadersReceivedEvent, request,
887 &extra_info_spec);
889 if (!listeners.empty() &&
890 !GetAndSetSignaled(request->identifier(), kOnHeadersReceived)) {
891 base::ListValue args;
892 base::DictionaryValue* dict = new base::DictionaryValue();
893 ExtractRequestInfo(request, dict);
894 dict->SetString(keys::kStatusLineKey,
895 original_response_headers->GetStatusLine());
896 if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
897 dict->Set(keys::kResponseHeadersKey,
898 GetResponseHeadersList(original_response_headers));
900 args.Append(dict);
902 initialize_blocked_requests |=
903 DispatchEvent(browser_context, request, listeners, args);
906 if (!initialize_blocked_requests)
907 return net::OK; // Nobody saw a reason for modifying the request.
909 blocked_requests_[request->identifier()].event = kOnHeadersReceived;
910 blocked_requests_[request->identifier()].is_incognito |=
911 IsIncognitoBrowserContext(browser_context);
912 blocked_requests_[request->identifier()].request = request;
913 blocked_requests_[request->identifier()].callback = callback;
914 blocked_requests_[request->identifier()].net_log = &request->net_log();
915 blocked_requests_[request->identifier()].override_response_headers =
916 override_response_headers;
917 blocked_requests_[request->identifier()].original_response_headers =
918 original_response_headers;
919 blocked_requests_[request->identifier()].new_url =
920 allowed_unsafe_redirect_url;
922 if (blocked_requests_[request->identifier()].num_handlers_blocking == 0) {
923 // If there are no blocking handlers, only the declarative rules tried
924 // to modify the request and we can respond synchronously.
925 return ExecuteDeltas(browser_context, request->identifier(),
926 false /* call_callback*/);
927 } else {
928 return net::ERR_IO_PENDING;
932 net::NetworkDelegate::AuthRequiredResponse
933 ExtensionWebRequestEventRouter::OnAuthRequired(
934 void* browser_context,
935 InfoMap* extension_info_map,
936 net::URLRequest* request,
937 const net::AuthChallengeInfo& auth_info,
938 const net::NetworkDelegate::AuthCallback& callback,
939 net::AuthCredentials* credentials) {
940 // No browser_context means that this is for authentication challenges in the
941 // system context. Skip in that case. Also skip sensitive requests.
942 if (!browser_context ||
943 WebRequestPermissions::HideRequest(extension_info_map, request))
944 return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION;
946 int extra_info_spec = 0;
947 std::vector<const EventListener*> listeners =
948 GetMatchingListeners(browser_context, extension_info_map,
949 keys::kOnAuthRequiredEvent, request,
950 &extra_info_spec);
951 if (listeners.empty())
952 return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION;
954 base::ListValue args;
955 base::DictionaryValue* dict = new base::DictionaryValue();
956 ExtractRequestInfo(request, dict);
957 dict->SetBoolean(keys::kIsProxyKey, auth_info.is_proxy);
958 if (!auth_info.scheme.empty())
959 dict->SetString(keys::kSchemeKey, auth_info.scheme);
960 if (!auth_info.realm.empty())
961 dict->SetString(keys::kRealmKey, auth_info.realm);
962 base::DictionaryValue* challenger = new base::DictionaryValue();
963 challenger->SetString(keys::kHostKey, auth_info.challenger.host());
964 challenger->SetInteger(keys::kPortKey, auth_info.challenger.port());
965 dict->Set(keys::kChallengerKey, challenger);
966 dict->Set(keys::kStatusLineKey, GetStatusLine(request->response_headers()));
967 if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
968 dict->Set(keys::kResponseHeadersKey,
969 GetResponseHeadersList(request->response_headers()));
971 args.Append(dict);
973 if (DispatchEvent(browser_context, request, listeners, args)) {
974 blocked_requests_[request->identifier()].event = kOnAuthRequired;
975 blocked_requests_[request->identifier()].is_incognito |=
976 IsIncognitoBrowserContext(browser_context);
977 blocked_requests_[request->identifier()].request = request;
978 blocked_requests_[request->identifier()].auth_callback = callback;
979 blocked_requests_[request->identifier()].auth_credentials = credentials;
980 blocked_requests_[request->identifier()].net_log = &request->net_log();
981 return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_IO_PENDING;
983 return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION;
986 void ExtensionWebRequestEventRouter::OnBeforeRedirect(
987 void* browser_context,
988 InfoMap* extension_info_map,
989 net::URLRequest* request,
990 const GURL& new_location) {
991 // We hide events from the system context as well as sensitive requests.
992 if (!browser_context ||
993 WebRequestPermissions::HideRequest(extension_info_map, request))
994 return;
996 if (GetAndSetSignaled(request->identifier(), kOnBeforeRedirect))
997 return;
999 ClearSignaled(request->identifier(), kOnBeforeRequest);
1000 ClearSignaled(request->identifier(), kOnBeforeSendHeaders);
1001 ClearSignaled(request->identifier(), kOnSendHeaders);
1002 ClearSignaled(request->identifier(), kOnHeadersReceived);
1004 int extra_info_spec = 0;
1005 std::vector<const EventListener*> listeners =
1006 GetMatchingListeners(browser_context, extension_info_map,
1007 keys::kOnBeforeRedirectEvent, request,
1008 &extra_info_spec);
1009 if (listeners.empty())
1010 return;
1012 int http_status_code = request->GetResponseCode();
1014 std::string response_ip = request->GetSocketAddress().host();
1016 base::ListValue args;
1017 base::DictionaryValue* dict = new base::DictionaryValue();
1018 ExtractRequestInfo(request, dict);
1019 dict->SetString(keys::kRedirectUrlKey, new_location.spec());
1020 dict->SetInteger(keys::kStatusCodeKey, http_status_code);
1021 if (!response_ip.empty())
1022 dict->SetString(keys::kIpKey, response_ip);
1023 dict->SetBoolean(keys::kFromCache, request->was_cached());
1024 dict->Set(keys::kStatusLineKey, GetStatusLine(request->response_headers()));
1025 if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
1026 dict->Set(keys::kResponseHeadersKey,
1027 GetResponseHeadersList(request->response_headers()));
1029 args.Append(dict);
1031 DispatchEvent(browser_context, request, listeners, args);
1034 void ExtensionWebRequestEventRouter::OnResponseStarted(
1035 void* browser_context,
1036 InfoMap* extension_info_map,
1037 net::URLRequest* request) {
1038 // We hide events from the system context as well as sensitive requests.
1039 if (!browser_context ||
1040 WebRequestPermissions::HideRequest(extension_info_map, request))
1041 return;
1043 // OnResponseStarted is even triggered, when the request was cancelled.
1044 if (request->status().status() != net::URLRequestStatus::SUCCESS)
1045 return;
1047 int extra_info_spec = 0;
1048 std::vector<const EventListener*> listeners =
1049 GetMatchingListeners(browser_context, extension_info_map,
1050 keys::kOnResponseStartedEvent, request,
1051 &extra_info_spec);
1052 if (listeners.empty())
1053 return;
1055 // UrlRequestFileJobs do not send headers, so we simulate their behavior.
1056 int response_code = 200;
1057 if (request->response_headers())
1058 response_code = request->response_headers()->response_code();
1060 std::string response_ip = request->GetSocketAddress().host();
1062 base::ListValue args;
1063 base::DictionaryValue* dict = new base::DictionaryValue();
1064 ExtractRequestInfo(request, dict);
1065 if (!response_ip.empty())
1066 dict->SetString(keys::kIpKey, response_ip);
1067 dict->SetBoolean(keys::kFromCache, request->was_cached());
1068 dict->SetInteger(keys::kStatusCodeKey, response_code);
1069 dict->Set(keys::kStatusLineKey, GetStatusLine(request->response_headers()));
1070 if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
1071 dict->Set(keys::kResponseHeadersKey,
1072 GetResponseHeadersList(request->response_headers()));
1074 args.Append(dict);
1076 DispatchEvent(browser_context, request, listeners, args);
1079 void ExtensionWebRequestEventRouter::OnCompleted(void* browser_context,
1080 InfoMap* extension_info_map,
1081 net::URLRequest* request) {
1082 // We hide events from the system context as well as sensitive requests.
1083 // However, if the request first became sensitive after redirecting we have
1084 // already signaled it and thus we have to signal the end of it. This is
1085 // risk-free because the handler cannot modify the request now.
1086 if (!browser_context ||
1087 (WebRequestPermissions::HideRequest(extension_info_map, request) &&
1088 !WasSignaled(*request)))
1089 return;
1091 request_time_tracker_->LogRequestEndTime(request->identifier(),
1092 base::Time::Now());
1094 DCHECK(request->status().status() == net::URLRequestStatus::SUCCESS);
1096 DCHECK(!GetAndSetSignaled(request->identifier(), kOnCompleted));
1098 ClearPendingCallbacks(request);
1100 int extra_info_spec = 0;
1101 std::vector<const EventListener*> listeners =
1102 GetMatchingListeners(browser_context, extension_info_map,
1103 keys::kOnCompletedEvent, request, &extra_info_spec);
1104 if (listeners.empty())
1105 return;
1107 // UrlRequestFileJobs do not send headers, so we simulate their behavior.
1108 int response_code = 200;
1109 if (request->response_headers())
1110 response_code = request->response_headers()->response_code();
1112 std::string response_ip = request->GetSocketAddress().host();
1114 base::ListValue args;
1115 base::DictionaryValue* dict = new base::DictionaryValue();
1116 ExtractRequestInfo(request, dict);
1117 dict->SetInteger(keys::kStatusCodeKey, response_code);
1118 if (!response_ip.empty())
1119 dict->SetString(keys::kIpKey, response_ip);
1120 dict->SetBoolean(keys::kFromCache, request->was_cached());
1121 dict->Set(keys::kStatusLineKey, GetStatusLine(request->response_headers()));
1122 if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
1123 dict->Set(keys::kResponseHeadersKey,
1124 GetResponseHeadersList(request->response_headers()));
1126 args.Append(dict);
1128 DispatchEvent(browser_context, request, listeners, args);
1131 void ExtensionWebRequestEventRouter::OnErrorOccurred(
1132 void* browser_context,
1133 InfoMap* extension_info_map,
1134 net::URLRequest* request,
1135 bool started) {
1136 // We hide events from the system context as well as sensitive requests.
1137 // However, if the request first became sensitive after redirecting we have
1138 // already signaled it and thus we have to signal the end of it. This is
1139 // risk-free because the handler cannot modify the request now.
1140 if (!browser_context ||
1141 (WebRequestPermissions::HideRequest(extension_info_map, request) &&
1142 !WasSignaled(*request)))
1143 return;
1145 request_time_tracker_->LogRequestEndTime(request->identifier(),
1146 base::Time::Now());
1148 DCHECK(request->status().status() == net::URLRequestStatus::FAILED ||
1149 request->status().status() == net::URLRequestStatus::CANCELED);
1151 DCHECK(!GetAndSetSignaled(request->identifier(), kOnErrorOccurred));
1153 ClearPendingCallbacks(request);
1155 int extra_info_spec = 0;
1156 std::vector<const EventListener*> listeners =
1157 GetMatchingListeners(browser_context, extension_info_map,
1158 web_request::OnErrorOccurred::kEventName, request,
1159 &extra_info_spec);
1160 if (listeners.empty())
1161 return;
1163 base::ListValue args;
1164 base::DictionaryValue* dict = new base::DictionaryValue();
1165 ExtractRequestInfo(request, dict);
1166 if (started) {
1167 std::string response_ip = request->GetSocketAddress().host();
1168 if (!response_ip.empty())
1169 dict->SetString(keys::kIpKey, response_ip);
1171 dict->SetBoolean(keys::kFromCache, request->was_cached());
1172 dict->SetString(keys::kErrorKey,
1173 net::ErrorToString(request->status().error()));
1174 args.Append(dict);
1176 DispatchEvent(browser_context, request, listeners, args);
1179 void ExtensionWebRequestEventRouter::OnURLRequestDestroyed(
1180 void* browser_context, net::URLRequest* request) {
1181 ClearPendingCallbacks(request);
1183 signaled_requests_.erase(request->identifier());
1185 request_time_tracker_->LogRequestEndTime(request->identifier(),
1186 base::Time::Now());
1189 void ExtensionWebRequestEventRouter::ClearPendingCallbacks(
1190 net::URLRequest* request) {
1191 blocked_requests_.erase(request->identifier());
1194 bool ExtensionWebRequestEventRouter::DispatchEvent(
1195 void* browser_context,
1196 net::URLRequest* request,
1197 const std::vector<const EventListener*>& listeners,
1198 const base::ListValue& args) {
1199 // TODO(mpcomplete): Consider consolidating common (extension_id,json_args)
1200 // pairs into a single message sent to a list of sub_event_names.
1201 int num_handlers_blocking = 0;
1202 for (std::vector<const EventListener*>::const_iterator it = listeners.begin();
1203 it != listeners.end(); ++it) {
1204 // Filter out the optional keys that this listener didn't request.
1205 scoped_ptr<base::ListValue> args_filtered(args.DeepCopy());
1206 base::DictionaryValue* dict = NULL;
1207 CHECK(args_filtered->GetDictionary(0, &dict) && dict);
1208 if (!((*it)->extra_info_spec & ExtraInfoSpec::REQUEST_HEADERS))
1209 dict->Remove(keys::kRequestHeadersKey, NULL);
1210 if (!((*it)->extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS))
1211 dict->Remove(keys::kResponseHeadersKey, NULL);
1213 extensions::EventRouter::DispatchEvent(
1214 (*it)->ipc_sender.get(), browser_context,
1215 (*it)->extension_id, (*it)->sub_event_name,
1216 args_filtered.Pass(),
1217 extensions::EventRouter::USER_GESTURE_UNKNOWN,
1218 extensions::EventFilteringInfo());
1219 if ((*it)->extra_info_spec &
1220 (ExtraInfoSpec::BLOCKING | ExtraInfoSpec::ASYNC_BLOCKING)) {
1221 (*it)->blocked_requests.insert(request->identifier());
1222 // If this is the first delegate blocking the request, go ahead and log
1223 // it.
1224 if (num_handlers_blocking == 0) {
1225 std::string delegate_info =
1226 l10n_util::GetStringFUTF8(IDS_LOAD_STATE_PARAMETER_EXTENSION,
1227 base::UTF8ToUTF16((*it)->extension_name));
1228 // LobAndReport allows extensions that block requests to be displayed in
1229 // the load status bar.
1230 request->LogAndReportBlockedBy(delegate_info.c_str());
1232 ++num_handlers_blocking;
1236 if (num_handlers_blocking > 0) {
1237 blocked_requests_[request->identifier()].request = request;
1238 blocked_requests_[request->identifier()].is_incognito |=
1239 IsIncognitoBrowserContext(browser_context);
1240 blocked_requests_[request->identifier()].num_handlers_blocking +=
1241 num_handlers_blocking;
1242 blocked_requests_[request->identifier()].blocking_time = base::Time::Now();
1244 return true;
1247 return false;
1250 void ExtensionWebRequestEventRouter::OnEventHandled(
1251 void* browser_context,
1252 const std::string& extension_id,
1253 const std::string& event_name,
1254 const std::string& sub_event_name,
1255 uint64 request_id,
1256 EventResponse* response) {
1257 EventListener listener;
1258 listener.extension_id = extension_id;
1259 listener.sub_event_name = sub_event_name;
1261 // The listener may have been removed (e.g. due to the process going away)
1262 // before we got here.
1263 std::set<EventListener>::iterator found =
1264 listeners_[browser_context][event_name].find(listener);
1265 if (found != listeners_[browser_context][event_name].end())
1266 found->blocked_requests.erase(request_id);
1268 DecrementBlockCount(
1269 browser_context, extension_id, event_name, request_id, response);
1272 bool ExtensionWebRequestEventRouter::AddEventListener(
1273 void* browser_context,
1274 const std::string& extension_id,
1275 const std::string& extension_name,
1276 const std::string& event_name,
1277 const std::string& sub_event_name,
1278 const RequestFilter& filter,
1279 int extra_info_spec,
1280 int embedder_process_id,
1281 int webview_instance_id,
1282 base::WeakPtr<IPC::Sender> ipc_sender) {
1283 if (!IsWebRequestEvent(event_name))
1284 return false;
1286 EventListener listener;
1287 listener.extension_id = extension_id;
1288 listener.extension_name = extension_name;
1289 listener.sub_event_name = sub_event_name;
1290 listener.filter = filter;
1291 listener.extra_info_spec = extra_info_spec;
1292 listener.ipc_sender = ipc_sender;
1293 listener.embedder_process_id = embedder_process_id;
1294 listener.webview_instance_id = webview_instance_id;
1295 if (listener.webview_instance_id) {
1296 content::RecordAction(
1297 base::UserMetricsAction("WebView.WebRequest.AddListener"));
1300 if (listeners_[browser_context][event_name].count(listener) != 0u) {
1301 // This is likely an abuse of the API by a malicious extension.
1302 return false;
1304 listeners_[browser_context][event_name].insert(listener);
1305 return true;
1308 void ExtensionWebRequestEventRouter::RemoveEventListener(
1309 void* browser_context,
1310 const std::string& extension_id,
1311 const std::string& sub_event_name) {
1312 std::string event_name =
1313 extensions::EventRouter::GetBaseEventName(sub_event_name);
1314 DCHECK(IsWebRequestEvent(event_name));
1316 EventListener listener;
1317 listener.extension_id = extension_id;
1318 listener.sub_event_name = sub_event_name;
1320 // It's possible for AddEventListener to fail asynchronously. In that case,
1321 // the renderer believes the listener exists, while the browser does not.
1322 // Ignore a RemoveEventListener in that case.
1323 std::set<EventListener>::iterator found =
1324 listeners_[browser_context][event_name].find(listener);
1325 if (found == listeners_[browser_context][event_name].end())
1326 return;
1328 CHECK_EQ(listeners_[browser_context][event_name].count(listener), 1u) <<
1329 "extension=" << extension_id << " event=" << event_name;
1331 // Unblock any request that this event listener may have been blocking.
1332 for (std::set<uint64>::iterator it = found->blocked_requests.begin();
1333 it != found->blocked_requests.end(); ++it) {
1334 DecrementBlockCount(browser_context, extension_id, event_name, *it, NULL);
1337 listeners_[browser_context][event_name].erase(listener);
1339 helpers::ClearCacheOnNavigation();
1342 void ExtensionWebRequestEventRouter::RemoveWebViewEventListeners(
1343 void* browser_context,
1344 const std::string& extension_id,
1345 int embedder_process_id,
1346 int webview_instance_id) {
1347 // Iterate over all listeners of all WebRequest events to delete
1348 // any listeners that belong to the provided <webview>.
1349 ListenerMapForBrowserContext& map_for_browser_context =
1350 listeners_[browser_context];
1351 for (ListenerMapForBrowserContext::iterator event_iter =
1352 map_for_browser_context.begin();
1353 event_iter != map_for_browser_context.end(); ++event_iter) {
1354 std::vector<EventListener> listeners_to_delete;
1355 std::set<EventListener>& listeners = event_iter->second;
1356 for (std::set<EventListener>::iterator listener_iter = listeners.begin();
1357 listener_iter != listeners.end(); ++listener_iter) {
1358 const EventListener& listener = *listener_iter;
1359 if (listener.embedder_process_id == embedder_process_id &&
1360 listener.webview_instance_id == webview_instance_id)
1361 listeners_to_delete.push_back(listener);
1363 for (size_t i = 0; i < listeners_to_delete.size(); ++i) {
1364 EventListener& listener = listeners_to_delete[i];
1365 content::BrowserThread::PostTask(
1366 content::BrowserThread::UI,
1367 FROM_HERE,
1368 base::Bind(&RemoveEventListenerOnUI,
1369 browser_context,
1370 listener.sub_event_name,
1371 embedder_process_id,
1372 extension_id));
1377 void ExtensionWebRequestEventRouter::OnOTRBrowserContextCreated(
1378 void* original_browser_context, void* otr_browser_context) {
1379 cross_browser_context_map_[original_browser_context] =
1380 std::make_pair(false, otr_browser_context);
1381 cross_browser_context_map_[otr_browser_context] =
1382 std::make_pair(true, original_browser_context);
1385 void ExtensionWebRequestEventRouter::OnOTRBrowserContextDestroyed(
1386 void* original_browser_context, void* otr_browser_context) {
1387 cross_browser_context_map_.erase(otr_browser_context);
1388 cross_browser_context_map_.erase(original_browser_context);
1391 void ExtensionWebRequestEventRouter::AddCallbackForPageLoad(
1392 const base::Closure& callback) {
1393 callbacks_for_page_load_.push_back(callback);
1396 bool ExtensionWebRequestEventRouter::IsPageLoad(
1397 net::URLRequest* request) const {
1398 bool is_main_frame = false;
1399 int frame_id = -1;
1400 bool parent_is_main_frame = false;
1401 int parent_frame_id = -1;
1402 int render_process_host_id = -1;
1403 int routing_id = -1;
1404 ResourceType resource_type = content::RESOURCE_TYPE_LAST_TYPE;
1406 ExtractRequestInfoDetails(request, &is_main_frame, &frame_id,
1407 &parent_is_main_frame, &parent_frame_id,
1408 &render_process_host_id,
1409 &routing_id, &resource_type);
1411 return resource_type == content::RESOURCE_TYPE_MAIN_FRAME;
1414 void ExtensionWebRequestEventRouter::NotifyPageLoad() {
1415 for (CallbacksForPageLoad::const_iterator i =
1416 callbacks_for_page_load_.begin();
1417 i != callbacks_for_page_load_.end(); ++i) {
1418 i->Run();
1420 callbacks_for_page_load_.clear();
1423 void* ExtensionWebRequestEventRouter::GetCrossBrowserContext(
1424 void* browser_context) const {
1425 CrossBrowserContextMap::const_iterator cross_browser_context =
1426 cross_browser_context_map_.find(browser_context);
1427 if (cross_browser_context == cross_browser_context_map_.end())
1428 return NULL;
1429 return cross_browser_context->second.second;
1432 bool ExtensionWebRequestEventRouter::IsIncognitoBrowserContext(
1433 void* browser_context) const {
1434 CrossBrowserContextMap::const_iterator cross_browser_context =
1435 cross_browser_context_map_.find(browser_context);
1436 if (cross_browser_context == cross_browser_context_map_.end())
1437 return false;
1438 return cross_browser_context->second.first;
1441 bool ExtensionWebRequestEventRouter::WasSignaled(
1442 const net::URLRequest& request) const {
1443 SignaledRequestMap::const_iterator flag =
1444 signaled_requests_.find(request.identifier());
1445 return (flag != signaled_requests_.end()) && (flag->second != 0);
1448 void ExtensionWebRequestEventRouter::GetMatchingListenersImpl(
1449 void* browser_context,
1450 net::URLRequest* request,
1451 InfoMap* extension_info_map,
1452 bool crosses_incognito,
1453 const std::string& event_name,
1454 const GURL& url,
1455 int render_process_host_id,
1456 int routing_id,
1457 ResourceType resource_type,
1458 bool is_async_request,
1459 bool is_request_from_extension,
1460 int* extra_info_spec,
1461 std::vector<const ExtensionWebRequestEventRouter::EventListener*>*
1462 matching_listeners) {
1463 std::string web_request_event_name(event_name);
1464 extensions::WebViewRendererState::WebViewInfo web_view_info;
1465 bool is_web_view_guest = extensions::WebViewRendererState::GetInstance()->
1466 GetInfo(render_process_host_id, routing_id, &web_view_info);
1467 if (is_web_view_guest) {
1468 web_request_event_name.replace(
1469 0, sizeof(kWebRequestEventPrefix) - 1, webview::kWebViewEventPrefix);
1472 std::set<EventListener>& listeners =
1473 listeners_[browser_context][web_request_event_name];
1474 for (std::set<EventListener>::iterator it = listeners.begin();
1475 it != listeners.end(); ++it) {
1476 if (!it->ipc_sender.get()) {
1477 // The IPC sender has been deleted. This listener will be removed soon
1478 // via a call to RemoveEventListener. For now, just skip it.
1479 continue;
1482 if (is_web_view_guest &&
1483 (it->embedder_process_id != web_view_info.embedder_process_id ||
1484 it->webview_instance_id != web_view_info.instance_id))
1485 continue;
1487 if (!it->filter.urls.is_empty() && !it->filter.urls.MatchesURL(url))
1488 continue;
1489 if (web_request_event_router_delegate_ &&
1490 web_request_event_router_delegate_->OnGetMatchingListenersImplCheck(
1491 it->filter.tab_id, it->filter.window_id, request))
1492 continue;
1493 if (!it->filter.types.empty() &&
1494 std::find(it->filter.types.begin(), it->filter.types.end(),
1495 resource_type) == it->filter.types.end())
1496 continue;
1498 if (!is_web_view_guest && !WebRequestPermissions::CanExtensionAccessURL(
1499 extension_info_map, it->extension_id, url, crosses_incognito,
1500 WebRequestPermissions::REQUIRE_HOST_PERMISSION))
1501 continue;
1503 bool blocking_listener =
1504 (it->extra_info_spec &
1505 (ExtraInfoSpec::BLOCKING | ExtraInfoSpec::ASYNC_BLOCKING)) != 0;
1507 // We do not want to notify extensions about XHR requests that are
1508 // triggered by themselves. This is a workaround to prevent deadlocks
1509 // in case of synchronous XHR requests that block the extension renderer
1510 // and therefore prevent the extension from processing the request
1511 // handler. This is only a problem for blocking listeners.
1512 // http://crbug.com/105656
1513 bool synchronous_xhr_from_extension =
1514 !is_async_request && is_request_from_extension &&
1515 resource_type == content::RESOURCE_TYPE_XHR;
1517 // Only send webRequest events for URLs the extension has access to.
1518 if (blocking_listener && synchronous_xhr_from_extension)
1519 continue;
1521 matching_listeners->push_back(&(*it));
1522 *extra_info_spec |= it->extra_info_spec;
1526 std::vector<const ExtensionWebRequestEventRouter::EventListener*>
1527 ExtensionWebRequestEventRouter::GetMatchingListeners(
1528 void* browser_context,
1529 InfoMap* extension_info_map,
1530 const std::string& event_name,
1531 net::URLRequest* request,
1532 int* extra_info_spec) {
1533 // TODO(mpcomplete): handle browser_context == NULL (should collect all
1534 // listeners).
1535 *extra_info_spec = 0;
1537 bool is_main_frame = false;
1538 int frame_id = -1;
1539 bool parent_is_main_frame = false;
1540 int parent_frame_id = -1;
1541 int render_process_host_id = -1;
1542 int routing_id = -1;
1543 ResourceType resource_type = content::RESOURCE_TYPE_LAST_TYPE;
1544 const GURL& url = request->url();
1546 ExtractRequestInfoDetails(request, &is_main_frame, &frame_id,
1547 &parent_is_main_frame, &parent_frame_id,
1548 &render_process_host_id,
1549 &routing_id, &resource_type);
1551 std::vector<const ExtensionWebRequestEventRouter::EventListener*>
1552 matching_listeners;
1554 bool is_request_from_extension =
1555 IsRequestFromExtension(request, extension_info_map);
1557 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
1558 // We are conservative here and assume requests are asynchronous in case
1559 // we don't have an info object. We don't want to risk a deadlock.
1560 bool is_async_request = !info || info->IsAsync();
1562 GetMatchingListenersImpl(
1563 browser_context, request, extension_info_map, false, event_name,
1564 url, render_process_host_id, routing_id, resource_type,
1565 is_async_request, is_request_from_extension, extra_info_spec,
1566 &matching_listeners);
1567 void* cross_browser_context = GetCrossBrowserContext(browser_context);
1568 if (cross_browser_context) {
1569 GetMatchingListenersImpl(
1570 cross_browser_context, request, extension_info_map, true, event_name,
1571 url, render_process_host_id, routing_id, resource_type,
1572 is_async_request, is_request_from_extension, extra_info_spec,
1573 &matching_listeners);
1576 return matching_listeners;
1579 namespace {
1581 helpers::EventResponseDelta* CalculateDelta(
1582 ExtensionWebRequestEventRouter::BlockedRequest* blocked_request,
1583 ExtensionWebRequestEventRouter::EventResponse* response) {
1584 switch (blocked_request->event) {
1585 case ExtensionWebRequestEventRouter::kOnBeforeRequest:
1586 return helpers::CalculateOnBeforeRequestDelta(
1587 response->extension_id, response->extension_install_time,
1588 response->cancel, response->new_url);
1589 case ExtensionWebRequestEventRouter::kOnBeforeSendHeaders: {
1590 net::HttpRequestHeaders* old_headers = blocked_request->request_headers;
1591 net::HttpRequestHeaders* new_headers = response->request_headers.get();
1592 return helpers::CalculateOnBeforeSendHeadersDelta(
1593 response->extension_id, response->extension_install_time,
1594 response->cancel, old_headers, new_headers);
1596 case ExtensionWebRequestEventRouter::kOnHeadersReceived: {
1597 const net::HttpResponseHeaders* old_headers =
1598 blocked_request->original_response_headers.get();
1599 helpers::ResponseHeaders* new_headers =
1600 response->response_headers.get();
1601 return helpers::CalculateOnHeadersReceivedDelta(
1602 response->extension_id,
1603 response->extension_install_time,
1604 response->cancel,
1605 response->new_url,
1606 old_headers,
1607 new_headers);
1609 case ExtensionWebRequestEventRouter::kOnAuthRequired:
1610 return helpers::CalculateOnAuthRequiredDelta(
1611 response->extension_id, response->extension_install_time,
1612 response->cancel, &response->auth_credentials);
1613 default:
1614 NOTREACHED();
1615 break;
1617 return NULL;
1620 base::Value* SerializeResponseHeaders(const helpers::ResponseHeaders& headers) {
1621 scoped_ptr<base::ListValue> serialized_headers(new base::ListValue());
1622 for (helpers::ResponseHeaders::const_iterator i = headers.begin();
1623 i != headers.end(); ++i) {
1624 serialized_headers->Append(
1625 helpers::CreateHeaderDictionary(i->first, i->second));
1627 return serialized_headers.release();
1630 // Convert a RequestCookieModifications/ResponseCookieModifications object to a
1631 // base::ListValue which summarizes the changes made. This is templated since
1632 // the two types (request/response) are different but contain essentially the
1633 // same fields.
1634 template<typename CookieType>
1635 base::ListValue* SummarizeCookieModifications(
1636 const std::vector<linked_ptr<CookieType> >& modifications) {
1637 scoped_ptr<base::ListValue> cookie_modifications(new base::ListValue());
1638 for (typename std::vector<linked_ptr<CookieType> >::const_iterator i =
1639 modifications.begin();
1640 i != modifications.end(); ++i) {
1641 scoped_ptr<base::DictionaryValue> summary(new base::DictionaryValue());
1642 const CookieType& mod = *i->get();
1643 switch (mod.type) {
1644 case helpers::ADD:
1645 summary->SetString(activitylog::kCookieModificationTypeKey,
1646 activitylog::kCookieModificationAdd);
1647 break;
1648 case helpers::EDIT:
1649 summary->SetString(activitylog::kCookieModificationTypeKey,
1650 activitylog::kCookieModificationEdit);
1651 break;
1652 case helpers::REMOVE:
1653 summary->SetString(activitylog::kCookieModificationTypeKey,
1654 activitylog::kCookieModificationRemove);
1655 break;
1657 if (mod.filter) {
1658 if (mod.filter->name)
1659 summary->SetString(activitylog::kCookieFilterNameKey,
1660 *mod.modification->name);
1661 if (mod.filter->domain)
1662 summary->SetString(activitylog::kCookieFilterDomainKey,
1663 *mod.modification->name);
1665 if (mod.modification) {
1666 if (mod.modification->name)
1667 summary->SetString(activitylog::kCookieModDomainKey,
1668 *mod.modification->name);
1669 if (mod.modification->domain)
1670 summary->SetString(activitylog::kCookieModDomainKey,
1671 *mod.modification->name);
1673 cookie_modifications->Append(summary.release());
1675 return cookie_modifications.release();
1678 // Converts an EventResponseDelta object to a dictionary value suitable for the
1679 // activity log.
1680 scoped_ptr<base::DictionaryValue> SummarizeResponseDelta(
1681 const std::string& event_name,
1682 const helpers::EventResponseDelta& delta) {
1683 scoped_ptr<base::DictionaryValue> details(new base::DictionaryValue());
1684 if (delta.cancel) {
1685 details->SetBoolean(activitylog::kCancelKey, true);
1687 if (!delta.new_url.is_empty()) {
1688 details->SetString(activitylog::kNewUrlKey, delta.new_url.spec());
1691 scoped_ptr<base::ListValue> modified_headers(new base::ListValue());
1692 net::HttpRequestHeaders::Iterator iter(delta.modified_request_headers);
1693 while (iter.GetNext()) {
1694 modified_headers->Append(
1695 helpers::CreateHeaderDictionary(iter.name(), iter.value()));
1697 if (!modified_headers->empty()) {
1698 details->Set(activitylog::kModifiedRequestHeadersKey,
1699 modified_headers.release());
1702 scoped_ptr<base::ListValue> deleted_headers(new base::ListValue());
1703 deleted_headers->AppendStrings(delta.deleted_request_headers);
1704 if (!deleted_headers->empty()) {
1705 details->Set(activitylog::kDeletedRequestHeadersKey,
1706 deleted_headers.release());
1709 if (!delta.added_response_headers.empty()) {
1710 details->Set(activitylog::kAddedRequestHeadersKey,
1711 SerializeResponseHeaders(delta.added_response_headers));
1713 if (!delta.deleted_response_headers.empty()) {
1714 details->Set(activitylog::kDeletedResponseHeadersKey,
1715 SerializeResponseHeaders(delta.deleted_response_headers));
1717 if (delta.auth_credentials) {
1718 details->SetString(activitylog::kAuthCredentialsKey,
1719 base::UTF16ToUTF8(
1720 delta.auth_credentials->username()) + ":*");
1723 if (!delta.response_cookie_modifications.empty()) {
1724 details->Set(
1725 activitylog::kResponseCookieModificationsKey,
1726 SummarizeCookieModifications(delta.response_cookie_modifications));
1729 return details.Pass();
1732 } // namespace
1734 void ExtensionWebRequestEventRouter::LogExtensionActivity(
1735 void* browser_context_id,
1736 bool is_incognito,
1737 const std::string& extension_id,
1738 const GURL& url,
1739 const std::string& api_call,
1740 scoped_ptr<base::DictionaryValue> details) {
1741 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
1742 BrowserThread::PostTask(
1743 BrowserThread::UI,
1744 FROM_HERE,
1745 base::Bind(&ExtensionWebRequestEventRouter::LogExtensionActivity,
1746 base::Unretained(this),
1747 browser_context_id,
1748 is_incognito,
1749 extension_id,
1750 url,
1751 api_call,
1752 base::Passed(&details)));
1753 } else {
1754 if (web_request_event_router_delegate_) {
1755 web_request_event_router_delegate_->LogExtensionActivity(
1756 reinterpret_cast<content::BrowserContext*>(browser_context_id),
1757 is_incognito, extension_id, url, api_call, details.Pass());
1762 void ExtensionWebRequestEventRouter::DecrementBlockCount(
1763 void* browser_context,
1764 const std::string& extension_id,
1765 const std::string& event_name,
1766 uint64 request_id,
1767 EventResponse* response) {
1768 scoped_ptr<EventResponse> response_scoped(response);
1770 // It's possible that this request was deleted, or cancelled by a previous
1771 // event handler. If so, ignore this response.
1772 if (blocked_requests_.find(request_id) == blocked_requests_.end())
1773 return;
1775 BlockedRequest& blocked_request = blocked_requests_[request_id];
1776 int num_handlers_blocking = --blocked_request.num_handlers_blocking;
1777 CHECK_GE(num_handlers_blocking, 0);
1779 if (response) {
1780 helpers::EventResponseDelta* delta =
1781 CalculateDelta(&blocked_request, response);
1783 LogExtensionActivity(browser_context,
1784 blocked_request.is_incognito,
1785 extension_id,
1786 blocked_request.request->url(),
1787 event_name,
1788 SummarizeResponseDelta(event_name, *delta));
1790 blocked_request.response_deltas.push_back(
1791 linked_ptr<helpers::EventResponseDelta>(delta));
1794 base::TimeDelta block_time =
1795 base::Time::Now() - blocked_request.blocking_time;
1796 if (!extension_id.empty()) {
1797 request_time_tracker_->IncrementExtensionBlockTime(
1798 extension_id, request_id, block_time);
1799 } else {
1800 // |extension_id| is empty for requests blocked on startup waiting for the
1801 // declarative rules to be read from disk.
1802 UMA_HISTOGRAM_TIMES("Extensions.NetworkDelayStartup", block_time);
1805 if (num_handlers_blocking == 0) {
1806 blocked_request.request->LogUnblocked();
1807 ExecuteDeltas(browser_context, request_id, true);
1808 } else {
1809 // Update the URLRequest to make sure it's tagged with an extension that's
1810 // still blocking it. This may end up being the same extension as before.
1811 std::set<EventListener>& listeners =
1812 listeners_[browser_context][event_name];
1814 for (std::set<EventListener>::iterator it = listeners.begin();
1815 it != listeners.end(); ++it) {
1816 if (it->blocked_requests.count(request_id) == 0)
1817 continue;
1818 std::string delegate_info =
1819 l10n_util::GetStringFUTF8(IDS_LOAD_STATE_PARAMETER_EXTENSION,
1820 base::UTF8ToUTF16(it->extension_name));
1821 blocked_request.request->LogAndReportBlockedBy(delegate_info.c_str());
1822 break;
1827 void ExtensionWebRequestEventRouter::SendMessages(
1828 void* browser_context,
1829 const BlockedRequest& blocked_request) {
1830 const helpers::EventResponseDeltas& deltas = blocked_request.response_deltas;
1831 for (helpers::EventResponseDeltas::const_iterator delta = deltas.begin();
1832 delta != deltas.end(); ++delta) {
1833 const std::set<std::string>& messages = (*delta)->messages_to_extension;
1834 for (std::set<std::string>::const_iterator message = messages.begin();
1835 message != messages.end(); ++message) {
1836 scoped_ptr<base::DictionaryValue> argument(new base::DictionaryValue);
1837 ExtractRequestInfo(blocked_request.request, argument.get());
1838 extensions::WebViewRendererState::WebViewInfo web_view_info;
1839 bool is_web_view_guest = GetWebViewInfo(blocked_request.request,
1840 &web_view_info);
1841 argument->SetString(keys::kMessageKey, *message);
1842 argument->SetString(keys::kStageKey,
1843 GetRequestStageAsString(blocked_request.event));
1845 BrowserThread::PostTask(
1846 BrowserThread::UI,
1847 FROM_HERE,
1848 base::Bind(&SendOnMessageEventOnUI,
1849 browser_context,
1850 (*delta)->extension_id,
1851 is_web_view_guest,
1852 web_view_info,
1853 base::Passed(&argument)));
1858 int ExtensionWebRequestEventRouter::ExecuteDeltas(
1859 void* browser_context,
1860 uint64 request_id,
1861 bool call_callback) {
1862 BlockedRequest& blocked_request = blocked_requests_[request_id];
1863 CHECK(blocked_request.num_handlers_blocking == 0);
1864 helpers::EventResponseDeltas& deltas = blocked_request.response_deltas;
1865 base::TimeDelta block_time =
1866 base::Time::Now() - blocked_request.blocking_time;
1867 request_time_tracker_->IncrementTotalBlockTime(request_id, block_time);
1869 bool credentials_set = false;
1871 deltas.sort(&helpers::InDecreasingExtensionInstallationTimeOrder);
1872 WarningSet warnings;
1874 bool canceled = false;
1875 helpers::MergeCancelOfResponses(
1876 blocked_request.response_deltas,
1877 &canceled,
1878 blocked_request.net_log);
1880 if (blocked_request.event == kOnBeforeRequest) {
1881 CHECK(!blocked_request.callback.is_null());
1882 helpers::MergeOnBeforeRequestResponses(
1883 blocked_request.response_deltas,
1884 blocked_request.new_url,
1885 &warnings,
1886 blocked_request.net_log);
1887 } else if (blocked_request.event == kOnBeforeSendHeaders) {
1888 CHECK(!blocked_request.callback.is_null());
1889 helpers::MergeOnBeforeSendHeadersResponses(
1890 blocked_request.response_deltas,
1891 blocked_request.request_headers,
1892 &warnings,
1893 blocked_request.net_log);
1894 } else if (blocked_request.event == kOnHeadersReceived) {
1895 CHECK(!blocked_request.callback.is_null());
1896 helpers::MergeOnHeadersReceivedResponses(
1897 blocked_request.response_deltas,
1898 blocked_request.original_response_headers.get(),
1899 blocked_request.override_response_headers,
1900 blocked_request.new_url,
1901 &warnings,
1902 blocked_request.net_log);
1903 } else if (blocked_request.event == kOnAuthRequired) {
1904 CHECK(blocked_request.callback.is_null());
1905 CHECK(!blocked_request.auth_callback.is_null());
1906 credentials_set = helpers::MergeOnAuthRequiredResponses(
1907 blocked_request.response_deltas,
1908 blocked_request.auth_credentials,
1909 &warnings,
1910 blocked_request.net_log);
1911 } else {
1912 NOTREACHED();
1915 SendMessages(browser_context, blocked_request);
1917 if (!warnings.empty()) {
1918 BrowserThread::PostTask(
1919 BrowserThread::UI,
1920 FROM_HERE,
1921 base::Bind(&WarningService::NotifyWarningsOnUI,
1922 browser_context, warnings));
1925 if (canceled) {
1926 request_time_tracker_->SetRequestCanceled(request_id);
1927 } else if (blocked_request.new_url &&
1928 !blocked_request.new_url->is_empty()) {
1929 request_time_tracker_->SetRequestRedirected(request_id);
1932 // This triggers onErrorOccurred if canceled is true.
1933 int rv = canceled ? net::ERR_BLOCKED_BY_CLIENT : net::OK;
1935 if (!blocked_request.callback.is_null()) {
1936 net::CompletionCallback callback = blocked_request.callback;
1937 // Ensure that request is removed before callback because the callback
1938 // might trigger the next event.
1939 blocked_requests_.erase(request_id);
1940 if (call_callback)
1941 callback.Run(rv);
1942 } else if (!blocked_request.auth_callback.is_null()) {
1943 net::NetworkDelegate::AuthRequiredResponse response =
1944 net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION;
1945 if (canceled) {
1946 response = net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_CANCEL_AUTH;
1947 } else if (credentials_set) {
1948 response = net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_SET_AUTH;
1950 net::NetworkDelegate::AuthCallback callback = blocked_request.auth_callback;
1951 blocked_requests_.erase(request_id);
1952 if (call_callback)
1953 callback.Run(response);
1954 } else {
1955 blocked_requests_.erase(request_id);
1957 return rv;
1960 bool ExtensionWebRequestEventRouter::ProcessDeclarativeRules(
1961 void* browser_context,
1962 InfoMap* extension_info_map,
1963 const std::string& event_name,
1964 net::URLRequest* request,
1965 extensions::RequestStage request_stage,
1966 const net::HttpResponseHeaders* original_response_headers) {
1967 extensions::WebViewRendererState::WebViewInfo web_view_info;
1968 bool is_web_view_guest = GetWebViewInfo(request, &web_view_info);
1970 extensions::RulesRegistry::WebViewKey webview_key(
1971 is_web_view_guest ? web_view_info.embedder_process_id : 0,
1972 is_web_view_guest ? web_view_info.instance_id : 0);
1973 RulesRegistryKey rules_key(browser_context, webview_key);
1974 // If this check fails, check that the active stages are up-to-date in
1975 // extensions/browser/api/declarative_webrequest/request_stage.h .
1976 DCHECK(request_stage & extensions::kActiveStages);
1978 // Rules of the current |browser_context| may apply but we need to check also
1979 // whether there are applicable rules from extensions whose background page
1980 // spans from regular to incognito mode.
1982 // First parameter identifies the registry, the second indicates whether the
1983 // registry belongs to the cross browser_context.
1984 typedef std::pair<extensions::WebRequestRulesRegistry*, bool>
1985 RelevantRegistry;
1986 typedef std::vector<RelevantRegistry> RelevantRegistries;
1987 RelevantRegistries relevant_registries;
1989 if (rules_registries_.find(rules_key) != rules_registries_.end()) {
1990 relevant_registries.push_back(
1991 std::make_pair(rules_registries_[rules_key].get(), false));
1994 void* cross_browser_context = GetCrossBrowserContext(browser_context);
1995 RulesRegistryKey cross_browser_context_rules_key(
1996 cross_browser_context, webview_key);
1997 if (cross_browser_context &&
1998 rules_registries_.find(cross_browser_context_rules_key) !=
1999 rules_registries_.end()) {
2000 relevant_registries.push_back(
2001 std::make_pair(
2002 rules_registries_[cross_browser_context_rules_key].get(), true));
2005 // The following block is experimentally enabled and its impact on load time
2006 // logged with UMA Extensions.NetworkDelayRegistryLoad. crbug.com/175961
2007 for (RelevantRegistries::iterator i = relevant_registries.begin();
2008 i != relevant_registries.end(); ++i) {
2009 extensions::WebRequestRulesRegistry* rules_registry = i->first;
2010 if (!rules_registry->ready().is_signaled()) {
2011 // The rules registry is still loading. Block this request until it
2012 // finishes.
2013 rules_registry->ready().Post(
2014 FROM_HERE,
2015 base::Bind(&ExtensionWebRequestEventRouter::OnRulesRegistryReady,
2016 AsWeakPtr(),
2017 browser_context,
2018 event_name,
2019 request->identifier(),
2020 request_stage));
2021 blocked_requests_[request->identifier()].num_handlers_blocking++;
2022 blocked_requests_[request->identifier()].request = request;
2023 blocked_requests_[request->identifier()].is_incognito |=
2024 IsIncognitoBrowserContext(browser_context);
2025 blocked_requests_[request->identifier()].blocking_time =
2026 base::Time::Now();
2027 blocked_requests_[request->identifier()].original_response_headers =
2028 original_response_headers;
2029 blocked_requests_[request->identifier()].extension_info_map =
2030 extension_info_map;
2031 return true;
2035 base::Time start = base::Time::Now();
2037 bool deltas_created = false;
2038 for (RelevantRegistries::iterator i = relevant_registries.begin();
2039 i != relevant_registries.end(); ++i) {
2040 extensions::WebRequestRulesRegistry* rules_registry =
2041 i->first;
2042 helpers::EventResponseDeltas result =
2043 rules_registry->CreateDeltas(
2044 extension_info_map,
2045 extensions::WebRequestData(
2046 request, request_stage, original_response_headers),
2047 i->second);
2049 if (!result.empty()) {
2050 helpers::EventResponseDeltas& deltas =
2051 blocked_requests_[request->identifier()].response_deltas;
2052 deltas.insert(deltas.end(), result.begin(), result.end());
2053 deltas_created = true;
2057 base::TimeDelta elapsed_time = start - base::Time::Now();
2058 UMA_HISTOGRAM_TIMES("Extensions.DeclarativeWebRequestNetworkDelay",
2059 elapsed_time);
2061 return deltas_created;
2064 void ExtensionWebRequestEventRouter::OnRulesRegistryReady(
2065 void* browser_context,
2066 const std::string& event_name,
2067 uint64 request_id,
2068 extensions::RequestStage request_stage) {
2069 // It's possible that this request was deleted, or cancelled by a previous
2070 // event handler. If so, ignore this response.
2071 if (blocked_requests_.find(request_id) == blocked_requests_.end())
2072 return;
2074 BlockedRequest& blocked_request = blocked_requests_[request_id];
2075 base::TimeDelta block_time =
2076 base::Time::Now() - blocked_request.blocking_time;
2077 UMA_HISTOGRAM_TIMES("Extensions.NetworkDelayRegistryLoad", block_time);
2079 ProcessDeclarativeRules(browser_context,
2080 blocked_request.extension_info_map,
2081 event_name,
2082 blocked_request.request,
2083 request_stage,
2084 blocked_request.original_response_headers.get());
2085 // Reset to NULL so that nobody relies on this being set.
2086 blocked_request.extension_info_map = NULL;
2087 DecrementBlockCount(
2088 browser_context, std::string(), event_name, request_id, NULL);
2091 bool ExtensionWebRequestEventRouter::GetAndSetSignaled(uint64 request_id,
2092 EventTypes event_type) {
2093 SignaledRequestMap::iterator iter = signaled_requests_.find(request_id);
2094 if (iter == signaled_requests_.end()) {
2095 signaled_requests_[request_id] = event_type;
2096 return false;
2098 bool was_signaled_before = (iter->second & event_type) != 0;
2099 iter->second |= event_type;
2100 return was_signaled_before;
2103 void ExtensionWebRequestEventRouter::ClearSignaled(uint64 request_id,
2104 EventTypes event_type) {
2105 SignaledRequestMap::iterator iter = signaled_requests_.find(request_id);
2106 if (iter == signaled_requests_.end())
2107 return;
2108 iter->second &= ~event_type;
2111 // Special QuotaLimitHeuristic for WebRequestHandlerBehaviorChangedFunction.
2113 // Each call of webRequest.handlerBehaviorChanged() clears the in-memory cache
2114 // of WebKit at the time of the next page load (top level navigation event).
2115 // This quota heuristic is intended to limit the number of times the cache is
2116 // cleared by an extension.
2118 // As we want to account for the number of times the cache is really cleared
2119 // (opposed to the number of times webRequest.handlerBehaviorChanged() is
2120 // called), we cannot decide whether a call of
2121 // webRequest.handlerBehaviorChanged() should trigger a quota violation at the
2122 // time it is called. Instead we only decrement the bucket counter at the time
2123 // when the cache is cleared (when page loads happen).
2124 class ClearCacheQuotaHeuristic : public extensions::QuotaLimitHeuristic {
2125 public:
2126 ClearCacheQuotaHeuristic(const Config& config, BucketMapper* map)
2127 : QuotaLimitHeuristic(
2128 config,
2129 map,
2130 "MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES"),
2131 callback_registered_(false),
2132 weak_ptr_factory_(this) {}
2133 ~ClearCacheQuotaHeuristic() override {}
2134 bool Apply(Bucket* bucket, const base::TimeTicks& event_time) override;
2136 private:
2137 // Callback that is triggered by the ExtensionWebRequestEventRouter on a page
2138 // load.
2140 // We don't need to take care of the life time of |bucket|: It is owned by the
2141 // BucketMapper of our base class in |QuotaLimitHeuristic::bucket_mapper_|. As
2142 // long as |this| exists, the respective BucketMapper and its bucket will
2143 // exist as well.
2144 void OnPageLoad(Bucket* bucket);
2146 // Flag to prevent that we register more than one call back in-between
2147 // clearing the cache.
2148 bool callback_registered_;
2150 base::WeakPtrFactory<ClearCacheQuotaHeuristic> weak_ptr_factory_;
2152 DISALLOW_COPY_AND_ASSIGN(ClearCacheQuotaHeuristic);
2155 bool ClearCacheQuotaHeuristic::Apply(Bucket* bucket,
2156 const base::TimeTicks& event_time) {
2157 if (event_time > bucket->expiration())
2158 bucket->Reset(config(), event_time);
2160 // Call bucket->DeductToken() on a new page load, this is when
2161 // webRequest.handlerBehaviorChanged() clears the cache.
2162 if (!callback_registered_) {
2163 ExtensionWebRequestEventRouter::GetInstance()->AddCallbackForPageLoad(
2164 base::Bind(&ClearCacheQuotaHeuristic::OnPageLoad,
2165 weak_ptr_factory_.GetWeakPtr(),
2166 bucket));
2167 callback_registered_ = true;
2170 // We only check whether tokens are left here. Deducting a token happens in
2171 // OnPageLoad().
2172 return bucket->has_tokens();
2175 void ClearCacheQuotaHeuristic::OnPageLoad(Bucket* bucket) {
2176 callback_registered_ = false;
2177 bucket->DeductToken();
2180 bool WebRequestInternalAddEventListenerFunction::RunSync() {
2181 // Argument 0 is the callback, which we don't use here.
2182 ExtensionWebRequestEventRouter::RequestFilter filter;
2183 base::DictionaryValue* value = NULL;
2184 error_.clear();
2185 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &value));
2186 // Failure + an empty error string means a fatal error.
2187 EXTENSION_FUNCTION_VALIDATE(filter.InitFromValue(*value, &error_) ||
2188 !error_.empty());
2189 if (!error_.empty())
2190 return false;
2192 int extra_info_spec = 0;
2193 if (HasOptionalArgument(2)) {
2194 base::ListValue* value = NULL;
2195 EXTENSION_FUNCTION_VALIDATE(args_->GetList(2, &value));
2196 EXTENSION_FUNCTION_VALIDATE(
2197 ExtensionWebRequestEventRouter::ExtraInfoSpec::InitFromValue(
2198 *value, &extra_info_spec));
2201 std::string event_name;
2202 EXTENSION_FUNCTION_VALIDATE(args_->GetString(3, &event_name));
2204 std::string sub_event_name;
2205 EXTENSION_FUNCTION_VALIDATE(args_->GetString(4, &sub_event_name));
2207 int webview_instance_id = 0;
2208 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(5, &webview_instance_id));
2210 base::WeakPtr<extensions::ExtensionMessageFilter> ipc_sender =
2211 ipc_sender_weak();
2212 int embedder_process_id =
2213 ipc_sender.get() ? ipc_sender->render_process_id() : -1;
2215 const Extension* extension =
2216 extension_info_map()->extensions().GetByID(extension_id_safe());
2217 std::string extension_name =
2218 extension ? extension->name() : extension_id_safe();
2220 bool is_web_view_guest = webview_instance_id != 0;
2221 // We check automatically whether the extension has the 'webRequest'
2222 // permission. For blocking calls we require the additional permission
2223 // 'webRequestBlocking'.
2224 if ((!is_web_view_guest &&
2225 extra_info_spec &
2226 (ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING |
2227 ExtensionWebRequestEventRouter::ExtraInfoSpec::ASYNC_BLOCKING)) &&
2228 !extension->permissions_data()->HasAPIPermission(
2229 extensions::APIPermission::kWebRequestBlocking)) {
2230 error_ = keys::kBlockingPermissionRequired;
2231 return false;
2234 // We allow to subscribe to patterns that are broader than the host
2235 // permissions. E.g., we could subscribe to http://www.example.com/*
2236 // while having host permissions for http://www.example.com/foo/* and
2237 // http://www.example.com/bar/*.
2238 // For this reason we do only a coarse check here to warn the extension
2239 // developer if he does something obviously wrong.
2240 if (!is_web_view_guest &&
2241 extension->permissions_data()->GetEffectiveHostPermissions().is_empty()) {
2242 error_ = keys::kHostPermissionsRequired;
2243 return false;
2246 bool success =
2247 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
2248 profile_id(), extension_id_safe(), extension_name,
2249 event_name, sub_event_name, filter, extra_info_spec,
2250 embedder_process_id, webview_instance_id, ipc_sender_weak());
2251 EXTENSION_FUNCTION_VALIDATE(success);
2253 helpers::ClearCacheOnNavigation();
2255 BrowserThread::PostTask(BrowserThread::UI,
2256 FROM_HERE,
2257 base::Bind(&helpers::NotifyWebRequestAPIUsed,
2258 profile_id(),
2259 make_scoped_refptr(extension)));
2261 return true;
2264 void WebRequestInternalEventHandledFunction::RespondWithError(
2265 const std::string& event_name,
2266 const std::string& sub_event_name,
2267 uint64 request_id,
2268 scoped_ptr<ExtensionWebRequestEventRouter::EventResponse> response,
2269 const std::string& error) {
2270 error_ = error;
2271 ExtensionWebRequestEventRouter::GetInstance()->OnEventHandled(
2272 profile_id(),
2273 extension_id_safe(),
2274 event_name,
2275 sub_event_name,
2276 request_id,
2277 response.release());
2280 bool WebRequestInternalEventHandledFunction::RunSync() {
2281 std::string event_name;
2282 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &event_name));
2284 std::string sub_event_name;
2285 EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &sub_event_name));
2287 std::string request_id_str;
2288 EXTENSION_FUNCTION_VALIDATE(args_->GetString(2, &request_id_str));
2289 uint64 request_id;
2290 EXTENSION_FUNCTION_VALIDATE(base::StringToUint64(request_id_str,
2291 &request_id));
2293 scoped_ptr<ExtensionWebRequestEventRouter::EventResponse> response;
2294 if (HasOptionalArgument(3)) {
2295 base::DictionaryValue* value = NULL;
2296 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(3, &value));
2298 if (!value->empty()) {
2299 base::Time install_time =
2300 extension_info_map()->GetInstallTime(extension_id_safe());
2301 response.reset(new ExtensionWebRequestEventRouter::EventResponse(
2302 extension_id_safe(), install_time));
2305 if (value->HasKey("cancel")) {
2306 // Don't allow cancel mixed with other keys.
2307 if (value->size() != 1) {
2308 RespondWithError(event_name,
2309 sub_event_name,
2310 request_id,
2311 response.Pass(),
2312 keys::kInvalidBlockingResponse);
2313 return false;
2316 bool cancel = false;
2317 EXTENSION_FUNCTION_VALIDATE(value->GetBoolean("cancel", &cancel));
2318 response->cancel = cancel;
2321 if (value->HasKey("redirectUrl")) {
2322 std::string new_url_str;
2323 EXTENSION_FUNCTION_VALIDATE(value->GetString("redirectUrl",
2324 &new_url_str));
2325 response->new_url = GURL(new_url_str);
2326 if (!response->new_url.is_valid()) {
2327 RespondWithError(event_name,
2328 sub_event_name,
2329 request_id,
2330 response.Pass(),
2331 ErrorUtils::FormatErrorMessage(
2332 keys::kInvalidRedirectUrl, new_url_str));
2333 return false;
2337 const bool hasRequestHeaders = value->HasKey("requestHeaders");
2338 const bool hasResponseHeaders = value->HasKey("responseHeaders");
2339 if (hasRequestHeaders || hasResponseHeaders) {
2340 if (hasRequestHeaders && hasResponseHeaders) {
2341 // Allow only one of the keys, not both.
2342 RespondWithError(event_name,
2343 sub_event_name,
2344 request_id,
2345 response.Pass(),
2346 keys::kInvalidHeaderKeyCombination);
2347 return false;
2350 base::ListValue* headers_value = NULL;
2351 scoped_ptr<net::HttpRequestHeaders> request_headers;
2352 scoped_ptr<helpers::ResponseHeaders> response_headers;
2353 if (hasRequestHeaders) {
2354 request_headers.reset(new net::HttpRequestHeaders());
2355 EXTENSION_FUNCTION_VALIDATE(value->GetList(keys::kRequestHeadersKey,
2356 &headers_value));
2357 } else {
2358 response_headers.reset(new helpers::ResponseHeaders());
2359 EXTENSION_FUNCTION_VALIDATE(value->GetList(keys::kResponseHeadersKey,
2360 &headers_value));
2363 for (size_t i = 0; i < headers_value->GetSize(); ++i) {
2364 base::DictionaryValue* header_value = NULL;
2365 std::string name;
2366 std::string value;
2367 EXTENSION_FUNCTION_VALIDATE(
2368 headers_value->GetDictionary(i, &header_value));
2369 if (!FromHeaderDictionary(header_value, &name, &value)) {
2370 std::string serialized_header;
2371 base::JSONWriter::Write(header_value, &serialized_header);
2372 RespondWithError(event_name,
2373 sub_event_name,
2374 request_id,
2375 response.Pass(),
2376 ErrorUtils::FormatErrorMessage(keys::kInvalidHeader,
2377 serialized_header));
2378 return false;
2380 if (!net::HttpUtil::IsValidHeaderName(name)) {
2381 RespondWithError(event_name,
2382 sub_event_name,
2383 request_id,
2384 response.Pass(),
2385 keys::kInvalidHeaderName);
2386 return false;
2388 if (!net::HttpUtil::IsValidHeaderValue(value)) {
2389 RespondWithError(event_name,
2390 sub_event_name,
2391 request_id,
2392 response.Pass(),
2393 ErrorUtils::FormatErrorMessage(
2394 keys::kInvalidHeaderValue, name));
2395 return false;
2397 if (hasRequestHeaders)
2398 request_headers->SetHeader(name, value);
2399 else
2400 response_headers->push_back(helpers::ResponseHeader(name, value));
2402 if (hasRequestHeaders)
2403 response->request_headers.reset(request_headers.release());
2404 else
2405 response->response_headers.reset(response_headers.release());
2408 if (value->HasKey(keys::kAuthCredentialsKey)) {
2409 base::DictionaryValue* credentials_value = NULL;
2410 EXTENSION_FUNCTION_VALIDATE(value->GetDictionary(
2411 keys::kAuthCredentialsKey,
2412 &credentials_value));
2413 base::string16 username;
2414 base::string16 password;
2415 EXTENSION_FUNCTION_VALIDATE(
2416 credentials_value->GetString(keys::kUsernameKey, &username));
2417 EXTENSION_FUNCTION_VALIDATE(
2418 credentials_value->GetString(keys::kPasswordKey, &password));
2419 response->auth_credentials.reset(
2420 new net::AuthCredentials(username, password));
2424 ExtensionWebRequestEventRouter::GetInstance()->OnEventHandled(
2425 profile_id(), extension_id_safe(), event_name, sub_event_name, request_id,
2426 response.release());
2428 return true;
2431 void WebRequestHandlerBehaviorChangedFunction::GetQuotaLimitHeuristics(
2432 extensions::QuotaLimitHeuristics* heuristics) const {
2433 extensions::QuotaLimitHeuristic::Config config = {
2434 // See web_request.json for current value.
2435 web_request::MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES,
2436 base::TimeDelta::FromMinutes(10)};
2437 extensions::QuotaLimitHeuristic::BucketMapper* bucket_mapper =
2438 new extensions::QuotaLimitHeuristic::SingletonBucketMapper();
2439 ClearCacheQuotaHeuristic* heuristic =
2440 new ClearCacheQuotaHeuristic(config, bucket_mapper);
2441 heuristics->push_back(heuristic);
2444 void WebRequestHandlerBehaviorChangedFunction::OnQuotaExceeded(
2445 const std::string& violation_error) {
2446 // Post warning message.
2447 WarningSet warnings;
2448 warnings.insert(
2449 Warning::CreateRepeatedCacheFlushesWarning(extension_id_safe()));
2450 BrowserThread::PostTask(
2451 BrowserThread::UI,
2452 FROM_HERE,
2453 base::Bind(&WarningService::NotifyWarningsOnUI, profile_id(), warnings));
2455 // Continue gracefully.
2456 RunSync();
2459 bool WebRequestHandlerBehaviorChangedFunction::RunSync() {
2460 helpers::ClearCacheOnNavigation();
2461 return true;