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"
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/rules_registry_service.h"
27 #include "extensions/browser/api/declarative_webrequest/request_stage.h"
28 #include "extensions/browser/api/declarative_webrequest/webrequest_constants.h"
29 #include "extensions/browser/api/declarative_webrequest/webrequest_rules_registry.h"
30 #include "extensions/browser/api/extensions_api_client.h"
31 #include "extensions/browser/api/web_request/upload_data_presenter.h"
32 #include "extensions/browser/api/web_request/web_request_api_constants.h"
33 #include "extensions/browser/api/web_request/web_request_api_helpers.h"
34 #include "extensions/browser/api/web_request/web_request_event_router_delegate.h"
35 #include "extensions/browser/api/web_request/web_request_time_tracker.h"
36 #include "extensions/browser/event_router.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/io_thread_extension_message_filter.h"
45 #include "extensions/browser/runtime_data.h"
46 #include "extensions/browser/warning_service.h"
47 #include "extensions/browser/warning_set.h"
48 #include "extensions/common/api/web_request.h"
49 #include "extensions/common/error_utils.h"
50 #include "extensions/common/event_filtering_info.h"
51 #include "extensions/common/extension.h"
52 #include "extensions/common/features/feature.h"
53 #include "extensions/common/permissions/permissions_data.h"
54 #include "extensions/common/url_pattern.h"
55 #include "extensions/strings/grit/extensions_strings.h"
56 #include "net/base/auth.h"
57 #include "net/base/net_errors.h"
58 #include "net/base/upload_data_stream.h"
59 #include "net/http/http_response_headers.h"
60 #include "net/http/http_util.h"
61 #include "net/url_request/url_request.h"
62 #include "ui/base/l10n/l10n_util.h"
65 using base::DictionaryValue
;
66 using base::ListValue
;
67 using base::StringValue
;
68 using content::BrowserMessageFilter
;
69 using content::BrowserThread
;
70 using content::ResourceRequestInfo
;
71 using content::ResourceType
;
73 namespace activity_log
= activity_log_web_request_constants
;
74 namespace helpers
= extension_web_request_api_helpers
;
75 namespace keys
= extension_web_request_api_constants
;
77 namespace extensions
{
79 namespace declarative_keys
= declarative_webrequest_constants
;
80 namespace web_request
= api::web_request
;
84 const char kWebRequestEventPrefix
[] = "webRequest.";
86 // List of all the webRequest events.
87 const char* const kWebRequestEvents
[] = {
88 keys::kOnBeforeRedirectEvent
,
89 web_request::OnBeforeRequest::kEventName
,
90 keys::kOnBeforeSendHeadersEvent
,
91 keys::kOnCompletedEvent
,
92 web_request::OnErrorOccurred::kEventName
,
93 keys::kOnSendHeadersEvent
,
94 keys::kOnAuthRequiredEvent
,
95 keys::kOnResponseStartedEvent
,
96 keys::kOnHeadersReceivedEvent
,
99 const size_t kWebRequestEventsLength
= arraysize(kWebRequestEvents
);
101 const char* GetRequestStageAsString(
102 ExtensionWebRequestEventRouter::EventTypes type
) {
104 case ExtensionWebRequestEventRouter::kInvalidEvent
:
106 case ExtensionWebRequestEventRouter::kOnBeforeRequest
:
107 return keys::kOnBeforeRequest
;
108 case ExtensionWebRequestEventRouter::kOnBeforeSendHeaders
:
109 return keys::kOnBeforeSendHeaders
;
110 case ExtensionWebRequestEventRouter::kOnSendHeaders
:
111 return keys::kOnSendHeaders
;
112 case ExtensionWebRequestEventRouter::kOnHeadersReceived
:
113 return keys::kOnHeadersReceived
;
114 case ExtensionWebRequestEventRouter::kOnBeforeRedirect
:
115 return keys::kOnBeforeRedirect
;
116 case ExtensionWebRequestEventRouter::kOnAuthRequired
:
117 return keys::kOnAuthRequired
;
118 case ExtensionWebRequestEventRouter::kOnResponseStarted
:
119 return keys::kOnResponseStarted
;
120 case ExtensionWebRequestEventRouter::kOnErrorOccurred
:
121 return keys::kOnErrorOccurred
;
122 case ExtensionWebRequestEventRouter::kOnCompleted
:
123 return keys::kOnCompleted
;
126 return "Not reached";
129 int GetFrameId(bool is_main_frame
, int frame_id
) {
130 return is_main_frame
? 0 : frame_id
;
133 bool IsWebRequestEvent(const std::string
& event_name
) {
134 std::string
web_request_event_name(event_name
);
135 if (base::StartsWith(web_request_event_name
,
136 webview::kWebViewEventPrefix
,
137 base::CompareCase::SENSITIVE
)) {
138 web_request_event_name
.replace(
139 0, strlen(webview::kWebViewEventPrefix
), kWebRequestEventPrefix
);
143 kWebRequestEvents
+ kWebRequestEventsLength
,
144 web_request_event_name
) != (kWebRequestEvents
+ kWebRequestEventsLength
);
147 // Returns whether |request| has been triggered by an extension in
148 // |extension_info_map|.
149 bool IsRequestFromExtension(const net::URLRequest
* request
,
150 const InfoMap
* extension_info_map
) {
151 // |extension_info_map| is NULL for system-level requests.
152 if (!extension_info_map
)
155 const ResourceRequestInfo
* info
= ResourceRequestInfo::ForRequest(request
);
157 // If this request was not created by the ResourceDispatcher, |info| is NULL.
158 // All requests from extensions are created by the ResourceDispatcher.
162 return extension_info_map
->process_map().Contains(info
->GetChildID());
165 void ExtractRequestRoutingInfo(net::URLRequest
* request
,
166 int* render_process_host_id
,
168 if (!request
->GetUserData(NULL
))
170 const ResourceRequestInfo
* info
= ResourceRequestInfo::ForRequest(request
);
171 *render_process_host_id
= info
->GetChildID();
172 *routing_id
= info
->GetRouteID();
175 // Given a |request|, this function determines whether it originated from
176 // a <webview> guest process or not. If it is from a <webview> guest process,
177 // then |web_view_info| is returned with information about the instance ID
178 // that uniquely identifies the <webview> and its embedder.
179 bool GetWebViewInfo(net::URLRequest
* request
,
180 WebViewRendererState::WebViewInfo
* web_view_info
) {
181 int render_process_host_id
= -1;
183 ExtractRequestRoutingInfo(request
, &render_process_host_id
, &routing_id
);
184 return WebViewRendererState::GetInstance()->GetInfo(
185 render_process_host_id
, routing_id
, web_view_info
);
188 void ExtractRequestInfoDetails(net::URLRequest
* request
,
191 bool* parent_is_main_frame
,
192 int* parent_frame_id
,
193 int* render_process_host_id
,
195 ResourceType
* resource_type
) {
196 if (!request
->GetUserData(NULL
))
199 const ResourceRequestInfo
* info
= ResourceRequestInfo::ForRequest(request
);
200 *frame_id
= info
->GetRenderFrameID();
201 *is_main_frame
= info
->IsMainFrame();
202 *parent_frame_id
= info
->GetParentRenderFrameID();
203 *parent_is_main_frame
= info
->ParentIsMainFrame();
204 *render_process_host_id
= info
->GetChildID();
205 *routing_id
= info
->GetRouteID();
207 // Restrict the resource type to the values we care about.
208 if (helpers::IsRelevantResourceType(info
->GetResourceType()))
209 *resource_type
= info
->GetResourceType();
211 *resource_type
= content::RESOURCE_TYPE_LAST_TYPE
;
214 // Extracts the body from |request| and writes the data into |out|.
215 void ExtractRequestInfoBody(const net::URLRequest
* request
,
216 base::DictionaryValue
* out
) {
217 const net::UploadDataStream
* upload_data
= request
->get_upload();
219 (request
->method() != "POST" && request
->method() != "PUT"))
220 return; // Need to exit without "out->Set(keys::kRequestBodyKey, ...);" .
222 base::DictionaryValue
* request_body
= new base::DictionaryValue();
223 out
->Set(keys::kRequestBodyKey
, request_body
);
225 // Get the data presenters, ordered by how specific they are.
226 ParsedDataPresenter
parsed_data_presenter(*request
);
227 RawDataPresenter raw_data_presenter
;
228 UploadDataPresenter
* const presenters
[] = {
229 &parsed_data_presenter
, // 1: any parseable forms? (Specific to forms.)
230 &raw_data_presenter
// 2: any data at all? (Non-specific.)
232 // Keys for the results of the corresponding presenters.
233 static const char* const kKeys
[] = {
234 keys::kRequestBodyFormDataKey
,
235 keys::kRequestBodyRawKey
238 const ScopedVector
<net::UploadElementReader
>* readers
=
239 upload_data
->GetElementReaders();
240 bool some_succeeded
= false;
242 for (size_t i
= 0; !some_succeeded
&& i
< arraysize(presenters
); ++i
) {
243 ScopedVector
<net::UploadElementReader
>::const_iterator reader
;
244 for (reader
= readers
->begin(); reader
!= readers
->end(); ++reader
)
245 presenters
[i
]->FeedNext(**reader
);
246 if (presenters
[i
]->Succeeded()) {
247 request_body
->Set(kKeys
[i
], presenters
[i
]->Result().release());
248 some_succeeded
= true;
253 request_body
->SetString(keys::kRequestBodyErrorKey
, "Unknown error.");
256 // Converts a HttpHeaders dictionary to a |name|, |value| pair. Returns
257 // true if successful.
258 bool FromHeaderDictionary(const base::DictionaryValue
* header_value
,
260 std::string
* value
) {
261 if (!header_value
->GetString(keys::kHeaderNameKey
, name
))
264 // We require either a "value" or a "binaryValue" entry.
265 if (!(header_value
->HasKey(keys::kHeaderValueKey
) ^
266 header_value
->HasKey(keys::kHeaderBinaryValueKey
)))
269 if (header_value
->HasKey(keys::kHeaderValueKey
)) {
270 if (!header_value
->GetString(keys::kHeaderValueKey
, value
)) {
273 } else if (header_value
->HasKey(keys::kHeaderBinaryValueKey
)) {
274 const base::ListValue
* list
= NULL
;
275 if (!header_value
->HasKey(keys::kHeaderBinaryValueKey
)) {
277 } else if (!header_value
->GetList(keys::kHeaderBinaryValueKey
, &list
) ||
278 !helpers::CharListToString(list
, value
)) {
285 // Creates a list of HttpHeaders (see the extension API JSON). If |headers| is
286 // NULL, the list is empty. Ownership is passed to the caller.
287 base::ListValue
* GetResponseHeadersList(
288 const net::HttpResponseHeaders
* headers
) {
289 base::ListValue
* headers_value
= new base::ListValue();
294 while (headers
->EnumerateHeaderLines(&iter
, &name
, &value
))
295 headers_value
->Append(helpers::CreateHeaderDictionary(name
, value
));
297 return headers_value
;
300 base::ListValue
* GetRequestHeadersList(const net::HttpRequestHeaders
& headers
) {
301 base::ListValue
* headers_value
= new base::ListValue();
302 for (net::HttpRequestHeaders::Iterator
it(headers
); it
.GetNext(); )
303 headers_value
->Append(
304 helpers::CreateHeaderDictionary(it
.name(), it
.value()));
305 return headers_value
;
308 // Creates a base::StringValue with the status line of |headers|. If |headers|
309 // is NULL, an empty string is returned. Ownership is passed to the caller.
310 base::StringValue
* GetStatusLine(net::HttpResponseHeaders
* headers
) {
311 return new base::StringValue(
312 headers
? headers
->GetStatusLine() : std::string());
315 // Sends an event to subscribers of chrome.declarativeWebRequest.onMessage or
316 // to subscribers of webview.onMessage if the action is being operated upon
317 // a <webview> guest renderer.
318 // |extension_id| identifies the extension that sends and receives the event.
319 // |is_web_view_guest| indicates whether the action is for a <webview>.
320 // |web_view_info| is a struct containing information about the <webview>
322 // |event_argument| is passed to the event listener.
323 void SendOnMessageEventOnUI(
324 void* browser_context_id
,
325 const std::string
& extension_id
,
326 bool is_web_view_guest
,
327 const WebViewRendererState::WebViewInfo
& web_view_info
,
328 scoped_ptr
<base::DictionaryValue
> event_argument
) {
329 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
331 content::BrowserContext
* browser_context
=
332 reinterpret_cast<content::BrowserContext
*>(browser_context_id
);
333 if (!ExtensionsBrowserClient::Get()->IsValidContext(browser_context
))
336 scoped_ptr
<base::ListValue
> event_args(new base::ListValue
);
337 event_args
->Append(event_argument
.release());
339 EventRouter
* event_router
= EventRouter::Get(browser_context
);
341 EventFilteringInfo event_filtering_info
;
343 events::HistogramValue histogram_value
= events::UNKNOWN
;
344 std::string event_name
;
345 // The instance ID uniquely identifies a <webview> instance within an embedder
346 // process. We use a filter here so that only event listeners for a particular
347 // <webview> will fire.
348 if (is_web_view_guest
) {
349 event_filtering_info
.SetInstanceID(web_view_info
.instance_id
);
350 histogram_value
= events::WEB_VIEW_INTERNAL_ON_MESSAGE
;
351 event_name
= webview::kEventMessage
;
353 histogram_value
= events::DECLARATIVE_WEB_REQUEST_ON_MESSAGE
;
354 event_name
= declarative_keys::kOnMessage
;
357 scoped_ptr
<Event
> event(new Event(
358 histogram_value
, event_name
, event_args
.Pass(), browser_context
, GURL(),
359 EventRouter::USER_GESTURE_UNKNOWN
, event_filtering_info
));
360 event_router
->DispatchEventToExtension(extension_id
, event
.Pass());
363 void RemoveEventListenerOnIOThread(
364 void* browser_context
,
365 const std::string
& extension_id
,
366 const std::string
& sub_event_name
,
367 int embedder_process_id
,
368 int web_view_instance_id
) {
369 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
370 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(
371 browser_context
, extension_id
, sub_event_name
,
372 embedder_process_id
, web_view_instance_id
);
377 WebRequestAPI::WebRequestAPI(content::BrowserContext
* context
)
378 : browser_context_(context
) {
379 EventRouter
* event_router
= EventRouter::Get(browser_context_
);
380 for (size_t i
= 0; i
< arraysize(kWebRequestEvents
); ++i
) {
381 // Observe the webRequest event.
382 std::string event_name
= kWebRequestEvents
[i
];
383 event_router
->RegisterObserver(this, event_name
);
385 // Also observe the corresponding webview event.
387 0, sizeof(kWebRequestEventPrefix
) - 1, webview::kWebViewEventPrefix
);
388 event_router
->RegisterObserver(this, event_name
);
392 WebRequestAPI::~WebRequestAPI() {
393 EventRouter::Get(browser_context_
)->UnregisterObserver(this);
396 static base::LazyInstance
<BrowserContextKeyedAPIFactory
<WebRequestAPI
> >
397 g_factory
= LAZY_INSTANCE_INITIALIZER
;
400 BrowserContextKeyedAPIFactory
<WebRequestAPI
>*
401 WebRequestAPI::GetFactoryInstance() {
402 return g_factory
.Pointer();
405 void WebRequestAPI::OnListenerRemoved(const EventListenerInfo
& details
) {
406 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
407 // Note that details.event_name includes the sub-event details (e.g. "/123").
408 // TODO(fsamuel): <webview> events will not be removed through this code path.
409 // <webview> events will be removed in RemoveWebViewEventListeners. Ideally,
410 // this code should be decoupled from extensions, we should use the host ID
411 // instead, and not have two different code paths. This is a huge undertaking
412 // unfortunately, so we'll resort to two code paths for now.
413 BrowserThread::PostTask(BrowserThread::IO
,
415 base::Bind(&RemoveEventListenerOnIOThread
,
416 details
.browser_context
,
417 details
.extension_id
,
419 0 /* embedder_process_id (ignored) */,
420 0 /* web_view_instance_id */));
423 // Represents a single unique listener to an event, along with whatever filter
424 // parameters and extra_info_spec were specified at the time the listener was
426 // NOTE(benjhayden) New APIs should not use this sub_event_name trick! It does
427 // not play well with event pages. See downloads.onDeterminingFilename and
428 // ExtensionDownloadsEventRouter for an alternative approach.
429 struct ExtensionWebRequestEventRouter::EventListener
{
430 std::string extension_id
;
431 std::string extension_name
;
432 std::string sub_event_name
;
433 RequestFilter filter
;
435 int embedder_process_id
;
436 int web_view_instance_id
;
437 base::WeakPtr
<IPC::Sender
> ipc_sender
;
438 mutable std::set
<uint64
> blocked_requests
;
440 // Comparator to work with std::set.
441 bool operator<(const EventListener
& that
) const {
442 if (extension_id
!= that
.extension_id
)
443 return extension_id
< that
.extension_id
;
445 if (sub_event_name
!= that
.sub_event_name
)
446 return sub_event_name
< that
.sub_event_name
;
448 if (web_view_instance_id
!= that
.web_view_instance_id
)
449 return web_view_instance_id
< that
.web_view_instance_id
;
451 if (web_view_instance_id
== 0) {
452 // Do not filter by process ID for non-webviews, because this comparator
453 // is also used to find and remove an event listener when an extension is
454 // unloaded. At this point, the event listener cannot be mapped back to
455 // the original process, so 0 is used instead of the actual process ID.
456 DCHECK(embedder_process_id
== 0 || that
.embedder_process_id
== 0);
460 if (embedder_process_id
!= that
.embedder_process_id
)
461 return embedder_process_id
< that
.embedder_process_id
;
468 embedder_process_id(0),
469 web_view_instance_id(0) {}
472 // Contains info about requests that are blocked waiting for a response from
474 struct ExtensionWebRequestEventRouter::BlockedRequest
{
475 // The request that is being blocked.
476 net::URLRequest
* request
;
478 // Whether the request originates from an incognito tab.
481 // The event that we're currently blocked on.
484 // The number of event handlers that we are awaiting a response from.
485 int num_handlers_blocking
;
487 // Pointer to NetLog to report significant changes to the request for
489 const net::BoundNetLog
* net_log
;
491 // The callback to call when we get a response from all event handlers.
492 net::CompletionCallback callback
;
494 // If non-empty, this contains the new URL that the request will redirect to.
495 // Only valid for OnBeforeRequest and OnHeadersReceived.
498 // The request headers that will be issued along with this request. Only valid
499 // for OnBeforeSendHeaders.
500 net::HttpRequestHeaders
* request_headers
;
502 // The response headers that were received from the server. Only valid for
503 // OnHeadersReceived.
504 scoped_refptr
<const net::HttpResponseHeaders
> original_response_headers
;
506 // Location where to override response headers. Only valid for
507 // OnHeadersReceived.
508 scoped_refptr
<net::HttpResponseHeaders
>* override_response_headers
;
510 // If non-empty, this contains the auth credentials that may be filled in.
511 // Only valid for OnAuthRequired.
512 net::AuthCredentials
* auth_credentials
;
514 // The callback to invoke for auth. If |auth_callback.is_null()| is false,
515 // |callback| must be NULL.
516 // Only valid for OnAuthRequired.
517 net::NetworkDelegate::AuthCallback auth_callback
;
519 // Time the request was paused. Used for logging purposes.
520 base::Time blocking_time
;
522 // Changes requested by extensions.
523 helpers::EventResponseDeltas response_deltas
;
525 // Provider of meta data about extensions, only used and non-NULL for events
526 // that are delayed until the rules registry is ready.
527 InfoMap
* extension_info_map
;
532 event(kInvalidEvent
),
533 num_handlers_blocking(0),
536 request_headers(NULL
),
537 override_response_headers(NULL
),
538 auth_credentials(NULL
),
539 extension_info_map(NULL
) {}
542 bool ExtensionWebRequestEventRouter::RequestFilter::InitFromValue(
543 const base::DictionaryValue
& value
, std::string
* error
) {
544 if (!value
.HasKey("urls"))
547 for (base::DictionaryValue::Iterator
it(value
); !it
.IsAtEnd(); it
.Advance()) {
548 if (it
.key() == "urls") {
549 const base::ListValue
* urls_value
= NULL
;
550 if (!it
.value().GetAsList(&urls_value
))
552 for (size_t i
= 0; i
< urls_value
->GetSize(); ++i
) {
555 URLPattern::SCHEME_HTTP
| URLPattern::SCHEME_HTTPS
|
556 URLPattern::SCHEME_FTP
| URLPattern::SCHEME_FILE
|
557 URLPattern::SCHEME_EXTENSION
);
558 if (!urls_value
->GetString(i
, &url
) ||
559 pattern
.Parse(url
) != URLPattern::PARSE_SUCCESS
) {
560 *error
= ErrorUtils::FormatErrorMessage(
561 keys::kInvalidRequestFilterUrl
, url
);
564 urls
.AddPattern(pattern
);
566 } else if (it
.key() == "types") {
567 const base::ListValue
* types_value
= NULL
;
568 if (!it
.value().GetAsList(&types_value
))
570 for (size_t i
= 0; i
< types_value
->GetSize(); ++i
) {
571 std::string type_str
;
573 if (!types_value
->GetString(i
, &type_str
) ||
574 !helpers::ParseResourceType(type_str
, &type
))
576 types
.push_back(type
);
578 } else if (it
.key() == "tabId") {
579 if (!it
.value().GetAsInteger(&tab_id
))
581 } else if (it
.key() == "windowId") {
582 if (!it
.value().GetAsInteger(&window_id
))
592 bool ExtensionWebRequestEventRouter::ExtraInfoSpec::InitFromValue(
593 const base::ListValue
& value
, int* extra_info_spec
) {
594 *extra_info_spec
= 0;
595 for (size_t i
= 0; i
< value
.GetSize(); ++i
) {
597 if (!value
.GetString(i
, &str
))
600 if (str
== "requestHeaders")
601 *extra_info_spec
|= REQUEST_HEADERS
;
602 else if (str
== "responseHeaders")
603 *extra_info_spec
|= RESPONSE_HEADERS
;
604 else if (str
== "blocking")
605 *extra_info_spec
|= BLOCKING
;
606 else if (str
== "asyncBlocking")
607 *extra_info_spec
|= ASYNC_BLOCKING
;
608 else if (str
== "requestBody")
609 *extra_info_spec
|= REQUEST_BODY
;
613 // BLOCKING and ASYNC_BLOCKING are mutually exclusive.
614 if ((*extra_info_spec
& BLOCKING
) && (*extra_info_spec
& ASYNC_BLOCKING
))
621 ExtensionWebRequestEventRouter::EventResponse::EventResponse(
622 const std::string
& extension_id
, const base::Time
& extension_install_time
)
623 : extension_id(extension_id
),
624 extension_install_time(extension_install_time
),
628 ExtensionWebRequestEventRouter::EventResponse::~EventResponse() {
631 ExtensionWebRequestEventRouter::RequestFilter::RequestFilter()
632 : tab_id(-1), window_id(-1) {
635 ExtensionWebRequestEventRouter::RequestFilter::~RequestFilter() {
639 // ExtensionWebRequestEventRouter
643 ExtensionWebRequestEventRouter
* ExtensionWebRequestEventRouter::GetInstance() {
644 return Singleton
<ExtensionWebRequestEventRouter
>::get();
647 ExtensionWebRequestEventRouter::ExtensionWebRequestEventRouter()
648 : request_time_tracker_(new ExtensionWebRequestTimeTracker
) {
649 web_request_event_router_delegate_
.reset(
650 ExtensionsAPIClient::Get()->CreateWebRequestEventRouterDelegate());
653 ExtensionWebRequestEventRouter::~ExtensionWebRequestEventRouter() {
656 void ExtensionWebRequestEventRouter::RegisterRulesRegistry(
657 void* browser_context
,
658 int rules_registry_id
,
659 scoped_refptr
<WebRequestRulesRegistry
> rules_registry
) {
660 RulesRegistryKey
key(browser_context
, rules_registry_id
);
661 if (rules_registry
.get())
662 rules_registries_
[key
] = rules_registry
;
664 rules_registries_
.erase(key
);
667 void ExtensionWebRequestEventRouter::ExtractRequestInfo(
668 net::URLRequest
* request
, base::DictionaryValue
* out
) {
669 bool is_main_frame
= false;
671 bool parent_is_main_frame
= false;
672 int parent_frame_id
= -1;
673 int frame_id_for_extension
= -1;
674 int parent_frame_id_for_extension
= -1;
675 int render_process_host_id
= -1;
677 ResourceType resource_type
= content::RESOURCE_TYPE_LAST_TYPE
;
678 ExtractRequestInfoDetails(request
, &is_main_frame
, &frame_id
,
679 &parent_is_main_frame
, &parent_frame_id
,
680 &render_process_host_id
, &routing_id
,
682 frame_id_for_extension
= GetFrameId(is_main_frame
, frame_id
);
683 parent_frame_id_for_extension
= GetFrameId(parent_is_main_frame
,
686 out
->SetString(keys::kRequestIdKey
,
687 base::Uint64ToString(request
->identifier()));
688 out
->SetString(keys::kUrlKey
, request
->url().spec());
689 out
->SetString(keys::kMethodKey
, request
->method());
690 out
->SetInteger(keys::kFrameIdKey
, frame_id_for_extension
);
691 out
->SetInteger(keys::kParentFrameIdKey
, parent_frame_id_for_extension
);
692 out
->SetString(keys::kTypeKey
, helpers::ResourceTypeToString(resource_type
));
693 out
->SetDouble(keys::kTimeStampKey
, base::Time::Now().ToDoubleT() * 1000);
694 if (web_request_event_router_delegate_
) {
695 web_request_event_router_delegate_
->ExtractExtraRequestDetails(
700 int ExtensionWebRequestEventRouter::OnBeforeRequest(
701 void* browser_context
,
702 InfoMap
* extension_info_map
,
703 net::URLRequest
* request
,
704 const net::CompletionCallback
& callback
,
706 // We hide events from the system context as well as sensitive requests.
707 if (!browser_context
||
708 WebRequestPermissions::HideRequest(extension_info_map
, request
))
711 if (IsPageLoad(request
))
714 request_time_tracker_
->LogRequestStartTime(request
->identifier(),
719 // Whether to initialized blocked_requests_.
720 bool initialize_blocked_requests
= false;
722 initialize_blocked_requests
|=
723 ProcessDeclarativeRules(browser_context
, extension_info_map
,
724 web_request::OnBeforeRequest::kEventName
, request
,
725 ON_BEFORE_REQUEST
, NULL
);
727 int extra_info_spec
= 0;
728 std::vector
<const EventListener
*> listeners
=
729 GetMatchingListeners(browser_context
, extension_info_map
,
730 web_request::OnBeforeRequest::kEventName
, request
,
732 if (!listeners
.empty() &&
733 !GetAndSetSignaled(request
->identifier(), kOnBeforeRequest
)) {
734 base::ListValue args
;
735 base::DictionaryValue
* dict
= new base::DictionaryValue();
736 ExtractRequestInfo(request
, dict
);
737 if (extra_info_spec
& ExtraInfoSpec::REQUEST_BODY
)
738 ExtractRequestInfoBody(request
, dict
);
741 initialize_blocked_requests
|=
742 DispatchEvent(browser_context
, request
, listeners
, args
);
745 if (!initialize_blocked_requests
)
746 return net::OK
; // Nobody saw a reason for modifying the request.
748 blocked_requests_
[request
->identifier()].event
= kOnBeforeRequest
;
749 blocked_requests_
[request
->identifier()].is_incognito
|=
750 IsIncognitoBrowserContext(browser_context
);
751 blocked_requests_
[request
->identifier()].request
= request
;
752 blocked_requests_
[request
->identifier()].callback
= callback
;
753 blocked_requests_
[request
->identifier()].new_url
= new_url
;
754 blocked_requests_
[request
->identifier()].net_log
= &request
->net_log();
756 if (blocked_requests_
[request
->identifier()].num_handlers_blocking
== 0) {
757 // If there are no blocking handlers, only the declarative rules tried
758 // to modify the request and we can respond synchronously.
759 return ExecuteDeltas(browser_context
, request
->identifier(),
760 false /* call_callback*/);
762 return net::ERR_IO_PENDING
;
766 int ExtensionWebRequestEventRouter::OnBeforeSendHeaders(
767 void* browser_context
,
768 InfoMap
* extension_info_map
,
769 net::URLRequest
* request
,
770 const net::CompletionCallback
& callback
,
771 net::HttpRequestHeaders
* headers
) {
772 // We hide events from the system context as well as sensitive requests.
773 if (!browser_context
||
774 WebRequestPermissions::HideRequest(extension_info_map
, request
))
777 bool initialize_blocked_requests
= false;
779 initialize_blocked_requests
|= ProcessDeclarativeRules(
780 browser_context
, extension_info_map
, keys::kOnBeforeSendHeadersEvent
,
781 request
, ON_BEFORE_SEND_HEADERS
, NULL
);
783 int extra_info_spec
= 0;
784 std::vector
<const EventListener
*> listeners
=
785 GetMatchingListeners(browser_context
, extension_info_map
,
786 keys::kOnBeforeSendHeadersEvent
, request
,
788 if (!listeners
.empty() &&
789 !GetAndSetSignaled(request
->identifier(), kOnBeforeSendHeaders
)) {
790 base::ListValue args
;
791 base::DictionaryValue
* dict
= new base::DictionaryValue();
792 ExtractRequestInfo(request
, dict
);
793 if (extra_info_spec
& ExtraInfoSpec::REQUEST_HEADERS
)
794 dict
->Set(keys::kRequestHeadersKey
, GetRequestHeadersList(*headers
));
797 initialize_blocked_requests
|=
798 DispatchEvent(browser_context
, request
, listeners
, args
);
801 if (!initialize_blocked_requests
)
802 return net::OK
; // Nobody saw a reason for modifying the request.
804 blocked_requests_
[request
->identifier()].event
= kOnBeforeSendHeaders
;
805 blocked_requests_
[request
->identifier()].is_incognito
|=
806 IsIncognitoBrowserContext(browser_context
);
807 blocked_requests_
[request
->identifier()].request
= request
;
808 blocked_requests_
[request
->identifier()].callback
= callback
;
809 blocked_requests_
[request
->identifier()].request_headers
= headers
;
810 blocked_requests_
[request
->identifier()].net_log
= &request
->net_log();
812 if (blocked_requests_
[request
->identifier()].num_handlers_blocking
== 0) {
813 // If there are no blocking handlers, only the declarative rules tried
814 // to modify the request and we can respond synchronously.
815 return ExecuteDeltas(browser_context
, request
->identifier(),
816 false /* call_callback*/);
818 return net::ERR_IO_PENDING
;
822 void ExtensionWebRequestEventRouter::OnSendHeaders(
823 void* browser_context
,
824 InfoMap
* extension_info_map
,
825 net::URLRequest
* request
,
826 const net::HttpRequestHeaders
& headers
) {
827 // We hide events from the system context as well as sensitive requests.
828 if (!browser_context
||
829 WebRequestPermissions::HideRequest(extension_info_map
, request
))
832 if (GetAndSetSignaled(request
->identifier(), kOnSendHeaders
))
835 ClearSignaled(request
->identifier(), kOnBeforeRedirect
);
837 int extra_info_spec
= 0;
838 std::vector
<const EventListener
*> listeners
=
839 GetMatchingListeners(browser_context
, extension_info_map
,
840 keys::kOnSendHeadersEvent
, request
,
842 if (listeners
.empty())
845 base::ListValue args
;
846 base::DictionaryValue
* dict
= new base::DictionaryValue();
847 ExtractRequestInfo(request
, dict
);
848 if (extra_info_spec
& ExtraInfoSpec::REQUEST_HEADERS
)
849 dict
->Set(keys::kRequestHeadersKey
, GetRequestHeadersList(headers
));
852 DispatchEvent(browser_context
, request
, listeners
, args
);
855 int ExtensionWebRequestEventRouter::OnHeadersReceived(
856 void* browser_context
,
857 InfoMap
* extension_info_map
,
858 net::URLRequest
* request
,
859 const net::CompletionCallback
& callback
,
860 const net::HttpResponseHeaders
* original_response_headers
,
861 scoped_refptr
<net::HttpResponseHeaders
>* override_response_headers
,
862 GURL
* allowed_unsafe_redirect_url
) {
863 // We hide events from the system context as well as sensitive requests.
864 if (!browser_context
||
865 WebRequestPermissions::HideRequest(extension_info_map
, request
))
868 bool initialize_blocked_requests
= false;
870 initialize_blocked_requests
|= ProcessDeclarativeRules(
871 browser_context
, extension_info_map
, keys::kOnHeadersReceivedEvent
,
872 request
, ON_HEADERS_RECEIVED
, original_response_headers
);
874 int extra_info_spec
= 0;
875 std::vector
<const EventListener
*> listeners
=
876 GetMatchingListeners(browser_context
, extension_info_map
,
877 keys::kOnHeadersReceivedEvent
, request
,
880 if (!listeners
.empty() &&
881 !GetAndSetSignaled(request
->identifier(), kOnHeadersReceived
)) {
882 base::ListValue args
;
883 base::DictionaryValue
* dict
= new base::DictionaryValue();
884 ExtractRequestInfo(request
, dict
);
885 dict
->SetString(keys::kStatusLineKey
,
886 original_response_headers
->GetStatusLine());
887 dict
->SetInteger(keys::kStatusCodeKey
,
888 original_response_headers
->response_code());
889 if (extra_info_spec
& ExtraInfoSpec::RESPONSE_HEADERS
) {
890 dict
->Set(keys::kResponseHeadersKey
,
891 GetResponseHeadersList(original_response_headers
));
895 initialize_blocked_requests
|=
896 DispatchEvent(browser_context
, request
, listeners
, args
);
899 if (!initialize_blocked_requests
)
900 return net::OK
; // Nobody saw a reason for modifying the request.
902 blocked_requests_
[request
->identifier()].event
= kOnHeadersReceived
;
903 blocked_requests_
[request
->identifier()].is_incognito
|=
904 IsIncognitoBrowserContext(browser_context
);
905 blocked_requests_
[request
->identifier()].request
= request
;
906 blocked_requests_
[request
->identifier()].callback
= callback
;
907 blocked_requests_
[request
->identifier()].net_log
= &request
->net_log();
908 blocked_requests_
[request
->identifier()].override_response_headers
=
909 override_response_headers
;
910 blocked_requests_
[request
->identifier()].original_response_headers
=
911 original_response_headers
;
912 blocked_requests_
[request
->identifier()].new_url
=
913 allowed_unsafe_redirect_url
;
915 if (blocked_requests_
[request
->identifier()].num_handlers_blocking
== 0) {
916 // If there are no blocking handlers, only the declarative rules tried
917 // to modify the request and we can respond synchronously.
918 return ExecuteDeltas(browser_context
, request
->identifier(),
919 false /* call_callback*/);
921 return net::ERR_IO_PENDING
;
925 net::NetworkDelegate::AuthRequiredResponse
926 ExtensionWebRequestEventRouter::OnAuthRequired(
927 void* browser_context
,
928 InfoMap
* extension_info_map
,
929 net::URLRequest
* request
,
930 const net::AuthChallengeInfo
& auth_info
,
931 const net::NetworkDelegate::AuthCallback
& callback
,
932 net::AuthCredentials
* credentials
) {
933 // No browser_context means that this is for authentication challenges in the
934 // system context. Skip in that case. Also skip sensitive requests.
935 if (!browser_context
||
936 WebRequestPermissions::HideRequest(extension_info_map
, request
))
937 return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION
;
939 int extra_info_spec
= 0;
940 std::vector
<const EventListener
*> listeners
=
941 GetMatchingListeners(browser_context
, extension_info_map
,
942 keys::kOnAuthRequiredEvent
, request
,
944 if (listeners
.empty())
945 return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION
;
947 base::ListValue args
;
948 base::DictionaryValue
* dict
= new base::DictionaryValue();
949 ExtractRequestInfo(request
, dict
);
950 dict
->SetBoolean(keys::kIsProxyKey
, auth_info
.is_proxy
);
951 if (!auth_info
.scheme
.empty())
952 dict
->SetString(keys::kSchemeKey
, auth_info
.scheme
);
953 if (!auth_info
.realm
.empty())
954 dict
->SetString(keys::kRealmKey
, auth_info
.realm
);
955 base::DictionaryValue
* challenger
= new base::DictionaryValue();
956 challenger
->SetString(keys::kHostKey
, auth_info
.challenger
.host());
957 challenger
->SetInteger(keys::kPortKey
, auth_info
.challenger
.port());
958 dict
->Set(keys::kChallengerKey
, challenger
);
959 dict
->Set(keys::kStatusLineKey
, GetStatusLine(request
->response_headers()));
960 dict
->SetInteger(keys::kStatusCodeKey
,
961 request
->response_headers()->response_code());
962 if (extra_info_spec
& ExtraInfoSpec::RESPONSE_HEADERS
) {
963 dict
->Set(keys::kResponseHeadersKey
,
964 GetResponseHeadersList(request
->response_headers()));
968 if (DispatchEvent(browser_context
, request
, listeners
, args
)) {
969 blocked_requests_
[request
->identifier()].event
= kOnAuthRequired
;
970 blocked_requests_
[request
->identifier()].is_incognito
|=
971 IsIncognitoBrowserContext(browser_context
);
972 blocked_requests_
[request
->identifier()].request
= request
;
973 blocked_requests_
[request
->identifier()].auth_callback
= callback
;
974 blocked_requests_
[request
->identifier()].auth_credentials
= credentials
;
975 blocked_requests_
[request
->identifier()].net_log
= &request
->net_log();
976 return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_IO_PENDING
;
978 return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION
;
981 void ExtensionWebRequestEventRouter::OnBeforeRedirect(
982 void* browser_context
,
983 InfoMap
* extension_info_map
,
984 net::URLRequest
* request
,
985 const GURL
& new_location
) {
986 // We hide events from the system context as well as sensitive requests.
987 if (!browser_context
||
988 WebRequestPermissions::HideRequest(extension_info_map
, request
))
991 if (GetAndSetSignaled(request
->identifier(), kOnBeforeRedirect
))
994 ClearSignaled(request
->identifier(), kOnBeforeRequest
);
995 ClearSignaled(request
->identifier(), kOnBeforeSendHeaders
);
996 ClearSignaled(request
->identifier(), kOnSendHeaders
);
997 ClearSignaled(request
->identifier(), kOnHeadersReceived
);
999 int extra_info_spec
= 0;
1000 std::vector
<const EventListener
*> listeners
=
1001 GetMatchingListeners(browser_context
, extension_info_map
,
1002 keys::kOnBeforeRedirectEvent
, request
,
1004 if (listeners
.empty())
1007 int http_status_code
= request
->GetResponseCode();
1009 std::string response_ip
= request
->GetSocketAddress().host();
1011 base::ListValue args
;
1012 base::DictionaryValue
* dict
= new base::DictionaryValue();
1013 ExtractRequestInfo(request
, dict
);
1014 dict
->SetString(keys::kRedirectUrlKey
, new_location
.spec());
1015 dict
->SetInteger(keys::kStatusCodeKey
, http_status_code
);
1016 if (!response_ip
.empty())
1017 dict
->SetString(keys::kIpKey
, response_ip
);
1018 dict
->SetBoolean(keys::kFromCache
, request
->was_cached());
1019 dict
->Set(keys::kStatusLineKey
, GetStatusLine(request
->response_headers()));
1020 if (extra_info_spec
& ExtraInfoSpec::RESPONSE_HEADERS
) {
1021 dict
->Set(keys::kResponseHeadersKey
,
1022 GetResponseHeadersList(request
->response_headers()));
1026 DispatchEvent(browser_context
, request
, listeners
, args
);
1029 void ExtensionWebRequestEventRouter::OnResponseStarted(
1030 void* browser_context
,
1031 InfoMap
* extension_info_map
,
1032 net::URLRequest
* request
) {
1033 // We hide events from the system context as well as sensitive requests.
1034 if (!browser_context
||
1035 WebRequestPermissions::HideRequest(extension_info_map
, request
))
1038 // OnResponseStarted is even triggered, when the request was cancelled.
1039 if (request
->status().status() != net::URLRequestStatus::SUCCESS
)
1042 int extra_info_spec
= 0;
1043 std::vector
<const EventListener
*> listeners
=
1044 GetMatchingListeners(browser_context
, extension_info_map
,
1045 keys::kOnResponseStartedEvent
, request
,
1047 if (listeners
.empty())
1050 // UrlRequestFileJobs do not send headers, so we simulate their behavior.
1051 int response_code
= 200;
1052 if (request
->response_headers())
1053 response_code
= request
->response_headers()->response_code();
1055 std::string response_ip
= request
->GetSocketAddress().host();
1057 base::ListValue args
;
1058 base::DictionaryValue
* dict
= new base::DictionaryValue();
1059 ExtractRequestInfo(request
, dict
);
1060 if (!response_ip
.empty())
1061 dict
->SetString(keys::kIpKey
, response_ip
);
1062 dict
->SetBoolean(keys::kFromCache
, request
->was_cached());
1063 dict
->SetInteger(keys::kStatusCodeKey
, response_code
);
1064 dict
->Set(keys::kStatusLineKey
, GetStatusLine(request
->response_headers()));
1065 if (extra_info_spec
& ExtraInfoSpec::RESPONSE_HEADERS
) {
1066 dict
->Set(keys::kResponseHeadersKey
,
1067 GetResponseHeadersList(request
->response_headers()));
1071 DispatchEvent(browser_context
, request
, listeners
, args
);
1074 void ExtensionWebRequestEventRouter::OnCompleted(void* browser_context
,
1075 InfoMap
* extension_info_map
,
1076 net::URLRequest
* request
) {
1077 // We hide events from the system context as well as sensitive requests.
1078 // However, if the request first became sensitive after redirecting we have
1079 // already signaled it and thus we have to signal the end of it. This is
1080 // risk-free because the handler cannot modify the request now.
1081 if (!browser_context
||
1082 (WebRequestPermissions::HideRequest(extension_info_map
, request
) &&
1083 !WasSignaled(*request
)))
1086 request_time_tracker_
->LogRequestEndTime(request
->identifier(),
1089 DCHECK(request
->status().status() == net::URLRequestStatus::SUCCESS
);
1091 DCHECK(!GetAndSetSignaled(request
->identifier(), kOnCompleted
));
1093 ClearPendingCallbacks(request
);
1095 int extra_info_spec
= 0;
1096 std::vector
<const EventListener
*> listeners
=
1097 GetMatchingListeners(browser_context
, extension_info_map
,
1098 keys::kOnCompletedEvent
, request
, &extra_info_spec
);
1099 if (listeners
.empty())
1102 // UrlRequestFileJobs do not send headers, so we simulate their behavior.
1103 int response_code
= 200;
1104 if (request
->response_headers())
1105 response_code
= request
->response_headers()->response_code();
1107 std::string response_ip
= request
->GetSocketAddress().host();
1109 base::ListValue args
;
1110 base::DictionaryValue
* dict
= new base::DictionaryValue();
1111 ExtractRequestInfo(request
, dict
);
1112 dict
->SetInteger(keys::kStatusCodeKey
, response_code
);
1113 if (!response_ip
.empty())
1114 dict
->SetString(keys::kIpKey
, response_ip
);
1115 dict
->SetBoolean(keys::kFromCache
, request
->was_cached());
1116 dict
->Set(keys::kStatusLineKey
, GetStatusLine(request
->response_headers()));
1117 if (extra_info_spec
& ExtraInfoSpec::RESPONSE_HEADERS
) {
1118 dict
->Set(keys::kResponseHeadersKey
,
1119 GetResponseHeadersList(request
->response_headers()));
1123 DispatchEvent(browser_context
, request
, listeners
, args
);
1126 void ExtensionWebRequestEventRouter::OnErrorOccurred(
1127 void* browser_context
,
1128 InfoMap
* extension_info_map
,
1129 net::URLRequest
* request
,
1131 // We hide events from the system context as well as sensitive requests.
1132 // However, if the request first became sensitive after redirecting we have
1133 // already signaled it and thus we have to signal the end of it. This is
1134 // risk-free because the handler cannot modify the request now.
1135 if (!browser_context
||
1136 (WebRequestPermissions::HideRequest(extension_info_map
, request
) &&
1137 !WasSignaled(*request
)))
1140 request_time_tracker_
->LogRequestEndTime(request
->identifier(),
1143 DCHECK(request
->status().status() == net::URLRequestStatus::FAILED
||
1144 request
->status().status() == net::URLRequestStatus::CANCELED
);
1146 DCHECK(!GetAndSetSignaled(request
->identifier(), kOnErrorOccurred
));
1148 ClearPendingCallbacks(request
);
1150 int extra_info_spec
= 0;
1151 std::vector
<const EventListener
*> listeners
=
1152 GetMatchingListeners(browser_context
, extension_info_map
,
1153 web_request::OnErrorOccurred::kEventName
, request
,
1155 if (listeners
.empty())
1158 base::ListValue args
;
1159 base::DictionaryValue
* dict
= new base::DictionaryValue();
1160 ExtractRequestInfo(request
, dict
);
1162 std::string response_ip
= request
->GetSocketAddress().host();
1163 if (!response_ip
.empty())
1164 dict
->SetString(keys::kIpKey
, response_ip
);
1166 dict
->SetBoolean(keys::kFromCache
, request
->was_cached());
1167 dict
->SetString(keys::kErrorKey
,
1168 net::ErrorToString(request
->status().error()));
1171 DispatchEvent(browser_context
, request
, listeners
, args
);
1174 void ExtensionWebRequestEventRouter::OnURLRequestDestroyed(
1175 void* browser_context
, net::URLRequest
* request
) {
1176 ClearPendingCallbacks(request
);
1178 signaled_requests_
.erase(request
->identifier());
1180 request_time_tracker_
->LogRequestEndTime(request
->identifier(),
1184 void ExtensionWebRequestEventRouter::ClearPendingCallbacks(
1185 net::URLRequest
* request
) {
1186 blocked_requests_
.erase(request
->identifier());
1189 bool ExtensionWebRequestEventRouter::DispatchEvent(
1190 void* browser_context
,
1191 net::URLRequest
* request
,
1192 const std::vector
<const EventListener
*>& listeners
,
1193 const base::ListValue
& args
) {
1194 // TODO(mpcomplete): Consider consolidating common (extension_id,json_args)
1195 // pairs into a single message sent to a list of sub_event_names.
1196 int num_handlers_blocking
= 0;
1197 for (std::vector
<const EventListener
*>::const_iterator it
= listeners
.begin();
1198 it
!= listeners
.end(); ++it
) {
1199 // Filter out the optional keys that this listener didn't request.
1200 scoped_ptr
<base::ListValue
> args_filtered(args
.DeepCopy());
1201 base::DictionaryValue
* dict
= NULL
;
1202 CHECK(args_filtered
->GetDictionary(0, &dict
) && dict
);
1203 if (!((*it
)->extra_info_spec
& ExtraInfoSpec::REQUEST_HEADERS
))
1204 dict
->Remove(keys::kRequestHeadersKey
, NULL
);
1205 if (!((*it
)->extra_info_spec
& ExtraInfoSpec::RESPONSE_HEADERS
))
1206 dict
->Remove(keys::kResponseHeadersKey
, NULL
);
1208 EventRouter::DispatchEvent(
1209 (*it
)->ipc_sender
.get(), browser_context
, (*it
)->extension_id
,
1210 (*it
)->sub_event_name
, args_filtered
.Pass(),
1211 EventRouter::USER_GESTURE_UNKNOWN
, EventFilteringInfo());
1212 if ((*it
)->extra_info_spec
&
1213 (ExtraInfoSpec::BLOCKING
| ExtraInfoSpec::ASYNC_BLOCKING
)) {
1214 (*it
)->blocked_requests
.insert(request
->identifier());
1215 // If this is the first delegate blocking the request, go ahead and log
1217 if (num_handlers_blocking
== 0) {
1218 std::string delegate_info
=
1219 l10n_util::GetStringFUTF8(IDS_LOAD_STATE_PARAMETER_EXTENSION
,
1220 base::UTF8ToUTF16((*it
)->extension_name
));
1221 // LobAndReport allows extensions that block requests to be displayed in
1222 // the load status bar.
1223 request
->LogAndReportBlockedBy(delegate_info
.c_str());
1225 ++num_handlers_blocking
;
1229 if (num_handlers_blocking
> 0) {
1230 blocked_requests_
[request
->identifier()].request
= request
;
1231 blocked_requests_
[request
->identifier()].is_incognito
|=
1232 IsIncognitoBrowserContext(browser_context
);
1233 blocked_requests_
[request
->identifier()].num_handlers_blocking
+=
1234 num_handlers_blocking
;
1235 blocked_requests_
[request
->identifier()].blocking_time
= base::Time::Now();
1243 void ExtensionWebRequestEventRouter::OnEventHandled(
1244 void* browser_context
,
1245 const std::string
& extension_id
,
1246 const std::string
& event_name
,
1247 const std::string
& sub_event_name
,
1249 EventResponse
* response
) {
1250 // TODO(robwu): Does this also work with webviews? operator< (used by find)
1251 // takes the webview ID into account, which is not set on |listener|.
1252 EventListener listener
;
1253 listener
.extension_id
= extension_id
;
1254 listener
.sub_event_name
= sub_event_name
;
1256 // The listener may have been removed (e.g. due to the process going away)
1257 // before we got here.
1258 std::set
<EventListener
>::iterator found
=
1259 listeners_
[browser_context
][event_name
].find(listener
);
1260 if (found
!= listeners_
[browser_context
][event_name
].end())
1261 found
->blocked_requests
.erase(request_id
);
1263 DecrementBlockCount(
1264 browser_context
, extension_id
, event_name
, request_id
, response
);
1267 bool ExtensionWebRequestEventRouter::AddEventListener(
1268 void* browser_context
,
1269 const std::string
& extension_id
,
1270 const std::string
& extension_name
,
1271 const std::string
& event_name
,
1272 const std::string
& sub_event_name
,
1273 const RequestFilter
& filter
,
1274 int extra_info_spec
,
1275 int embedder_process_id
,
1276 int web_view_instance_id
,
1277 base::WeakPtr
<IPC::Sender
> ipc_sender
) {
1278 if (!IsWebRequestEvent(event_name
))
1281 EventListener listener
;
1282 listener
.extension_id
= extension_id
;
1283 listener
.extension_name
= extension_name
;
1284 listener
.sub_event_name
= sub_event_name
;
1285 listener
.filter
= filter
;
1286 listener
.extra_info_spec
= extra_info_spec
;
1287 listener
.ipc_sender
= ipc_sender
;
1288 listener
.embedder_process_id
= embedder_process_id
;
1289 listener
.web_view_instance_id
= web_view_instance_id
;
1290 if (listener
.web_view_instance_id
) {
1291 content::RecordAction(
1292 base::UserMetricsAction("WebView.WebRequest.AddListener"));
1295 if (listeners_
[browser_context
][event_name
].count(listener
) != 0u) {
1296 // This is likely an abuse of the API by a malicious extension.
1299 listeners_
[browser_context
][event_name
].insert(listener
);
1303 void ExtensionWebRequestEventRouter::RemoveEventListener(
1304 void* browser_context
,
1305 const std::string
& extension_id
,
1306 const std::string
& sub_event_name
,
1307 int embedder_process_id
,
1308 int web_view_instance_id
) {
1309 std::string event_name
= EventRouter::GetBaseEventName(sub_event_name
);
1310 DCHECK(IsWebRequestEvent(event_name
));
1312 EventListener listener
;
1313 listener
.extension_id
= extension_id
;
1314 listener
.sub_event_name
= sub_event_name
;
1315 listener
.embedder_process_id
= embedder_process_id
;
1316 listener
.web_view_instance_id
= web_view_instance_id
;
1318 std::set
<EventListener
>& event_listeners
=
1319 listeners_
[browser_context
][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
= event_listeners
.find(listener
);
1324 if (found
== event_listeners
.end())
1327 CHECK_EQ(event_listeners
.count(listener
), 1u) <<
1328 "extension=" << extension_id
<< " event=" << event_name
;
1330 // Unblock any request that this event listener may have been blocking.
1331 for (std::set
<uint64
>::iterator it
= found
->blocked_requests
.begin();
1332 it
!= found
->blocked_requests
.end(); ++it
) {
1333 DecrementBlockCount(browser_context
, extension_id
, event_name
, *it
, NULL
);
1336 event_listeners
.erase(listener
);
1338 helpers::ClearCacheOnNavigation();
1341 void ExtensionWebRequestEventRouter::RemoveWebViewEventListeners(
1342 void* browser_context
,
1343 int embedder_process_id
,
1344 int web_view_instance_id
) {
1345 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
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 (const auto& event_iter
: map_for_browser_context
) {
1352 // Construct a listeners_to_delete vector so that we don't modify the set of
1353 // listeners as we iterate through it.
1354 std::vector
<EventListener
> listeners_to_delete
;
1355 const std::set
<EventListener
>& listeners
= event_iter
.second
;
1356 for (const auto& listener
: listeners
) {
1357 if (listener
.embedder_process_id
== embedder_process_id
&&
1358 listener
.web_view_instance_id
== web_view_instance_id
) {
1359 listeners_to_delete
.push_back(listener
);
1362 // Remove the listeners selected for deletion.
1363 for (const auto& listener
: listeners_to_delete
) {
1364 RemoveEventListenerOnIOThread(
1366 listener
.extension_id
,
1367 listener
.sub_event_name
,
1368 listener
.embedder_process_id
,
1369 listener
.web_view_instance_id
);
1374 void ExtensionWebRequestEventRouter::OnOTRBrowserContextCreated(
1375 void* original_browser_context
, void* otr_browser_context
) {
1376 cross_browser_context_map_
[original_browser_context
] =
1377 std::make_pair(false, otr_browser_context
);
1378 cross_browser_context_map_
[otr_browser_context
] =
1379 std::make_pair(true, original_browser_context
);
1382 void ExtensionWebRequestEventRouter::OnOTRBrowserContextDestroyed(
1383 void* original_browser_context
, void* otr_browser_context
) {
1384 cross_browser_context_map_
.erase(otr_browser_context
);
1385 cross_browser_context_map_
.erase(original_browser_context
);
1388 void ExtensionWebRequestEventRouter::AddCallbackForPageLoad(
1389 const base::Closure
& callback
) {
1390 callbacks_for_page_load_
.push_back(callback
);
1393 bool ExtensionWebRequestEventRouter::IsPageLoad(
1394 net::URLRequest
* request
) const {
1395 bool is_main_frame
= false;
1397 bool parent_is_main_frame
= false;
1398 int parent_frame_id
= -1;
1399 int render_process_host_id
= -1;
1400 int routing_id
= -1;
1401 ResourceType resource_type
= content::RESOURCE_TYPE_LAST_TYPE
;
1403 ExtractRequestInfoDetails(request
, &is_main_frame
, &frame_id
,
1404 &parent_is_main_frame
, &parent_frame_id
,
1405 &render_process_host_id
,
1406 &routing_id
, &resource_type
);
1408 return resource_type
== content::RESOURCE_TYPE_MAIN_FRAME
;
1411 void ExtensionWebRequestEventRouter::NotifyPageLoad() {
1412 for (CallbacksForPageLoad::const_iterator i
=
1413 callbacks_for_page_load_
.begin();
1414 i
!= callbacks_for_page_load_
.end(); ++i
) {
1417 callbacks_for_page_load_
.clear();
1420 void* ExtensionWebRequestEventRouter::GetCrossBrowserContext(
1421 void* browser_context
) const {
1422 CrossBrowserContextMap::const_iterator cross_browser_context
=
1423 cross_browser_context_map_
.find(browser_context
);
1424 if (cross_browser_context
== cross_browser_context_map_
.end())
1426 return cross_browser_context
->second
.second
;
1429 bool ExtensionWebRequestEventRouter::IsIncognitoBrowserContext(
1430 void* browser_context
) const {
1431 CrossBrowserContextMap::const_iterator cross_browser_context
=
1432 cross_browser_context_map_
.find(browser_context
);
1433 if (cross_browser_context
== cross_browser_context_map_
.end())
1435 return cross_browser_context
->second
.first
;
1438 bool ExtensionWebRequestEventRouter::WasSignaled(
1439 const net::URLRequest
& request
) const {
1440 SignaledRequestMap::const_iterator flag
=
1441 signaled_requests_
.find(request
.identifier());
1442 return (flag
!= signaled_requests_
.end()) && (flag
->second
!= 0);
1445 void ExtensionWebRequestEventRouter::GetMatchingListenersImpl(
1446 void* browser_context
,
1447 net::URLRequest
* request
,
1448 InfoMap
* extension_info_map
,
1449 bool crosses_incognito
,
1450 const std::string
& event_name
,
1452 int render_process_host_id
,
1454 ResourceType resource_type
,
1455 bool is_async_request
,
1456 bool is_request_from_extension
,
1457 int* extra_info_spec
,
1458 std::vector
<const ExtensionWebRequestEventRouter::EventListener
*>*
1459 matching_listeners
) {
1460 std::string
web_request_event_name(event_name
);
1461 WebViewRendererState::WebViewInfo web_view_info
;
1462 bool is_web_view_guest
= WebViewRendererState::GetInstance()->GetInfo(
1463 render_process_host_id
, routing_id
, &web_view_info
);
1464 if (is_web_view_guest
) {
1465 web_request_event_name
.replace(
1466 0, sizeof(kWebRequestEventPrefix
) - 1, webview::kWebViewEventPrefix
);
1469 std::set
<EventListener
>& listeners
=
1470 listeners_
[browser_context
][web_request_event_name
];
1471 for (std::set
<EventListener
>::iterator it
= listeners
.begin();
1472 it
!= listeners
.end(); ++it
) {
1473 if (!it
->ipc_sender
.get()) {
1474 // The IPC sender has been deleted. This listener will be removed soon
1475 // via a call to RemoveEventListener. For now, just skip it.
1479 if (is_web_view_guest
&&
1480 (it
->embedder_process_id
!= web_view_info
.embedder_process_id
||
1481 it
->web_view_instance_id
!= web_view_info
.instance_id
))
1484 // Filter requests from other extensions / apps. This does not work for
1485 // content scripts, or extension pages in non-extension processes.
1486 if (is_request_from_extension
&&
1487 it
->embedder_process_id
!= render_process_host_id
)
1490 if (!it
->filter
.urls
.is_empty() && !it
->filter
.urls
.MatchesURL(url
))
1492 if (web_request_event_router_delegate_
&&
1493 web_request_event_router_delegate_
->OnGetMatchingListenersImplCheck(
1494 it
->filter
.tab_id
, it
->filter
.window_id
, request
))
1496 if (!it
->filter
.types
.empty() &&
1497 std::find(it
->filter
.types
.begin(), it
->filter
.types
.end(),
1498 resource_type
) == it
->filter
.types
.end())
1501 if (!is_web_view_guest
&& !WebRequestPermissions::CanExtensionAccessURL(
1502 extension_info_map
, it
->extension_id
, url
, crosses_incognito
,
1503 WebRequestPermissions::REQUIRE_HOST_PERMISSION
))
1506 bool blocking_listener
=
1507 (it
->extra_info_spec
&
1508 (ExtraInfoSpec::BLOCKING
| ExtraInfoSpec::ASYNC_BLOCKING
)) != 0;
1510 // We do not want to notify extensions about XHR requests that are
1511 // triggered by themselves. This is a workaround to prevent deadlocks
1512 // in case of synchronous XHR requests that block the extension renderer
1513 // and therefore prevent the extension from processing the request
1514 // handler. This is only a problem for blocking listeners.
1515 // http://crbug.com/105656
1516 bool synchronous_xhr_from_extension
=
1517 !is_async_request
&& is_request_from_extension
&&
1518 resource_type
== content::RESOURCE_TYPE_XHR
;
1520 // Only send webRequest events for URLs the extension has access to.
1521 if (blocking_listener
&& synchronous_xhr_from_extension
)
1524 matching_listeners
->push_back(&(*it
));
1525 *extra_info_spec
|= it
->extra_info_spec
;
1529 std::vector
<const ExtensionWebRequestEventRouter::EventListener
*>
1530 ExtensionWebRequestEventRouter::GetMatchingListeners(
1531 void* browser_context
,
1532 InfoMap
* extension_info_map
,
1533 const std::string
& event_name
,
1534 net::URLRequest
* request
,
1535 int* extra_info_spec
) {
1536 // TODO(mpcomplete): handle browser_context == NULL (should collect all
1538 *extra_info_spec
= 0;
1540 bool is_main_frame
= false;
1542 bool parent_is_main_frame
= false;
1543 int parent_frame_id
= -1;
1544 int render_process_host_id
= -1;
1545 int routing_id
= -1;
1546 ResourceType resource_type
= content::RESOURCE_TYPE_LAST_TYPE
;
1547 const GURL
& url
= request
->url();
1549 ExtractRequestInfoDetails(request
, &is_main_frame
, &frame_id
,
1550 &parent_is_main_frame
, &parent_frame_id
,
1551 &render_process_host_id
,
1552 &routing_id
, &resource_type
);
1554 std::vector
<const ExtensionWebRequestEventRouter::EventListener
*>
1557 bool is_request_from_extension
=
1558 IsRequestFromExtension(request
, extension_info_map
);
1560 const ResourceRequestInfo
* info
= ResourceRequestInfo::ForRequest(request
);
1561 // We are conservative here and assume requests are asynchronous in case
1562 // we don't have an info object. We don't want to risk a deadlock.
1563 bool is_async_request
= !info
|| info
->IsAsync();
1565 GetMatchingListenersImpl(
1566 browser_context
, request
, extension_info_map
, false, event_name
,
1567 url
, render_process_host_id
, routing_id
, resource_type
,
1568 is_async_request
, is_request_from_extension
, extra_info_spec
,
1569 &matching_listeners
);
1570 void* cross_browser_context
= GetCrossBrowserContext(browser_context
);
1571 if (cross_browser_context
) {
1572 GetMatchingListenersImpl(
1573 cross_browser_context
, request
, extension_info_map
, true, event_name
,
1574 url
, render_process_host_id
, routing_id
, resource_type
,
1575 is_async_request
, is_request_from_extension
, extra_info_spec
,
1576 &matching_listeners
);
1579 return matching_listeners
;
1584 helpers::EventResponseDelta
* CalculateDelta(
1585 ExtensionWebRequestEventRouter::BlockedRequest
* blocked_request
,
1586 ExtensionWebRequestEventRouter::EventResponse
* response
) {
1587 switch (blocked_request
->event
) {
1588 case ExtensionWebRequestEventRouter::kOnBeforeRequest
:
1589 return helpers::CalculateOnBeforeRequestDelta(
1590 response
->extension_id
, response
->extension_install_time
,
1591 response
->cancel
, response
->new_url
);
1592 case ExtensionWebRequestEventRouter::kOnBeforeSendHeaders
: {
1593 net::HttpRequestHeaders
* old_headers
= blocked_request
->request_headers
;
1594 net::HttpRequestHeaders
* new_headers
= response
->request_headers
.get();
1595 return helpers::CalculateOnBeforeSendHeadersDelta(
1596 response
->extension_id
, response
->extension_install_time
,
1597 response
->cancel
, old_headers
, new_headers
);
1599 case ExtensionWebRequestEventRouter::kOnHeadersReceived
: {
1600 const net::HttpResponseHeaders
* old_headers
=
1601 blocked_request
->original_response_headers
.get();
1602 helpers::ResponseHeaders
* new_headers
=
1603 response
->response_headers
.get();
1604 return helpers::CalculateOnHeadersReceivedDelta(
1605 response
->extension_id
,
1606 response
->extension_install_time
,
1612 case ExtensionWebRequestEventRouter::kOnAuthRequired
:
1613 return helpers::CalculateOnAuthRequiredDelta(
1614 response
->extension_id
, response
->extension_install_time
,
1615 response
->cancel
, &response
->auth_credentials
);
1623 base::Value
* SerializeResponseHeaders(const helpers::ResponseHeaders
& headers
) {
1624 scoped_ptr
<base::ListValue
> serialized_headers(new base::ListValue());
1625 for (helpers::ResponseHeaders::const_iterator i
= headers
.begin();
1626 i
!= headers
.end(); ++i
) {
1627 serialized_headers
->Append(
1628 helpers::CreateHeaderDictionary(i
->first
, i
->second
));
1630 return serialized_headers
.release();
1633 // Convert a RequestCookieModifications/ResponseCookieModifications object to a
1634 // base::ListValue which summarizes the changes made. This is templated since
1635 // the two types (request/response) are different but contain essentially the
1637 template<typename CookieType
>
1638 base::ListValue
* SummarizeCookieModifications(
1639 const std::vector
<linked_ptr
<CookieType
> >& modifications
) {
1640 scoped_ptr
<base::ListValue
> cookie_modifications(new base::ListValue());
1641 for (typename
std::vector
<linked_ptr
<CookieType
> >::const_iterator i
=
1642 modifications
.begin();
1643 i
!= modifications
.end(); ++i
) {
1644 scoped_ptr
<base::DictionaryValue
> summary(new base::DictionaryValue());
1645 const CookieType
& mod
= *i
->get();
1648 summary
->SetString(activity_log::kCookieModificationTypeKey
,
1649 activity_log::kCookieModificationAdd
);
1652 summary
->SetString(activity_log::kCookieModificationTypeKey
,
1653 activity_log::kCookieModificationEdit
);
1655 case helpers::REMOVE
:
1656 summary
->SetString(activity_log::kCookieModificationTypeKey
,
1657 activity_log::kCookieModificationRemove
);
1661 if (mod
.filter
->name
)
1662 summary
->SetString(activity_log::kCookieFilterNameKey
,
1663 *mod
.modification
->name
);
1664 if (mod
.filter
->domain
)
1665 summary
->SetString(activity_log::kCookieFilterDomainKey
,
1666 *mod
.modification
->name
);
1668 if (mod
.modification
) {
1669 if (mod
.modification
->name
)
1670 summary
->SetString(activity_log::kCookieModDomainKey
,
1671 *mod
.modification
->name
);
1672 if (mod
.modification
->domain
)
1673 summary
->SetString(activity_log::kCookieModDomainKey
,
1674 *mod
.modification
->name
);
1676 cookie_modifications
->Append(summary
.release());
1678 return cookie_modifications
.release();
1681 // Converts an EventResponseDelta object to a dictionary value suitable for the
1683 scoped_ptr
<base::DictionaryValue
> SummarizeResponseDelta(
1684 const std::string
& event_name
,
1685 const helpers::EventResponseDelta
& delta
) {
1686 scoped_ptr
<base::DictionaryValue
> details(new base::DictionaryValue());
1688 details
->SetBoolean(activity_log::kCancelKey
, true);
1690 if (!delta
.new_url
.is_empty()) {
1691 details
->SetString(activity_log::kNewUrlKey
, delta
.new_url
.spec());
1694 scoped_ptr
<base::ListValue
> modified_headers(new base::ListValue());
1695 net::HttpRequestHeaders::Iterator
iter(delta
.modified_request_headers
);
1696 while (iter
.GetNext()) {
1697 modified_headers
->Append(
1698 helpers::CreateHeaderDictionary(iter
.name(), iter
.value()));
1700 if (!modified_headers
->empty()) {
1701 details
->Set(activity_log::kModifiedRequestHeadersKey
,
1702 modified_headers
.release());
1705 scoped_ptr
<base::ListValue
> deleted_headers(new base::ListValue());
1706 deleted_headers
->AppendStrings(delta
.deleted_request_headers
);
1707 if (!deleted_headers
->empty()) {
1708 details
->Set(activity_log::kDeletedRequestHeadersKey
,
1709 deleted_headers
.release());
1712 if (!delta
.added_response_headers
.empty()) {
1713 details
->Set(activity_log::kAddedRequestHeadersKey
,
1714 SerializeResponseHeaders(delta
.added_response_headers
));
1716 if (!delta
.deleted_response_headers
.empty()) {
1717 details
->Set(activity_log::kDeletedResponseHeadersKey
,
1718 SerializeResponseHeaders(delta
.deleted_response_headers
));
1720 if (delta
.auth_credentials
) {
1722 activity_log::kAuthCredentialsKey
,
1723 base::UTF16ToUTF8(delta
.auth_credentials
->username()) + ":*");
1726 if (!delta
.response_cookie_modifications
.empty()) {
1728 activity_log::kResponseCookieModificationsKey
,
1729 SummarizeCookieModifications(delta
.response_cookie_modifications
));
1732 return details
.Pass();
1737 void ExtensionWebRequestEventRouter::LogExtensionActivity(
1738 void* browser_context_id
,
1740 const std::string
& extension_id
,
1742 const std::string
& api_call
,
1743 scoped_ptr
<base::DictionaryValue
> details
) {
1744 if (!BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
1745 BrowserThread::PostTask(
1748 base::Bind(&ExtensionWebRequestEventRouter::LogExtensionActivity
,
1749 base::Unretained(this),
1755 base::Passed(&details
)));
1757 if (web_request_event_router_delegate_
) {
1758 web_request_event_router_delegate_
->LogExtensionActivity(
1759 reinterpret_cast<content::BrowserContext
*>(browser_context_id
),
1760 is_incognito
, extension_id
, url
, api_call
, details
.Pass());
1765 void ExtensionWebRequestEventRouter::DecrementBlockCount(
1766 void* browser_context
,
1767 const std::string
& extension_id
,
1768 const std::string
& event_name
,
1770 EventResponse
* response
) {
1771 scoped_ptr
<EventResponse
> response_scoped(response
);
1773 // It's possible that this request was deleted, or cancelled by a previous
1774 // event handler. If so, ignore this response.
1775 if (blocked_requests_
.find(request_id
) == blocked_requests_
.end())
1778 BlockedRequest
& blocked_request
= blocked_requests_
[request_id
];
1779 int num_handlers_blocking
= --blocked_request
.num_handlers_blocking
;
1780 CHECK_GE(num_handlers_blocking
, 0);
1783 helpers::EventResponseDelta
* delta
=
1784 CalculateDelta(&blocked_request
, response
);
1786 LogExtensionActivity(browser_context
,
1787 blocked_request
.is_incognito
,
1789 blocked_request
.request
->url(),
1791 SummarizeResponseDelta(event_name
, *delta
));
1793 blocked_request
.response_deltas
.push_back(
1794 linked_ptr
<helpers::EventResponseDelta
>(delta
));
1797 base::TimeDelta block_time
=
1798 base::Time::Now() - blocked_request
.blocking_time
;
1799 if (!extension_id
.empty()) {
1800 request_time_tracker_
->IncrementExtensionBlockTime(
1801 extension_id
, request_id
, block_time
);
1803 // |extension_id| is empty for requests blocked on startup waiting for the
1804 // declarative rules to be read from disk.
1805 UMA_HISTOGRAM_TIMES("Extensions.NetworkDelayStartup", block_time
);
1808 if (num_handlers_blocking
== 0) {
1809 blocked_request
.request
->LogUnblocked();
1810 ExecuteDeltas(browser_context
, request_id
, true);
1812 // Update the URLRequest to make sure it's tagged with an extension that's
1813 // still blocking it. This may end up being the same extension as before.
1814 std::set
<EventListener
>& listeners
=
1815 listeners_
[browser_context
][event_name
];
1817 for (std::set
<EventListener
>::iterator it
= listeners
.begin();
1818 it
!= listeners
.end(); ++it
) {
1819 if (it
->blocked_requests
.count(request_id
) == 0)
1821 std::string delegate_info
=
1822 l10n_util::GetStringFUTF8(IDS_LOAD_STATE_PARAMETER_EXTENSION
,
1823 base::UTF8ToUTF16(it
->extension_name
));
1824 blocked_request
.request
->LogAndReportBlockedBy(delegate_info
.c_str());
1830 void ExtensionWebRequestEventRouter::SendMessages(
1831 void* browser_context
,
1832 const BlockedRequest
& blocked_request
) {
1833 const helpers::EventResponseDeltas
& deltas
= blocked_request
.response_deltas
;
1834 for (helpers::EventResponseDeltas::const_iterator delta
= deltas
.begin();
1835 delta
!= deltas
.end(); ++delta
) {
1836 const std::set
<std::string
>& messages
= (*delta
)->messages_to_extension
;
1837 for (std::set
<std::string
>::const_iterator message
= messages
.begin();
1838 message
!= messages
.end(); ++message
) {
1839 scoped_ptr
<base::DictionaryValue
> argument(new base::DictionaryValue
);
1840 ExtractRequestInfo(blocked_request
.request
, argument
.get());
1841 WebViewRendererState::WebViewInfo web_view_info
;
1842 bool is_web_view_guest
= GetWebViewInfo(blocked_request
.request
,
1844 argument
->SetString(keys::kMessageKey
, *message
);
1845 argument
->SetString(keys::kStageKey
,
1846 GetRequestStageAsString(blocked_request
.event
));
1848 BrowserThread::PostTask(
1851 base::Bind(&SendOnMessageEventOnUI
,
1853 (*delta
)->extension_id
,
1856 base::Passed(&argument
)));
1861 int ExtensionWebRequestEventRouter::ExecuteDeltas(
1862 void* browser_context
,
1864 bool call_callback
) {
1865 BlockedRequest
& blocked_request
= blocked_requests_
[request_id
];
1866 CHECK(blocked_request
.num_handlers_blocking
== 0);
1867 helpers::EventResponseDeltas
& deltas
= blocked_request
.response_deltas
;
1868 base::TimeDelta block_time
=
1869 base::Time::Now() - blocked_request
.blocking_time
;
1870 request_time_tracker_
->IncrementTotalBlockTime(request_id
, block_time
);
1872 bool credentials_set
= false;
1874 deltas
.sort(&helpers::InDecreasingExtensionInstallationTimeOrder
);
1875 WarningSet warnings
;
1877 bool canceled
= false;
1878 helpers::MergeCancelOfResponses(
1879 blocked_request
.response_deltas
,
1881 blocked_request
.net_log
);
1883 if (blocked_request
.event
== kOnBeforeRequest
) {
1884 CHECK(!blocked_request
.callback
.is_null());
1885 helpers::MergeOnBeforeRequestResponses(
1886 blocked_request
.response_deltas
,
1887 blocked_request
.new_url
,
1889 blocked_request
.net_log
);
1890 } else if (blocked_request
.event
== kOnBeforeSendHeaders
) {
1891 CHECK(!blocked_request
.callback
.is_null());
1892 helpers::MergeOnBeforeSendHeadersResponses(
1893 blocked_request
.response_deltas
,
1894 blocked_request
.request_headers
,
1896 blocked_request
.net_log
);
1897 } else if (blocked_request
.event
== kOnHeadersReceived
) {
1898 CHECK(!blocked_request
.callback
.is_null());
1899 helpers::MergeOnHeadersReceivedResponses(
1900 blocked_request
.response_deltas
,
1901 blocked_request
.original_response_headers
.get(),
1902 blocked_request
.override_response_headers
,
1903 blocked_request
.new_url
,
1905 blocked_request
.net_log
);
1906 } else if (blocked_request
.event
== kOnAuthRequired
) {
1907 CHECK(blocked_request
.callback
.is_null());
1908 CHECK(!blocked_request
.auth_callback
.is_null());
1909 credentials_set
= helpers::MergeOnAuthRequiredResponses(
1910 blocked_request
.response_deltas
,
1911 blocked_request
.auth_credentials
,
1913 blocked_request
.net_log
);
1918 SendMessages(browser_context
, blocked_request
);
1920 if (!warnings
.empty()) {
1921 BrowserThread::PostTask(
1924 base::Bind(&WarningService::NotifyWarningsOnUI
,
1925 browser_context
, warnings
));
1929 request_time_tracker_
->SetRequestCanceled(request_id
);
1930 } else if (blocked_request
.new_url
&&
1931 !blocked_request
.new_url
->is_empty()) {
1932 request_time_tracker_
->SetRequestRedirected(request_id
);
1935 // This triggers onErrorOccurred if canceled is true.
1936 int rv
= canceled
? net::ERR_BLOCKED_BY_CLIENT
: net::OK
;
1938 if (!blocked_request
.callback
.is_null()) {
1939 net::CompletionCallback callback
= blocked_request
.callback
;
1940 // Ensure that request is removed before callback because the callback
1941 // might trigger the next event.
1942 blocked_requests_
.erase(request_id
);
1945 } else if (!blocked_request
.auth_callback
.is_null()) {
1946 net::NetworkDelegate::AuthRequiredResponse response
=
1947 net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION
;
1949 response
= net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_CANCEL_AUTH
;
1950 } else if (credentials_set
) {
1951 response
= net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_SET_AUTH
;
1953 net::NetworkDelegate::AuthCallback callback
= blocked_request
.auth_callback
;
1954 blocked_requests_
.erase(request_id
);
1956 callback
.Run(response
);
1958 blocked_requests_
.erase(request_id
);
1963 bool ExtensionWebRequestEventRouter::ProcessDeclarativeRules(
1964 void* browser_context
,
1965 InfoMap
* extension_info_map
,
1966 const std::string
& event_name
,
1967 net::URLRequest
* request
,
1968 RequestStage request_stage
,
1969 const net::HttpResponseHeaders
* original_response_headers
) {
1970 WebViewRendererState::WebViewInfo web_view_info
;
1971 bool is_web_view_guest
= GetWebViewInfo(request
, &web_view_info
);
1972 int rules_registry_id
= is_web_view_guest
1973 ? web_view_info
.rules_registry_id
1974 : RulesRegistryService::kDefaultRulesRegistryID
;
1976 RulesRegistryKey
rules_key(browser_context
, rules_registry_id
);
1977 // If this check fails, check that the active stages are up-to-date in
1978 // extensions/browser/api/declarative_webrequest/request_stage.h .
1979 DCHECK(request_stage
& kActiveStages
);
1981 // Rules of the current |browser_context| may apply but we need to check also
1982 // whether there are applicable rules from extensions whose background page
1983 // spans from regular to incognito mode.
1985 // First parameter identifies the registry, the second indicates whether the
1986 // registry belongs to the cross browser_context.
1987 typedef std::pair
<WebRequestRulesRegistry
*, bool> RelevantRegistry
;
1988 typedef std::vector
<RelevantRegistry
> RelevantRegistries
;
1989 RelevantRegistries relevant_registries
;
1991 if (rules_registries_
.find(rules_key
) != rules_registries_
.end()) {
1992 relevant_registries
.push_back(
1993 std::make_pair(rules_registries_
[rules_key
].get(), false));
1996 void* cross_browser_context
= GetCrossBrowserContext(browser_context
);
1997 RulesRegistryKey
cross_browser_context_rules_key(cross_browser_context
,
1999 if (cross_browser_context
&&
2000 rules_registries_
.find(cross_browser_context_rules_key
) !=
2001 rules_registries_
.end()) {
2002 relevant_registries
.push_back(
2004 rules_registries_
[cross_browser_context_rules_key
].get(), true));
2007 // The following block is experimentally enabled and its impact on load time
2008 // logged with UMA Extensions.NetworkDelayRegistryLoad. crbug.com/175961
2009 for (RelevantRegistries::iterator i
= relevant_registries
.begin();
2010 i
!= relevant_registries
.end(); ++i
) {
2011 WebRequestRulesRegistry
* rules_registry
= i
->first
;
2012 if (!rules_registry
->ready().is_signaled()) {
2013 // The rules registry is still loading. Block this request until it
2015 rules_registry
->ready().Post(
2017 base::Bind(&ExtensionWebRequestEventRouter::OnRulesRegistryReady
,
2021 request
->identifier(),
2023 blocked_requests_
[request
->identifier()].num_handlers_blocking
++;
2024 blocked_requests_
[request
->identifier()].request
= request
;
2025 blocked_requests_
[request
->identifier()].is_incognito
|=
2026 IsIncognitoBrowserContext(browser_context
);
2027 blocked_requests_
[request
->identifier()].blocking_time
=
2029 blocked_requests_
[request
->identifier()].original_response_headers
=
2030 original_response_headers
;
2031 blocked_requests_
[request
->identifier()].extension_info_map
=
2037 base::Time start
= base::Time::Now();
2039 bool deltas_created
= false;
2040 for (RelevantRegistries::iterator i
= relevant_registries
.begin();
2041 i
!= relevant_registries
.end(); ++i
) {
2042 WebRequestRulesRegistry
* rules_registry
= i
->first
;
2043 helpers::EventResponseDeltas result
= rules_registry
->CreateDeltas(
2045 WebRequestData(request
, request_stage
, original_response_headers
),
2048 if (!result
.empty()) {
2049 helpers::EventResponseDeltas
& deltas
=
2050 blocked_requests_
[request
->identifier()].response_deltas
;
2051 deltas
.insert(deltas
.end(), result
.begin(), result
.end());
2052 deltas_created
= true;
2056 base::TimeDelta elapsed_time
= start
- base::Time::Now();
2057 UMA_HISTOGRAM_TIMES("Extensions.DeclarativeWebRequestNetworkDelay",
2060 return deltas_created
;
2063 void ExtensionWebRequestEventRouter::OnRulesRegistryReady(
2064 void* browser_context
,
2065 const std::string
& event_name
,
2067 RequestStage request_stage
) {
2068 // It's possible that this request was deleted, or cancelled by a previous
2069 // event handler. If so, ignore this response.
2070 if (blocked_requests_
.find(request_id
) == blocked_requests_
.end())
2073 BlockedRequest
& blocked_request
= blocked_requests_
[request_id
];
2074 base::TimeDelta block_time
=
2075 base::Time::Now() - blocked_request
.blocking_time
;
2076 UMA_HISTOGRAM_TIMES("Extensions.NetworkDelayRegistryLoad", block_time
);
2078 ProcessDeclarativeRules(browser_context
,
2079 blocked_request
.extension_info_map
,
2081 blocked_request
.request
,
2083 blocked_request
.original_response_headers
.get());
2084 // Reset to NULL so that nobody relies on this being set.
2085 blocked_request
.extension_info_map
= NULL
;
2086 DecrementBlockCount(
2087 browser_context
, std::string(), event_name
, request_id
, NULL
);
2090 bool ExtensionWebRequestEventRouter::GetAndSetSignaled(uint64 request_id
,
2091 EventTypes event_type
) {
2092 SignaledRequestMap::iterator iter
= signaled_requests_
.find(request_id
);
2093 if (iter
== signaled_requests_
.end()) {
2094 signaled_requests_
[request_id
] = event_type
;
2097 bool was_signaled_before
= (iter
->second
& event_type
) != 0;
2098 iter
->second
|= event_type
;
2099 return was_signaled_before
;
2102 void ExtensionWebRequestEventRouter::ClearSignaled(uint64 request_id
,
2103 EventTypes event_type
) {
2104 SignaledRequestMap::iterator iter
= signaled_requests_
.find(request_id
);
2105 if (iter
== signaled_requests_
.end())
2107 iter
->second
&= ~event_type
;
2110 // Special QuotaLimitHeuristic for WebRequestHandlerBehaviorChangedFunction.
2112 // Each call of webRequest.handlerBehaviorChanged() clears the in-memory cache
2113 // of WebKit at the time of the next page load (top level navigation event).
2114 // This quota heuristic is intended to limit the number of times the cache is
2115 // cleared by an extension.
2117 // As we want to account for the number of times the cache is really cleared
2118 // (opposed to the number of times webRequest.handlerBehaviorChanged() is
2119 // called), we cannot decide whether a call of
2120 // webRequest.handlerBehaviorChanged() should trigger a quota violation at the
2121 // time it is called. Instead we only decrement the bucket counter at the time
2122 // when the cache is cleared (when page loads happen).
2123 class ClearCacheQuotaHeuristic
: public QuotaLimitHeuristic
{
2125 ClearCacheQuotaHeuristic(const Config
& config
, BucketMapper
* map
)
2126 : QuotaLimitHeuristic(
2129 "MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES"),
2130 callback_registered_(false),
2131 weak_ptr_factory_(this) {}
2132 ~ClearCacheQuotaHeuristic() override
{}
2133 bool Apply(Bucket
* bucket
, const base::TimeTicks
& event_time
) override
;
2136 // Callback that is triggered by the ExtensionWebRequestEventRouter on a page
2139 // We don't need to take care of the life time of |bucket|: It is owned by the
2140 // BucketMapper of our base class in |QuotaLimitHeuristic::bucket_mapper_|. As
2141 // long as |this| exists, the respective BucketMapper and its bucket will
2143 void OnPageLoad(Bucket
* bucket
);
2145 // Flag to prevent that we register more than one call back in-between
2146 // clearing the cache.
2147 bool callback_registered_
;
2149 base::WeakPtrFactory
<ClearCacheQuotaHeuristic
> weak_ptr_factory_
;
2151 DISALLOW_COPY_AND_ASSIGN(ClearCacheQuotaHeuristic
);
2154 bool ClearCacheQuotaHeuristic::Apply(Bucket
* bucket
,
2155 const base::TimeTicks
& event_time
) {
2156 if (event_time
> bucket
->expiration())
2157 bucket
->Reset(config(), event_time
);
2159 // Call bucket->DeductToken() on a new page load, this is when
2160 // webRequest.handlerBehaviorChanged() clears the cache.
2161 if (!callback_registered_
) {
2162 ExtensionWebRequestEventRouter::GetInstance()->AddCallbackForPageLoad(
2163 base::Bind(&ClearCacheQuotaHeuristic::OnPageLoad
,
2164 weak_ptr_factory_
.GetWeakPtr(),
2166 callback_registered_
= true;
2169 // We only check whether tokens are left here. Deducting a token happens in
2171 return bucket
->has_tokens();
2174 void ClearCacheQuotaHeuristic::OnPageLoad(Bucket
* bucket
) {
2175 callback_registered_
= false;
2176 bucket
->DeductToken();
2179 bool WebRequestInternalAddEventListenerFunction::RunSync() {
2180 // Argument 0 is the callback, which we don't use here.
2181 ExtensionWebRequestEventRouter::RequestFilter filter
;
2182 base::DictionaryValue
* value
= NULL
;
2184 EXTENSION_FUNCTION_VALIDATE(args_
->GetDictionary(1, &value
));
2185 // Failure + an empty error string means a fatal error.
2186 EXTENSION_FUNCTION_VALIDATE(filter
.InitFromValue(*value
, &error_
) ||
2188 if (!error_
.empty())
2191 int extra_info_spec
= 0;
2192 if (HasOptionalArgument(2)) {
2193 base::ListValue
* value
= NULL
;
2194 EXTENSION_FUNCTION_VALIDATE(args_
->GetList(2, &value
));
2195 EXTENSION_FUNCTION_VALIDATE(
2196 ExtensionWebRequestEventRouter::ExtraInfoSpec::InitFromValue(
2197 *value
, &extra_info_spec
));
2200 std::string event_name
;
2201 EXTENSION_FUNCTION_VALIDATE(args_
->GetString(3, &event_name
));
2203 std::string sub_event_name
;
2204 EXTENSION_FUNCTION_VALIDATE(args_
->GetString(4, &sub_event_name
));
2206 int web_view_instance_id
= 0;
2207 EXTENSION_FUNCTION_VALIDATE(args_
->GetInteger(5, &web_view_instance_id
));
2209 base::WeakPtr
<IOThreadExtensionMessageFilter
> ipc_sender
= ipc_sender_weak();
2210 int embedder_process_id
= ipc_sender
? ipc_sender
->render_process_id() : 0;
2212 const Extension
* extension
=
2213 extension_info_map()->extensions().GetByID(extension_id_safe());
2214 std::string extension_name
=
2215 extension
? extension
->name() : extension_id_safe();
2217 if (!web_view_instance_id
) {
2218 // We check automatically whether the extension has the 'webRequest'
2219 // permission. For blocking calls we require the additional permission
2220 // 'webRequestBlocking'.
2221 if ((extra_info_spec
&
2222 (ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING
|
2223 ExtensionWebRequestEventRouter::ExtraInfoSpec::ASYNC_BLOCKING
)) &&
2224 !extension
->permissions_data()->HasAPIPermission(
2225 APIPermission::kWebRequestBlocking
)) {
2226 error_
= keys::kBlockingPermissionRequired
;
2230 // We allow to subscribe to patterns that are broader than the host
2231 // permissions. E.g., we could subscribe to http://www.example.com/*
2232 // while having host permissions for http://www.example.com/foo/* and
2233 // http://www.example.com/bar/*.
2234 // For this reason we do only a coarse check here to warn the extension
2235 // developer if he does something obviously wrong.
2236 if (extension
->permissions_data()
2237 ->GetEffectiveHostPermissions()
2239 error_
= keys::kHostPermissionsRequired
;
2245 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
2246 profile_id(), extension_id_safe(), extension_name
,
2247 event_name
, sub_event_name
, filter
, extra_info_spec
,
2248 embedder_process_id
, web_view_instance_id
, ipc_sender_weak());
2249 EXTENSION_FUNCTION_VALIDATE(success
);
2251 helpers::ClearCacheOnNavigation();
2253 if (!extension_id_safe().empty()) {
2254 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
2255 base::Bind(&helpers::NotifyWebRequestAPIUsed
,
2256 profile_id(), extension_id_safe()));
2262 void WebRequestInternalEventHandledFunction::RespondWithError(
2263 const std::string
& event_name
,
2264 const std::string
& sub_event_name
,
2266 scoped_ptr
<ExtensionWebRequestEventRouter::EventResponse
> response
,
2267 const std::string
& error
) {
2269 ExtensionWebRequestEventRouter::GetInstance()->OnEventHandled(
2271 extension_id_safe(),
2275 response
.release());
2278 bool WebRequestInternalEventHandledFunction::RunSync() {
2279 std::string event_name
;
2280 EXTENSION_FUNCTION_VALIDATE(args_
->GetString(0, &event_name
));
2282 std::string sub_event_name
;
2283 EXTENSION_FUNCTION_VALIDATE(args_
->GetString(1, &sub_event_name
));
2285 std::string request_id_str
;
2286 EXTENSION_FUNCTION_VALIDATE(args_
->GetString(2, &request_id_str
));
2288 EXTENSION_FUNCTION_VALIDATE(base::StringToUint64(request_id_str
,
2291 scoped_ptr
<ExtensionWebRequestEventRouter::EventResponse
> response
;
2292 if (HasOptionalArgument(3)) {
2293 base::DictionaryValue
* value
= NULL
;
2294 EXTENSION_FUNCTION_VALIDATE(args_
->GetDictionary(3, &value
));
2296 if (!value
->empty()) {
2297 base::Time install_time
=
2298 extension_info_map()->GetInstallTime(extension_id_safe());
2299 response
.reset(new ExtensionWebRequestEventRouter::EventResponse(
2300 extension_id_safe(), install_time
));
2303 if (value
->HasKey("cancel")) {
2304 // Don't allow cancel mixed with other keys.
2305 if (value
->size() != 1) {
2306 RespondWithError(event_name
,
2310 keys::kInvalidBlockingResponse
);
2314 bool cancel
= false;
2315 EXTENSION_FUNCTION_VALIDATE(value
->GetBoolean("cancel", &cancel
));
2316 response
->cancel
= cancel
;
2319 if (value
->HasKey("redirectUrl")) {
2320 std::string new_url_str
;
2321 EXTENSION_FUNCTION_VALIDATE(value
->GetString("redirectUrl",
2323 response
->new_url
= GURL(new_url_str
);
2324 if (!response
->new_url
.is_valid()) {
2325 RespondWithError(event_name
,
2329 ErrorUtils::FormatErrorMessage(
2330 keys::kInvalidRedirectUrl
, new_url_str
));
2335 const bool hasRequestHeaders
= value
->HasKey("requestHeaders");
2336 const bool hasResponseHeaders
= value
->HasKey("responseHeaders");
2337 if (hasRequestHeaders
|| hasResponseHeaders
) {
2338 if (hasRequestHeaders
&& hasResponseHeaders
) {
2339 // Allow only one of the keys, not both.
2340 RespondWithError(event_name
,
2344 keys::kInvalidHeaderKeyCombination
);
2348 base::ListValue
* headers_value
= NULL
;
2349 scoped_ptr
<net::HttpRequestHeaders
> request_headers
;
2350 scoped_ptr
<helpers::ResponseHeaders
> response_headers
;
2351 if (hasRequestHeaders
) {
2352 request_headers
.reset(new net::HttpRequestHeaders());
2353 EXTENSION_FUNCTION_VALIDATE(value
->GetList(keys::kRequestHeadersKey
,
2356 response_headers
.reset(new helpers::ResponseHeaders());
2357 EXTENSION_FUNCTION_VALIDATE(value
->GetList(keys::kResponseHeadersKey
,
2361 for (size_t i
= 0; i
< headers_value
->GetSize(); ++i
) {
2362 base::DictionaryValue
* header_value
= NULL
;
2365 EXTENSION_FUNCTION_VALIDATE(
2366 headers_value
->GetDictionary(i
, &header_value
));
2367 if (!FromHeaderDictionary(header_value
, &name
, &value
)) {
2368 std::string serialized_header
;
2369 base::JSONWriter::Write(*header_value
, &serialized_header
);
2370 RespondWithError(event_name
,
2374 ErrorUtils::FormatErrorMessage(keys::kInvalidHeader
,
2375 serialized_header
));
2378 if (!net::HttpUtil::IsValidHeaderName(name
)) {
2379 RespondWithError(event_name
,
2383 keys::kInvalidHeaderName
);
2386 if (!net::HttpUtil::IsValidHeaderValue(value
)) {
2387 RespondWithError(event_name
,
2391 ErrorUtils::FormatErrorMessage(
2392 keys::kInvalidHeaderValue
, name
));
2395 if (hasRequestHeaders
)
2396 request_headers
->SetHeader(name
, value
);
2398 response_headers
->push_back(helpers::ResponseHeader(name
, value
));
2400 if (hasRequestHeaders
)
2401 response
->request_headers
.reset(request_headers
.release());
2403 response
->response_headers
.reset(response_headers
.release());
2406 if (value
->HasKey(keys::kAuthCredentialsKey
)) {
2407 base::DictionaryValue
* credentials_value
= NULL
;
2408 EXTENSION_FUNCTION_VALIDATE(value
->GetDictionary(
2409 keys::kAuthCredentialsKey
,
2410 &credentials_value
));
2411 base::string16 username
;
2412 base::string16 password
;
2413 EXTENSION_FUNCTION_VALIDATE(
2414 credentials_value
->GetString(keys::kUsernameKey
, &username
));
2415 EXTENSION_FUNCTION_VALIDATE(
2416 credentials_value
->GetString(keys::kPasswordKey
, &password
));
2417 response
->auth_credentials
.reset(
2418 new net::AuthCredentials(username
, password
));
2422 ExtensionWebRequestEventRouter::GetInstance()->OnEventHandled(
2423 profile_id(), extension_id_safe(), event_name
, sub_event_name
, request_id
,
2424 response
.release());
2429 void WebRequestHandlerBehaviorChangedFunction::GetQuotaLimitHeuristics(
2430 QuotaLimitHeuristics
* heuristics
) const {
2431 QuotaLimitHeuristic::Config config
= {
2432 // See web_request.json for current value.
2433 web_request::MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES
,
2434 base::TimeDelta::FromMinutes(10)};
2435 QuotaLimitHeuristic::BucketMapper
* bucket_mapper
=
2436 new QuotaLimitHeuristic::SingletonBucketMapper();
2437 ClearCacheQuotaHeuristic
* heuristic
=
2438 new ClearCacheQuotaHeuristic(config
, bucket_mapper
);
2439 heuristics
->push_back(heuristic
);
2442 void WebRequestHandlerBehaviorChangedFunction::OnQuotaExceeded(
2443 const std::string
& violation_error
) {
2444 // Post warning message.
2445 WarningSet warnings
;
2447 Warning::CreateRepeatedCacheFlushesWarning(extension_id_safe()));
2448 BrowserThread::PostTask(
2451 base::Bind(&WarningService::NotifyWarningsOnUI
, profile_id(), warnings
));
2453 // Continue gracefully.
2457 bool WebRequestHandlerBehaviorChangedFunction::RunSync() {
2458 helpers::ClearCacheOnNavigation();
2462 } // namespace extensions