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/macros.h"
14 #include "base/metrics/histogram.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "base/strings/string_util.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "base/time/time.h"
19 #include "base/values.h"
20 #include "content/public/browser/browser_message_filter.h"
21 #include "content/public/browser/browser_thread.h"
22 #include "content/public/browser/render_frame_host.h"
23 #include "content/public/browser/render_process_host.h"
24 #include "content/public/browser/resource_request_info.h"
25 #include "content/public/browser/user_metrics.h"
26 #include "extensions/browser/api/activity_log/web_request_constants.h"
27 #include "extensions/browser/api/declarative/rules_registry_service.h"
28 #include "extensions/browser/api/declarative_webrequest/request_stage.h"
29 #include "extensions/browser/api/declarative_webrequest/webrequest_constants.h"
30 #include "extensions/browser/api/declarative_webrequest/webrequest_rules_registry.h"
31 #include "extensions/browser/api/extensions_api_client.h"
32 #include "extensions/browser/api/web_request/upload_data_presenter.h"
33 #include "extensions/browser/api/web_request/web_request_api_constants.h"
34 #include "extensions/browser/api/web_request/web_request_api_helpers.h"
35 #include "extensions/browser/api/web_request/web_request_event_router_delegate.h"
36 #include "extensions/browser/api/web_request/web_request_time_tracker.h"
37 #include "extensions/browser/event_router.h"
38 #include "extensions/browser/extension_prefs.h"
39 #include "extensions/browser/extension_registry.h"
40 #include "extensions/browser/extension_system.h"
41 #include "extensions/browser/extensions_browser_client.h"
42 #include "extensions/browser/guest_view/guest_view_events.h"
43 #include "extensions/browser/guest_view/web_view/web_view_constants.h"
44 #include "extensions/browser/guest_view/web_view/web_view_renderer_state.h"
45 #include "extensions/browser/info_map.h"
46 #include "extensions/browser/io_thread_extension_message_filter.h"
47 #include "extensions/browser/runtime_data.h"
48 #include "extensions/browser/warning_service.h"
49 #include "extensions/browser/warning_set.h"
50 #include "extensions/common/api/web_request.h"
51 #include "extensions/common/error_utils.h"
52 #include "extensions/common/event_filtering_info.h"
53 #include "extensions/common/extension.h"
54 #include "extensions/common/features/feature.h"
55 #include "extensions/common/permissions/permissions_data.h"
56 #include "extensions/common/url_pattern.h"
57 #include "extensions/strings/grit/extensions_strings.h"
58 #include "net/base/auth.h"
59 #include "net/base/net_errors.h"
60 #include "net/base/upload_data_stream.h"
61 #include "net/http/http_response_headers.h"
62 #include "net/http/http_util.h"
63 #include "net/url_request/url_request.h"
64 #include "ui/base/l10n/l10n_util.h"
67 using base::DictionaryValue
;
68 using base::ListValue
;
69 using base::StringValue
;
70 using content::BrowserMessageFilter
;
71 using content::BrowserThread
;
72 using content::ResourceRequestInfo
;
73 using content::ResourceType
;
75 namespace activity_log
= activity_log_web_request_constants
;
76 namespace helpers
= extension_web_request_api_helpers
;
77 namespace keys
= extension_web_request_api_constants
;
79 namespace extensions
{
81 namespace declarative_keys
= declarative_webrequest_constants
;
82 namespace web_request
= api::web_request
;
86 const char kWebRequestEventPrefix
[] = "webRequest.";
88 // List of all the webRequest events.
89 const char* const kWebRequestEvents
[] = {
90 keys::kOnBeforeRedirectEvent
,
91 web_request::OnBeforeRequest::kEventName
,
92 keys::kOnBeforeSendHeadersEvent
,
93 keys::kOnCompletedEvent
,
94 web_request::OnErrorOccurred::kEventName
,
95 keys::kOnSendHeadersEvent
,
96 keys::kOnAuthRequiredEvent
,
97 keys::kOnResponseStartedEvent
,
98 keys::kOnHeadersReceivedEvent
,
101 const char* GetRequestStageAsString(
102 ExtensionWebRequestEventRouter::EventTypes type
) {
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
);
141 const auto web_request_events_end
=
142 kWebRequestEvents
+ arraysize(kWebRequestEvents
);
143 return std::find(kWebRequestEvents
, web_request_events_end
,
144 web_request_event_name
) != web_request_events_end
;
147 // Returns whether |request| has been triggered by an extension in
148 // |extension_info_map|.
149 bool IsRequestFromExtension(const net::URLRequest
* request
,
150 const InfoMap
* extension_info_map
) {
151 // |extension_info_map| is NULL for system-level requests.
152 if (!extension_info_map
)
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(const 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(const 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(const 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, ...);" .
223 base::DictionaryValue
* request_body
= new base::DictionaryValue();
224 out
->Set(keys::kRequestBodyKey
, request_body
);
226 // Get the data presenters, ordered by how specific they are.
227 ParsedDataPresenter
parsed_data_presenter(*request
);
228 RawDataPresenter raw_data_presenter
;
229 UploadDataPresenter
* const presenters
[] = {
230 &parsed_data_presenter
, // 1: any parseable forms? (Specific to forms.)
231 &raw_data_presenter
// 2: any data at all? (Non-specific.)
233 // Keys for the results of the corresponding presenters.
234 static const char* const kKeys
[] = {
235 keys::kRequestBodyFormDataKey
,
236 keys::kRequestBodyRawKey
239 const ScopedVector
<net::UploadElementReader
>* readers
=
240 upload_data
->GetElementReaders();
241 bool some_succeeded
= false;
243 for (size_t i
= 0; i
< arraysize(presenters
); ++i
) {
244 for (const auto& reader
: *readers
)
245 presenters
[i
]->FeedNext(*reader
);
246 if (presenters
[i
]->Succeeded()) {
247 request_body
->Set(kKeys
[i
], presenters
[i
]->Result().release());
248 some_succeeded
= true;
254 request_body
->SetString(keys::kRequestBodyErrorKey
, "Unknown error.");
257 // Converts a HttpHeaders dictionary to a |name|, |value| pair. Returns
258 // true if successful.
259 bool FromHeaderDictionary(const base::DictionaryValue
* header_value
,
261 std::string
* value
) {
262 if (!header_value
->GetString(keys::kHeaderNameKey
, name
))
265 // We require either a "value" or a "binaryValue" entry.
266 if (!(header_value
->HasKey(keys::kHeaderValueKey
) ^
267 header_value
->HasKey(keys::kHeaderBinaryValueKey
))) {
271 if (header_value
->HasKey(keys::kHeaderValueKey
)) {
272 if (!header_value
->GetString(keys::kHeaderValueKey
, value
)) {
275 } else if (header_value
->HasKey(keys::kHeaderBinaryValueKey
)) {
276 const base::ListValue
* list
= NULL
;
277 if (!header_value
->HasKey(keys::kHeaderBinaryValueKey
)) {
279 } else if (!header_value
->GetList(keys::kHeaderBinaryValueKey
, &list
) ||
280 !helpers::CharListToString(list
, value
)) {
287 // Creates a list of HttpHeaders (see the extension API JSON). If |headers| is
288 // NULL, the list is empty. Ownership is passed to the caller.
289 base::ListValue
* GetResponseHeadersList(
290 const net::HttpResponseHeaders
* headers
) {
291 base::ListValue
* headers_value
= new base::ListValue();
296 while (headers
->EnumerateHeaderLines(&iter
, &name
, &value
))
297 headers_value
->Append(helpers::CreateHeaderDictionary(name
, value
));
299 return headers_value
;
302 base::ListValue
* GetRequestHeadersList(const net::HttpRequestHeaders
& headers
) {
303 base::ListValue
* headers_value
= new base::ListValue();
304 for (net::HttpRequestHeaders::Iterator
it(headers
); it
.GetNext(); )
305 headers_value
->Append(
306 helpers::CreateHeaderDictionary(it
.name(), it
.value()));
307 return headers_value
;
310 // Creates a base::StringValue with the status line of |headers|. If |headers|
311 // is NULL, an empty string is returned. Ownership is passed to the caller.
312 base::StringValue
* GetStatusLine(net::HttpResponseHeaders
* headers
) {
313 return new base::StringValue(
314 headers
? headers
->GetStatusLine() : std::string());
317 // Returns the response code from the response headers, or 200 by default.
318 // |headers| may be NULL, e.g. UrlRequestFileJobs do not send headers, so
319 // simulate their behavior.
320 int GetResponseCodeWithDefault(net::HttpResponseHeaders
* headers
) {
321 return headers
? headers
->response_code() : 200;
324 // Sends an event to subscribers of chrome.declarativeWebRequest.onMessage or
325 // to subscribers of webview.onMessage if the action is being operated upon
326 // a <webview> guest renderer.
327 // |extension_id| identifies the extension that sends and receives the event.
328 // |is_web_view_guest| indicates whether the action is for a <webview>.
329 // |web_view_info| is a struct containing information about the <webview>
331 // |event_argument| is passed to the event listener.
332 void SendOnMessageEventOnUI(
333 void* browser_context_id
,
334 const std::string
& extension_id
,
335 bool is_web_view_guest
,
336 const WebViewRendererState::WebViewInfo
& web_view_info
,
337 scoped_ptr
<base::DictionaryValue
> event_argument
) {
338 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
340 content::BrowserContext
* browser_context
=
341 reinterpret_cast<content::BrowserContext
*>(browser_context_id
);
342 if (!ExtensionsBrowserClient::Get()->IsValidContext(browser_context
))
345 scoped_ptr
<base::ListValue
> event_args(new base::ListValue
);
346 event_args
->Append(event_argument
.release());
348 EventRouter
* event_router
= EventRouter::Get(browser_context
);
350 EventFilteringInfo event_filtering_info
;
352 events::HistogramValue histogram_value
= events::UNKNOWN
;
353 std::string event_name
;
354 // The instance ID uniquely identifies a <webview> instance within an embedder
355 // process. We use a filter here so that only event listeners for a particular
356 // <webview> will fire.
357 if (is_web_view_guest
) {
358 event_filtering_info
.SetInstanceID(web_view_info
.instance_id
);
359 histogram_value
= events::WEB_VIEW_INTERNAL_ON_MESSAGE
;
360 event_name
= webview::kEventMessage
;
362 histogram_value
= events::DECLARATIVE_WEB_REQUEST_ON_MESSAGE
;
363 event_name
= declarative_keys::kOnMessage
;
366 scoped_ptr
<Event
> event(new Event(
367 histogram_value
, event_name
, event_args
.Pass(), browser_context
, GURL(),
368 EventRouter::USER_GESTURE_UNKNOWN
, event_filtering_info
));
369 event_router
->DispatchEventToExtension(extension_id
, event
.Pass());
372 void RemoveEventListenerOnIOThread(
373 void* browser_context
,
374 const std::string
& extension_id
,
375 const std::string
& sub_event_name
,
376 int embedder_process_id
,
377 int web_view_instance_id
) {
378 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
379 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(
380 browser_context
, extension_id
, sub_event_name
,
381 embedder_process_id
, web_view_instance_id
);
384 events::HistogramValue
GetEventHistogramValue(const std::string
& event_name
) {
385 // Event names will either be webRequest events, or guest view (probably web
386 // view) events that map to webRequest events. Check webRequest first.
387 static struct ValueAndName
{
388 events::HistogramValue histogram_value
;
389 const char* const event_name
;
390 } values_and_names
[] = {
391 {events::WEB_REQUEST_ON_BEFORE_REDIRECT
, keys::kOnBeforeRedirectEvent
},
392 {events::WEB_REQUEST_ON_BEFORE_REQUEST
,
393 web_request::OnBeforeRequest::kEventName
},
394 {events::WEB_REQUEST_ON_BEFORE_SEND_HEADERS
,
395 keys::kOnBeforeSendHeadersEvent
},
396 {events::WEB_REQUEST_ON_COMPLETED
, keys::kOnCompletedEvent
},
397 {events::WEB_REQUEST_ON_ERROR_OCCURRED
,
398 web_request::OnErrorOccurred::kEventName
},
399 {events::WEB_REQUEST_ON_SEND_HEADERS
, keys::kOnSendHeadersEvent
},
400 {events::WEB_REQUEST_ON_AUTH_REQUIRED
, keys::kOnAuthRequiredEvent
},
401 {events::WEB_REQUEST_ON_RESPONSE_STARTED
, keys::kOnResponseStartedEvent
},
402 {events::WEB_REQUEST_ON_HEADERS_RECEIVED
, keys::kOnHeadersReceivedEvent
}};
403 COMPILE_ASSERT(arraysize(kWebRequestEvents
) == arraysize(values_and_names
),
404 "kWebRequestEvents and values_and_names must be the same");
405 for (const ValueAndName
& value_and_name
: values_and_names
) {
406 if (value_and_name
.event_name
== event_name
)
407 return value_and_name
.histogram_value
;
410 // If there is no webRequest event, it might be a guest view webRequest event.
411 events::HistogramValue guest_view_histogram_value
=
412 guest_view_events::GetEventHistogramValue(event_name
);
413 if (guest_view_histogram_value
!= events::UNKNOWN
)
414 return guest_view_histogram_value
;
416 // There is no histogram value for this event name. It should be added to
417 // either the mapping here, or in guest_view_events.
418 NOTREACHED() << "Event " << event_name
<< " must have a histogram value";
419 return events::UNKNOWN
;
422 // We hide events from the system context as well as sensitive requests.
423 bool ShouldHideEvent(void* browser_context
,
424 const InfoMap
* extension_info_map
,
425 const net::URLRequest
* request
) {
426 return (!browser_context
||
427 WebRequestPermissions::HideRequest(extension_info_map
, request
));
432 WebRequestAPI::WebRequestAPI(content::BrowserContext
* context
)
433 : browser_context_(context
) {
434 EventRouter
* event_router
= EventRouter::Get(browser_context_
);
435 for (size_t i
= 0; i
< arraysize(kWebRequestEvents
); ++i
) {
436 // Observe the webRequest event.
437 std::string event_name
= kWebRequestEvents
[i
];
438 event_router
->RegisterObserver(this, event_name
);
440 // Also observe the corresponding webview event.
442 0, sizeof(kWebRequestEventPrefix
) - 1, webview::kWebViewEventPrefix
);
443 event_router
->RegisterObserver(this, event_name
);
447 WebRequestAPI::~WebRequestAPI() {
448 EventRouter::Get(browser_context_
)->UnregisterObserver(this);
451 static base::LazyInstance
<BrowserContextKeyedAPIFactory
<WebRequestAPI
> >
452 g_factory
= LAZY_INSTANCE_INITIALIZER
;
455 BrowserContextKeyedAPIFactory
<WebRequestAPI
>*
456 WebRequestAPI::GetFactoryInstance() {
457 return g_factory
.Pointer();
460 void WebRequestAPI::OnListenerRemoved(const EventListenerInfo
& details
) {
461 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
462 // Note that details.event_name includes the sub-event details (e.g. "/123").
463 // TODO(fsamuel): <webview> events will not be removed through this code path.
464 // <webview> events will be removed in RemoveWebViewEventListeners. Ideally,
465 // this code should be decoupled from extensions, we should use the host ID
466 // instead, and not have two different code paths. This is a huge undertaking
467 // unfortunately, so we'll resort to two code paths for now.
468 BrowserThread::PostTask(BrowserThread::IO
,
470 base::Bind(&RemoveEventListenerOnIOThread
,
471 details
.browser_context
,
472 details
.extension_id
,
474 0 /* embedder_process_id (ignored) */,
475 0 /* web_view_instance_id */));
478 // Represents a single unique listener to an event, along with whatever filter
479 // parameters and extra_info_spec were specified at the time the listener was
481 // NOTE(benjhayden) New APIs should not use this sub_event_name trick! It does
482 // not play well with event pages. See downloads.onDeterminingFilename and
483 // ExtensionDownloadsEventRouter for an alternative approach.
484 struct ExtensionWebRequestEventRouter::EventListener
{
485 std::string extension_id
;
486 std::string extension_name
;
487 events::HistogramValue histogram_value
;
488 std::string sub_event_name
;
489 RequestFilter filter
;
491 int embedder_process_id
;
492 int web_view_instance_id
;
493 base::WeakPtr
<IPC::Sender
> ipc_sender
;
494 mutable std::set
<uint64_t> blocked_requests
;
496 // Comparator to work with std::set.
497 bool operator<(const EventListener
& that
) const {
498 if (extension_id
!= that
.extension_id
)
499 return extension_id
< that
.extension_id
;
501 if (sub_event_name
!= that
.sub_event_name
)
502 return sub_event_name
< that
.sub_event_name
;
504 if (web_view_instance_id
!= that
.web_view_instance_id
)
505 return web_view_instance_id
< that
.web_view_instance_id
;
507 if (web_view_instance_id
== 0) {
508 // Do not filter by process ID for non-webviews, because this comparator
509 // is also used to find and remove an event listener when an extension is
510 // unloaded. At this point, the event listener cannot be mapped back to
511 // the original process, so 0 is used instead of the actual process ID.
512 DCHECK(embedder_process_id
== 0 || that
.embedder_process_id
== 0);
516 if (embedder_process_id
!= that
.embedder_process_id
)
517 return embedder_process_id
< that
.embedder_process_id
;
523 : histogram_value(events::UNKNOWN
),
525 embedder_process_id(0),
526 web_view_instance_id(0) {}
529 // Contains info about requests that are blocked waiting for a response from
531 struct ExtensionWebRequestEventRouter::BlockedRequest
{
532 // The request that is being blocked.
533 net::URLRequest
* request
;
535 // Whether the request originates from an incognito tab.
538 // The event that we're currently blocked on.
541 // The number of event handlers that we are awaiting a response from.
542 int num_handlers_blocking
;
544 // Pointer to NetLog to report significant changes to the request for
546 const net::BoundNetLog
* net_log
;
548 // The callback to call when we get a response from all event handlers.
549 net::CompletionCallback callback
;
551 // If non-empty, this contains the new URL that the request will redirect to.
552 // Only valid for OnBeforeRequest and OnHeadersReceived.
555 // The request headers that will be issued along with this request. Only valid
556 // for OnBeforeSendHeaders.
557 net::HttpRequestHeaders
* request_headers
;
559 // The response headers that were received from the server. Only valid for
560 // OnHeadersReceived.
561 scoped_refptr
<const net::HttpResponseHeaders
> original_response_headers
;
563 // Location where to override response headers. Only valid for
564 // OnHeadersReceived.
565 scoped_refptr
<net::HttpResponseHeaders
>* override_response_headers
;
567 // If non-empty, this contains the auth credentials that may be filled in.
568 // Only valid for OnAuthRequired.
569 net::AuthCredentials
* auth_credentials
;
571 // The callback to invoke for auth. If |auth_callback.is_null()| is false,
572 // |callback| must be NULL.
573 // Only valid for OnAuthRequired.
574 net::NetworkDelegate::AuthCallback auth_callback
;
576 // Time the request was paused. Used for logging purposes.
577 base::Time blocking_time
;
579 // Changes requested by extensions.
580 helpers::EventResponseDeltas response_deltas
;
582 // Provider of meta data about extensions, only used and non-NULL for events
583 // that are delayed until the rules registry is ready.
584 const InfoMap
* extension_info_map
;
589 event(kInvalidEvent
),
590 num_handlers_blocking(0),
593 request_headers(NULL
),
594 override_response_headers(NULL
),
595 auth_credentials(NULL
),
596 extension_info_map(NULL
) {}
599 bool ExtensionWebRequestEventRouter::RequestFilter::InitFromValue(
600 const base::DictionaryValue
& value
, std::string
* error
) {
601 if (!value
.HasKey("urls"))
604 for (base::DictionaryValue::Iterator
it(value
); !it
.IsAtEnd(); it
.Advance()) {
605 if (it
.key() == "urls") {
606 const base::ListValue
* urls_value
= NULL
;
607 if (!it
.value().GetAsList(&urls_value
))
609 for (size_t i
= 0; i
< urls_value
->GetSize(); ++i
) {
612 URLPattern::SCHEME_HTTP
| URLPattern::SCHEME_HTTPS
|
613 URLPattern::SCHEME_FTP
| URLPattern::SCHEME_FILE
|
614 URLPattern::SCHEME_EXTENSION
);
615 if (!urls_value
->GetString(i
, &url
) ||
616 pattern
.Parse(url
) != URLPattern::PARSE_SUCCESS
) {
617 *error
= ErrorUtils::FormatErrorMessage(
618 keys::kInvalidRequestFilterUrl
, url
);
621 urls
.AddPattern(pattern
);
623 } else if (it
.key() == "types") {
624 const base::ListValue
* types_value
= NULL
;
625 if (!it
.value().GetAsList(&types_value
))
627 for (size_t i
= 0; i
< types_value
->GetSize(); ++i
) {
628 std::string type_str
;
630 if (!types_value
->GetString(i
, &type_str
) ||
631 !helpers::ParseResourceType(type_str
, &type
)) {
634 types
.push_back(type
);
636 } else if (it
.key() == "tabId") {
637 if (!it
.value().GetAsInteger(&tab_id
))
639 } else if (it
.key() == "windowId") {
640 if (!it
.value().GetAsInteger(&window_id
))
650 bool ExtensionWebRequestEventRouter::ExtraInfoSpec::InitFromValue(
651 const base::ListValue
& value
, int* extra_info_spec
) {
652 *extra_info_spec
= 0;
653 for (size_t i
= 0; i
< value
.GetSize(); ++i
) {
655 if (!value
.GetString(i
, &str
))
658 if (str
== "requestHeaders")
659 *extra_info_spec
|= REQUEST_HEADERS
;
660 else if (str
== "responseHeaders")
661 *extra_info_spec
|= RESPONSE_HEADERS
;
662 else if (str
== "blocking")
663 *extra_info_spec
|= BLOCKING
;
664 else if (str
== "asyncBlocking")
665 *extra_info_spec
|= ASYNC_BLOCKING
;
666 else if (str
== "requestBody")
667 *extra_info_spec
|= REQUEST_BODY
;
671 // BLOCKING and ASYNC_BLOCKING are mutually exclusive.
672 if ((*extra_info_spec
& BLOCKING
) && (*extra_info_spec
& ASYNC_BLOCKING
))
679 ExtensionWebRequestEventRouter::EventResponse::EventResponse(
680 const std::string
& extension_id
, const base::Time
& extension_install_time
)
681 : extension_id(extension_id
),
682 extension_install_time(extension_install_time
),
686 ExtensionWebRequestEventRouter::EventResponse::~EventResponse() {
689 ExtensionWebRequestEventRouter::RequestFilter::RequestFilter()
690 : tab_id(-1), window_id(-1) {
693 ExtensionWebRequestEventRouter::RequestFilter::~RequestFilter() {
697 // ExtensionWebRequestEventRouter
701 ExtensionWebRequestEventRouter
* ExtensionWebRequestEventRouter::GetInstance() {
702 return Singleton
<ExtensionWebRequestEventRouter
>::get();
705 ExtensionWebRequestEventRouter::ExtensionWebRequestEventRouter()
706 : request_time_tracker_(new ExtensionWebRequestTimeTracker
) {
707 web_request_event_router_delegate_
.reset(
708 ExtensionsAPIClient::Get()->CreateWebRequestEventRouterDelegate());
711 ExtensionWebRequestEventRouter::~ExtensionWebRequestEventRouter() {
714 void ExtensionWebRequestEventRouter::RegisterRulesRegistry(
715 void* browser_context
,
716 int rules_registry_id
,
717 scoped_refptr
<WebRequestRulesRegistry
> rules_registry
) {
718 RulesRegistryKey
key(browser_context
, rules_registry_id
);
719 if (rules_registry
.get())
720 rules_registries_
[key
] = rules_registry
;
722 rules_registries_
.erase(key
);
725 void ExtensionWebRequestEventRouter::ExtractRequestInfo(
726 const net::URLRequest
* request
,
727 base::DictionaryValue
* out
) {
728 bool is_main_frame
= false;
730 bool parent_is_main_frame
= false;
731 int parent_frame_id
= -1;
732 int frame_id_for_extension
= -1;
733 int parent_frame_id_for_extension
= -1;
734 int render_process_host_id
= -1;
736 ResourceType resource_type
= content::RESOURCE_TYPE_LAST_TYPE
;
737 ExtractRequestInfoDetails(request
, &is_main_frame
, &frame_id
,
738 &parent_is_main_frame
, &parent_frame_id
,
739 &render_process_host_id
, &routing_id
,
741 frame_id_for_extension
= GetFrameId(is_main_frame
, frame_id
);
742 parent_frame_id_for_extension
= GetFrameId(parent_is_main_frame
,
745 out
->SetString(keys::kRequestIdKey
,
746 base::Uint64ToString(request
->identifier()));
747 out
->SetString(keys::kUrlKey
, request
->url().spec());
748 out
->SetString(keys::kMethodKey
, request
->method());
749 out
->SetInteger(keys::kFrameIdKey
, frame_id_for_extension
);
750 out
->SetInteger(keys::kParentFrameIdKey
, parent_frame_id_for_extension
);
751 out
->SetString(keys::kTypeKey
, helpers::ResourceTypeToString(resource_type
));
752 out
->SetDouble(keys::kTimeStampKey
, base::Time::Now().ToDoubleT() * 1000);
753 if (web_request_event_router_delegate_
) {
754 web_request_event_router_delegate_
->ExtractExtraRequestDetails(
759 int ExtensionWebRequestEventRouter::OnBeforeRequest(
760 void* browser_context
,
761 const InfoMap
* extension_info_map
,
762 net::URLRequest
* request
,
763 const net::CompletionCallback
& callback
,
765 if (ShouldHideEvent(browser_context
, extension_info_map
, request
))
768 if (IsPageLoad(request
))
771 request_time_tracker_
->LogRequestStartTime(request
->identifier(),
776 // Whether to initialized |blocked_requests_|.
777 bool initialize_blocked_requests
= false;
779 initialize_blocked_requests
|=
780 ProcessDeclarativeRules(browser_context
, extension_info_map
,
781 web_request::OnBeforeRequest::kEventName
, request
,
782 ON_BEFORE_REQUEST
, NULL
);
784 int extra_info_spec
= 0;
785 EventListeners listeners
= GetMatchingListeners(
786 browser_context
, extension_info_map
,
787 web_request::OnBeforeRequest::kEventName
, request
, &extra_info_spec
);
788 if (!listeners
.empty() &&
789 !GetAndSetSignaled(request
->identifier(), kOnBeforeRequest
)) {
790 base::ListValue args
;
791 base::DictionaryValue
* dict
= new base::DictionaryValue();
792 ExtractRequestInfo(request
, dict
);
793 if (extra_info_spec
& ExtraInfoSpec::REQUEST_BODY
)
794 ExtractRequestInfoBody(request
, dict
);
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 BlockedRequest
& blocked_request
= blocked_requests_
[request
->identifier()];
805 blocked_request
.event
= kOnBeforeRequest
;
806 blocked_request
.is_incognito
|= IsIncognitoBrowserContext(browser_context
);
807 blocked_request
.request
= request
;
808 blocked_request
.callback
= callback
;
809 blocked_request
.new_url
= new_url
;
810 blocked_request
.net_log
= &request
->net_log();
812 if (blocked_request
.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
;
821 int ExtensionWebRequestEventRouter::OnBeforeSendHeaders(
822 void* browser_context
,
823 const InfoMap
* extension_info_map
,
824 net::URLRequest
* request
,
825 const net::CompletionCallback
& callback
,
826 net::HttpRequestHeaders
* headers
) {
827 if (ShouldHideEvent(browser_context
, extension_info_map
, request
))
830 bool initialize_blocked_requests
= false;
832 initialize_blocked_requests
|= ProcessDeclarativeRules(
833 browser_context
, extension_info_map
, keys::kOnBeforeSendHeadersEvent
,
834 request
, ON_BEFORE_SEND_HEADERS
, NULL
);
836 int extra_info_spec
= 0;
837 EventListeners listeners
= GetMatchingListeners(
838 browser_context
, extension_info_map
, keys::kOnBeforeSendHeadersEvent
,
839 request
, &extra_info_spec
);
840 if (!listeners
.empty() &&
841 !GetAndSetSignaled(request
->identifier(), kOnBeforeSendHeaders
)) {
842 base::ListValue args
;
843 base::DictionaryValue
* dict
= new base::DictionaryValue();
844 ExtractRequestInfo(request
, dict
);
845 if (extra_info_spec
& ExtraInfoSpec::REQUEST_HEADERS
)
846 dict
->Set(keys::kRequestHeadersKey
, GetRequestHeadersList(*headers
));
849 initialize_blocked_requests
|=
850 DispatchEvent(browser_context
, request
, listeners
, args
);
853 if (!initialize_blocked_requests
)
854 return net::OK
; // Nobody saw a reason for modifying the request.
856 BlockedRequest
& blocked_request
= blocked_requests_
[request
->identifier()];
857 blocked_request
.event
= kOnBeforeSendHeaders
;
858 blocked_request
.is_incognito
|= IsIncognitoBrowserContext(browser_context
);
859 blocked_request
.request
= request
;
860 blocked_request
.callback
= callback
;
861 blocked_request
.request_headers
= headers
;
862 blocked_request
.net_log
= &request
->net_log();
864 if (blocked_request
.num_handlers_blocking
== 0) {
865 // If there are no blocking handlers, only the declarative rules tried
866 // to modify the request and we can respond synchronously.
867 return ExecuteDeltas(browser_context
, request
->identifier(),
868 false /* call_callback*/);
870 return net::ERR_IO_PENDING
;
873 void ExtensionWebRequestEventRouter::OnSendHeaders(
874 void* browser_context
,
875 const InfoMap
* extension_info_map
,
876 net::URLRequest
* request
,
877 const net::HttpRequestHeaders
& headers
) {
878 if (ShouldHideEvent(browser_context
, extension_info_map
, request
))
881 if (GetAndSetSignaled(request
->identifier(), kOnSendHeaders
))
884 ClearSignaled(request
->identifier(), kOnBeforeRedirect
);
886 int extra_info_spec
= 0;
887 EventListeners listeners
= GetMatchingListeners(
888 browser_context
, extension_info_map
, keys::kOnSendHeadersEvent
, request
,
890 if (listeners
.empty())
893 base::ListValue args
;
894 base::DictionaryValue
* dict
= new base::DictionaryValue();
895 ExtractRequestInfo(request
, dict
);
896 if (extra_info_spec
& ExtraInfoSpec::REQUEST_HEADERS
)
897 dict
->Set(keys::kRequestHeadersKey
, GetRequestHeadersList(headers
));
900 DispatchEvent(browser_context
, request
, listeners
, args
);
903 int ExtensionWebRequestEventRouter::OnHeadersReceived(
904 void* browser_context
,
905 const InfoMap
* extension_info_map
,
906 net::URLRequest
* request
,
907 const net::CompletionCallback
& callback
,
908 const net::HttpResponseHeaders
* original_response_headers
,
909 scoped_refptr
<net::HttpResponseHeaders
>* override_response_headers
,
910 GURL
* allowed_unsafe_redirect_url
) {
911 if (ShouldHideEvent(browser_context
, extension_info_map
, request
))
914 bool initialize_blocked_requests
= false;
916 initialize_blocked_requests
|= ProcessDeclarativeRules(
917 browser_context
, extension_info_map
, keys::kOnHeadersReceivedEvent
,
918 request
, ON_HEADERS_RECEIVED
, original_response_headers
);
920 int extra_info_spec
= 0;
921 EventListeners listeners
= GetMatchingListeners(
922 browser_context
, extension_info_map
, keys::kOnHeadersReceivedEvent
,
923 request
, &extra_info_spec
);
925 if (!listeners
.empty() &&
926 !GetAndSetSignaled(request
->identifier(), kOnHeadersReceived
)) {
927 base::ListValue args
;
928 base::DictionaryValue
* dict
= new base::DictionaryValue();
929 ExtractRequestInfo(request
, dict
);
930 dict
->SetString(keys::kStatusLineKey
,
931 original_response_headers
->GetStatusLine());
932 dict
->SetInteger(keys::kStatusCodeKey
,
933 original_response_headers
->response_code());
934 if (extra_info_spec
& ExtraInfoSpec::RESPONSE_HEADERS
) {
935 dict
->Set(keys::kResponseHeadersKey
,
936 GetResponseHeadersList(original_response_headers
));
940 initialize_blocked_requests
|=
941 DispatchEvent(browser_context
, request
, listeners
, args
);
944 if (!initialize_blocked_requests
)
945 return net::OK
; // Nobody saw a reason for modifying the request.
947 BlockedRequest
& blocked_request
= blocked_requests_
[request
->identifier()];
948 blocked_request
.event
= kOnHeadersReceived
;
949 blocked_request
.is_incognito
|= IsIncognitoBrowserContext(browser_context
);
950 blocked_request
.request
= request
;
951 blocked_request
.callback
= callback
;
952 blocked_request
.net_log
= &request
->net_log();
953 blocked_request
.override_response_headers
= override_response_headers
;
954 blocked_request
.original_response_headers
= original_response_headers
;
955 blocked_request
.new_url
= allowed_unsafe_redirect_url
;
957 if (blocked_request
.num_handlers_blocking
== 0) {
958 // If there are no blocking handlers, only the declarative rules tried
959 // to modify the request and we can respond synchronously.
960 return ExecuteDeltas(browser_context
, request
->identifier(),
961 false /* call_callback*/);
963 return net::ERR_IO_PENDING
;
966 net::NetworkDelegate::AuthRequiredResponse
967 ExtensionWebRequestEventRouter::OnAuthRequired(
968 void* browser_context
,
969 const InfoMap
* extension_info_map
,
970 net::URLRequest
* request
,
971 const net::AuthChallengeInfo
& auth_info
,
972 const net::NetworkDelegate::AuthCallback
& callback
,
973 net::AuthCredentials
* credentials
) {
974 // No browser_context means that this is for authentication challenges in the
975 // system context. Skip in that case. Also skip sensitive requests.
976 if (!browser_context
||
977 WebRequestPermissions::HideRequest(extension_info_map
, request
)) {
978 return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION
;
981 int extra_info_spec
= 0;
982 EventListeners listeners
= GetMatchingListeners(
983 browser_context
, extension_info_map
, keys::kOnAuthRequiredEvent
, request
,
985 if (listeners
.empty())
986 return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION
;
988 base::ListValue args
;
989 base::DictionaryValue
* dict
= new base::DictionaryValue();
990 ExtractRequestInfo(request
, dict
);
991 dict
->SetBoolean(keys::kIsProxyKey
, auth_info
.is_proxy
);
992 if (!auth_info
.scheme
.empty())
993 dict
->SetString(keys::kSchemeKey
, auth_info
.scheme
);
994 if (!auth_info
.realm
.empty())
995 dict
->SetString(keys::kRealmKey
, auth_info
.realm
);
996 base::DictionaryValue
* challenger
= new base::DictionaryValue();
997 challenger
->SetString(keys::kHostKey
, auth_info
.challenger
.host());
998 challenger
->SetInteger(keys::kPortKey
, auth_info
.challenger
.port());
999 dict
->Set(keys::kChallengerKey
, challenger
);
1000 dict
->Set(keys::kStatusLineKey
, GetStatusLine(request
->response_headers()));
1001 if (request
->response_headers()) {
1002 dict
->SetInteger(keys::kStatusCodeKey
,
1003 request
->response_headers()->response_code());
1005 if (extra_info_spec
& ExtraInfoSpec::RESPONSE_HEADERS
) {
1006 dict
->Set(keys::kResponseHeadersKey
,
1007 GetResponseHeadersList(request
->response_headers()));
1011 if (DispatchEvent(browser_context
, request
, listeners
, args
)) {
1012 BlockedRequest
& blocked_request
= blocked_requests_
[request
->identifier()];
1013 blocked_request
.event
= kOnAuthRequired
;
1014 blocked_request
.is_incognito
|= IsIncognitoBrowserContext(browser_context
);
1015 blocked_request
.request
= request
;
1016 blocked_request
.auth_callback
= callback
;
1017 blocked_request
.auth_credentials
= credentials
;
1018 blocked_request
.net_log
= &request
->net_log();
1019 return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_IO_PENDING
;
1021 return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION
;
1024 void ExtensionWebRequestEventRouter::OnBeforeRedirect(
1025 void* browser_context
,
1026 const InfoMap
* extension_info_map
,
1027 net::URLRequest
* request
,
1028 const GURL
& new_location
) {
1029 if (ShouldHideEvent(browser_context
, extension_info_map
, request
))
1032 if (GetAndSetSignaled(request
->identifier(), kOnBeforeRedirect
))
1035 ClearSignaled(request
->identifier(), kOnBeforeRequest
);
1036 ClearSignaled(request
->identifier(), kOnBeforeSendHeaders
);
1037 ClearSignaled(request
->identifier(), kOnSendHeaders
);
1038 ClearSignaled(request
->identifier(), kOnHeadersReceived
);
1040 int extra_info_spec
= 0;
1041 EventListeners listeners
= GetMatchingListeners(
1042 browser_context
, extension_info_map
, keys::kOnBeforeRedirectEvent
,
1043 request
, &extra_info_spec
);
1044 if (listeners
.empty())
1047 int http_status_code
= request
->GetResponseCode();
1049 std::string response_ip
= request
->GetSocketAddress().host();
1051 base::ListValue args
;
1052 base::DictionaryValue
* dict
= new base::DictionaryValue();
1053 ExtractRequestInfo(request
, dict
);
1054 dict
->SetString(keys::kRedirectUrlKey
, new_location
.spec());
1055 dict
->SetInteger(keys::kStatusCodeKey
, http_status_code
);
1056 if (!response_ip
.empty())
1057 dict
->SetString(keys::kIpKey
, response_ip
);
1058 dict
->SetBoolean(keys::kFromCache
, request
->was_cached());
1059 dict
->Set(keys::kStatusLineKey
, GetStatusLine(request
->response_headers()));
1060 if (extra_info_spec
& ExtraInfoSpec::RESPONSE_HEADERS
) {
1061 dict
->Set(keys::kResponseHeadersKey
,
1062 GetResponseHeadersList(request
->response_headers()));
1066 DispatchEvent(browser_context
, request
, listeners
, args
);
1069 void ExtensionWebRequestEventRouter::OnResponseStarted(
1070 void* browser_context
,
1071 const InfoMap
* extension_info_map
,
1072 net::URLRequest
* request
) {
1073 if (ShouldHideEvent(browser_context
, extension_info_map
, request
))
1076 // OnResponseStarted is even triggered, when the request was cancelled.
1077 if (request
->status().status() != net::URLRequestStatus::SUCCESS
)
1080 int extra_info_spec
= 0;
1081 EventListeners listeners
= GetMatchingListeners(
1082 browser_context
, extension_info_map
, keys::kOnResponseStartedEvent
,
1083 request
, &extra_info_spec
);
1084 if (listeners
.empty())
1087 std::string response_ip
= request
->GetSocketAddress().host();
1089 base::ListValue args
;
1090 base::DictionaryValue
* dict
= new base::DictionaryValue();
1091 ExtractRequestInfo(request
, dict
);
1092 if (!response_ip
.empty())
1093 dict
->SetString(keys::kIpKey
, response_ip
);
1094 dict
->SetBoolean(keys::kFromCache
, request
->was_cached());
1095 dict
->SetInteger(keys::kStatusCodeKey
,
1096 GetResponseCodeWithDefault(request
->response_headers()));
1097 dict
->Set(keys::kStatusLineKey
, GetStatusLine(request
->response_headers()));
1098 if (extra_info_spec
& ExtraInfoSpec::RESPONSE_HEADERS
) {
1099 dict
->Set(keys::kResponseHeadersKey
,
1100 GetResponseHeadersList(request
->response_headers()));
1104 DispatchEvent(browser_context
, request
, listeners
, args
);
1107 void ExtensionWebRequestEventRouter::OnCompleted(
1108 void* browser_context
,
1109 const InfoMap
* extension_info_map
,
1110 net::URLRequest
* request
) {
1111 // We hide events from the system context as well as sensitive requests.
1112 // However, if the request first became sensitive after redirecting we have
1113 // already signaled it and thus we have to signal the end of it. This is
1114 // risk-free because the handler cannot modify the request now.
1115 if (!browser_context
||
1116 (WebRequestPermissions::HideRequest(extension_info_map
, request
) &&
1117 !WasSignaled(*request
))) {
1121 request_time_tracker_
->LogRequestEndTime(request
->identifier(),
1124 DCHECK(request
->status().status() == net::URLRequestStatus::SUCCESS
);
1126 DCHECK(!GetAndSetSignaled(request
->identifier(), kOnCompleted
));
1128 ClearPendingCallbacks(request
);
1130 int extra_info_spec
= 0;
1131 EventListeners listeners
=
1132 GetMatchingListeners(browser_context
, extension_info_map
,
1133 keys::kOnCompletedEvent
, request
, &extra_info_spec
);
1134 if (listeners
.empty())
1137 std::string response_ip
= request
->GetSocketAddress().host();
1139 base::ListValue args
;
1140 base::DictionaryValue
* dict
= new base::DictionaryValue();
1141 ExtractRequestInfo(request
, dict
);
1142 dict
->SetInteger(keys::kStatusCodeKey
,
1143 GetResponseCodeWithDefault(request
->response_headers()));
1144 if (!response_ip
.empty())
1145 dict
->SetString(keys::kIpKey
, response_ip
);
1146 dict
->SetBoolean(keys::kFromCache
, request
->was_cached());
1147 dict
->Set(keys::kStatusLineKey
, GetStatusLine(request
->response_headers()));
1148 if (extra_info_spec
& ExtraInfoSpec::RESPONSE_HEADERS
) {
1149 dict
->Set(keys::kResponseHeadersKey
,
1150 GetResponseHeadersList(request
->response_headers()));
1154 DispatchEvent(browser_context
, request
, listeners
, args
);
1157 void ExtensionWebRequestEventRouter::OnErrorOccurred(
1158 void* browser_context
,
1159 const InfoMap
* extension_info_map
,
1160 net::URLRequest
* request
,
1162 // We hide events from the system context as well as sensitive requests.
1163 // However, if the request first became sensitive after redirecting we have
1164 // already signaled it and thus we have to signal the end of it. This is
1165 // risk-free because the handler cannot modify the request now.
1166 if (!browser_context
||
1167 (WebRequestPermissions::HideRequest(extension_info_map
, request
) &&
1168 !WasSignaled(*request
))) {
1172 request_time_tracker_
->LogRequestEndTime(request
->identifier(),
1175 DCHECK(request
->status().status() == net::URLRequestStatus::FAILED
||
1176 request
->status().status() == net::URLRequestStatus::CANCELED
);
1178 DCHECK(!GetAndSetSignaled(request
->identifier(), kOnErrorOccurred
));
1180 ClearPendingCallbacks(request
);
1182 int extra_info_spec
= 0;
1183 EventListeners listeners
= GetMatchingListeners(
1184 browser_context
, extension_info_map
,
1185 web_request::OnErrorOccurred::kEventName
, request
, &extra_info_spec
);
1186 if (listeners
.empty())
1189 base::ListValue args
;
1190 base::DictionaryValue
* dict
= new base::DictionaryValue();
1191 ExtractRequestInfo(request
, dict
);
1193 std::string response_ip
= request
->GetSocketAddress().host();
1194 if (!response_ip
.empty())
1195 dict
->SetString(keys::kIpKey
, response_ip
);
1197 dict
->SetBoolean(keys::kFromCache
, request
->was_cached());
1198 dict
->SetString(keys::kErrorKey
,
1199 net::ErrorToString(request
->status().error()));
1202 DispatchEvent(browser_context
, request
, listeners
, args
);
1205 void ExtensionWebRequestEventRouter::OnURLRequestDestroyed(
1206 void* browser_context
,
1207 const net::URLRequest
* request
) {
1208 ClearPendingCallbacks(request
);
1210 signaled_requests_
.erase(request
->identifier());
1212 request_time_tracker_
->LogRequestEndTime(request
->identifier(),
1216 void ExtensionWebRequestEventRouter::ClearPendingCallbacks(
1217 const net::URLRequest
* request
) {
1218 blocked_requests_
.erase(request
->identifier());
1221 bool ExtensionWebRequestEventRouter::DispatchEvent(
1222 void* browser_context
,
1223 net::URLRequest
* request
,
1224 const std::vector
<const EventListener
*>& listeners
,
1225 const base::ListValue
& args
) {
1226 // TODO(mpcomplete): Consider consolidating common (extension_id,json_args)
1227 // pairs into a single message sent to a list of sub_event_names.
1228 int num_handlers_blocking
= 0;
1229 for (const EventListener
* listener
: listeners
) {
1230 // Filter out the optional keys that this listener didn't request.
1231 scoped_ptr
<base::ListValue
> args_filtered(args
.DeepCopy());
1232 base::DictionaryValue
* dict
= NULL
;
1233 CHECK(args_filtered
->GetDictionary(0, &dict
) && dict
);
1234 if (!(listener
->extra_info_spec
& ExtraInfoSpec::REQUEST_HEADERS
))
1235 dict
->Remove(keys::kRequestHeadersKey
, NULL
);
1236 if (!(listener
->extra_info_spec
& ExtraInfoSpec::RESPONSE_HEADERS
))
1237 dict
->Remove(keys::kResponseHeadersKey
, NULL
);
1239 EventRouter::DispatchEventToSender(
1240 listener
->ipc_sender
.get(), browser_context
, listener
->extension_id
,
1241 listener
->histogram_value
, listener
->sub_event_name
,
1242 args_filtered
.Pass(), EventRouter::USER_GESTURE_UNKNOWN
,
1243 EventFilteringInfo());
1244 if (listener
->extra_info_spec
&
1245 (ExtraInfoSpec::BLOCKING
| ExtraInfoSpec::ASYNC_BLOCKING
)) {
1246 listener
->blocked_requests
.insert(request
->identifier());
1247 // If this is the first delegate blocking the request, go ahead and log
1249 if (num_handlers_blocking
== 0) {
1250 std::string delegate_info
= l10n_util::GetStringFUTF8(
1251 IDS_LOAD_STATE_PARAMETER_EXTENSION
,
1252 base::UTF8ToUTF16(listener
->extension_name
));
1253 // LobAndReport allows extensions that block requests to be displayed in
1254 // the load status bar.
1255 request
->LogAndReportBlockedBy(delegate_info
.c_str());
1257 ++num_handlers_blocking
;
1261 if (num_handlers_blocking
> 0) {
1262 BlockedRequest
& blocked_request
= blocked_requests_
[request
->identifier()];
1263 blocked_request
.request
= request
;
1264 blocked_request
.is_incognito
|= IsIncognitoBrowserContext(browser_context
);
1265 blocked_request
.num_handlers_blocking
+= num_handlers_blocking
;
1266 blocked_request
.blocking_time
= base::Time::Now();
1273 void ExtensionWebRequestEventRouter::OnEventHandled(
1274 void* browser_context
,
1275 const std::string
& extension_id
,
1276 const std::string
& event_name
,
1277 const std::string
& sub_event_name
,
1278 uint64_t request_id
,
1279 EventResponse
* response
) {
1280 // TODO(robwu): Does this also work with webviews? operator< (used by find)
1281 // takes the webview ID into account, which is not set on |listener|.
1282 EventListener listener
;
1283 listener
.extension_id
= extension_id
;
1284 listener
.sub_event_name
= sub_event_name
;
1286 // The listener may have been removed (e.g. due to the process going away)
1287 // before we got here.
1288 std::set
<EventListener
>::iterator found
=
1289 listeners_
[browser_context
][event_name
].find(listener
);
1290 if (found
!= listeners_
[browser_context
][event_name
].end())
1291 found
->blocked_requests
.erase(request_id
);
1293 DecrementBlockCount(
1294 browser_context
, extension_id
, event_name
, request_id
, response
);
1297 bool ExtensionWebRequestEventRouter::AddEventListener(
1298 void* browser_context
,
1299 const std::string
& extension_id
,
1300 const std::string
& extension_name
,
1301 events::HistogramValue histogram_value
,
1302 const std::string
& event_name
,
1303 const std::string
& sub_event_name
,
1304 const RequestFilter
& filter
,
1305 int extra_info_spec
,
1306 int embedder_process_id
,
1307 int web_view_instance_id
,
1308 base::WeakPtr
<IPC::Sender
> ipc_sender
) {
1309 if (!IsWebRequestEvent(event_name
))
1312 EventListener listener
;
1313 listener
.extension_id
= extension_id
;
1314 listener
.extension_name
= extension_name
;
1315 listener
.histogram_value
= histogram_value
;
1316 listener
.sub_event_name
= sub_event_name
;
1317 listener
.filter
= filter
;
1318 listener
.extra_info_spec
= extra_info_spec
;
1319 listener
.ipc_sender
= ipc_sender
;
1320 listener
.embedder_process_id
= embedder_process_id
;
1321 listener
.web_view_instance_id
= web_view_instance_id
;
1322 if (listener
.web_view_instance_id
) {
1323 content::RecordAction(
1324 base::UserMetricsAction("WebView.WebRequest.AddListener"));
1327 if (ContainsKey(listeners_
[browser_context
][event_name
], listener
)) {
1328 // This is likely an abuse of the API by a malicious extension.
1331 listeners_
[browser_context
][event_name
].insert(listener
);
1335 void ExtensionWebRequestEventRouter::RemoveEventListener(
1336 void* browser_context
,
1337 const std::string
& extension_id
,
1338 const std::string
& sub_event_name
,
1339 int embedder_process_id
,
1340 int web_view_instance_id
) {
1341 std::string event_name
= EventRouter::GetBaseEventName(sub_event_name
);
1342 DCHECK(IsWebRequestEvent(event_name
));
1344 EventListener listener
;
1345 listener
.extension_id
= extension_id
;
1346 listener
.sub_event_name
= sub_event_name
;
1347 listener
.embedder_process_id
= embedder_process_id
;
1348 listener
.web_view_instance_id
= web_view_instance_id
;
1350 std::set
<EventListener
>& event_listeners
=
1351 listeners_
[browser_context
][event_name
];
1352 // It's possible for AddEventListener to fail asynchronously. In that case,
1353 // the renderer believes the listener exists, while the browser does not.
1354 // Ignore a RemoveEventListener in that case.
1355 std::set
<EventListener
>::const_iterator it
= event_listeners
.find(listener
);
1356 if (it
== event_listeners
.end())
1359 CHECK_EQ(event_listeners
.count(listener
), 1u) <<
1360 "extension=" << extension_id
<< " event=" << event_name
;
1362 // Unblock any request that this event listener may have been blocking.
1363 for (uint64_t id
: it
->blocked_requests
)
1364 DecrementBlockCount(browser_context
, extension_id
, event_name
, id
, NULL
);
1366 event_listeners
.erase(listener
);
1368 helpers::ClearCacheOnNavigation();
1371 void ExtensionWebRequestEventRouter::RemoveWebViewEventListeners(
1372 void* browser_context
,
1373 int embedder_process_id
,
1374 int web_view_instance_id
) {
1375 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
1377 // Iterate over all listeners of all WebRequest events to delete
1378 // any listeners that belong to the provided <webview>.
1379 ListenerMapForBrowserContext
& map_for_browser_context
=
1380 listeners_
[browser_context
];
1381 for (const auto& event_iter
: map_for_browser_context
) {
1382 // Construct a listeners_to_delete vector so that we don't modify the set of
1383 // listeners as we iterate through it.
1384 std::vector
<EventListener
> listeners_to_delete
;
1385 const std::set
<EventListener
>& listeners
= event_iter
.second
;
1386 for (const auto& listener
: listeners
) {
1387 if (listener
.embedder_process_id
== embedder_process_id
&&
1388 listener
.web_view_instance_id
== web_view_instance_id
) {
1389 listeners_to_delete
.push_back(listener
);
1392 // Remove the listeners selected for deletion.
1393 for (const auto& listener
: listeners_to_delete
) {
1394 RemoveEventListenerOnIOThread(
1396 listener
.extension_id
,
1397 listener
.sub_event_name
,
1398 listener
.embedder_process_id
,
1399 listener
.web_view_instance_id
);
1404 void ExtensionWebRequestEventRouter::OnOTRBrowserContextCreated(
1405 void* original_browser_context
, void* otr_browser_context
) {
1406 cross_browser_context_map_
[original_browser_context
] =
1407 std::make_pair(false, otr_browser_context
);
1408 cross_browser_context_map_
[otr_browser_context
] =
1409 std::make_pair(true, original_browser_context
);
1412 void ExtensionWebRequestEventRouter::OnOTRBrowserContextDestroyed(
1413 void* original_browser_context
, void* otr_browser_context
) {
1414 cross_browser_context_map_
.erase(otr_browser_context
);
1415 cross_browser_context_map_
.erase(original_browser_context
);
1418 void ExtensionWebRequestEventRouter::AddCallbackForPageLoad(
1419 const base::Closure
& callback
) {
1420 callbacks_for_page_load_
.push_back(callback
);
1423 bool ExtensionWebRequestEventRouter::IsPageLoad(
1424 const net::URLRequest
* request
) const {
1425 bool is_main_frame
= false;
1427 bool parent_is_main_frame
= false;
1428 int parent_frame_id
= -1;
1429 int render_process_host_id
= -1;
1430 int routing_id
= -1;
1431 ResourceType resource_type
= content::RESOURCE_TYPE_LAST_TYPE
;
1433 ExtractRequestInfoDetails(request
, &is_main_frame
, &frame_id
,
1434 &parent_is_main_frame
, &parent_frame_id
,
1435 &render_process_host_id
,
1436 &routing_id
, &resource_type
);
1438 return resource_type
== content::RESOURCE_TYPE_MAIN_FRAME
;
1441 void ExtensionWebRequestEventRouter::NotifyPageLoad() {
1442 for (const auto& callback
: callbacks_for_page_load_
)
1444 callbacks_for_page_load_
.clear();
1447 void* ExtensionWebRequestEventRouter::GetCrossBrowserContext(
1448 void* browser_context
) const {
1449 CrossBrowserContextMap::const_iterator cross_browser_context
=
1450 cross_browser_context_map_
.find(browser_context
);
1451 if (cross_browser_context
== cross_browser_context_map_
.end())
1453 return cross_browser_context
->second
.second
;
1456 bool ExtensionWebRequestEventRouter::IsIncognitoBrowserContext(
1457 void* browser_context
) const {
1458 CrossBrowserContextMap::const_iterator cross_browser_context
=
1459 cross_browser_context_map_
.find(browser_context
);
1460 if (cross_browser_context
== cross_browser_context_map_
.end())
1462 return cross_browser_context
->second
.first
;
1465 bool ExtensionWebRequestEventRouter::WasSignaled(
1466 const net::URLRequest
& request
) const {
1467 SignaledRequestMap::const_iterator flag
=
1468 signaled_requests_
.find(request
.identifier());
1469 return (flag
!= signaled_requests_
.end()) && (flag
->second
!= 0);
1472 void ExtensionWebRequestEventRouter::GetMatchingListenersImpl(
1473 void* browser_context
,
1474 const net::URLRequest
* request
,
1475 const InfoMap
* extension_info_map
,
1476 bool crosses_incognito
,
1477 const std::string
& event_name
,
1479 int render_process_host_id
,
1481 ResourceType resource_type
,
1482 bool is_async_request
,
1483 bool is_request_from_extension
,
1484 int* extra_info_spec
,
1485 EventListeners
* matching_listeners
) {
1486 std::string
web_request_event_name(event_name
);
1487 WebViewRendererState::WebViewInfo web_view_info
;
1488 bool is_web_view_guest
= WebViewRendererState::GetInstance()->GetInfo(
1489 render_process_host_id
, routing_id
, &web_view_info
);
1490 if (is_web_view_guest
) {
1491 web_request_event_name
.replace(
1492 0, sizeof(kWebRequestEventPrefix
) - 1, webview::kWebViewEventPrefix
);
1495 std::set
<EventListener
>& listeners
=
1496 listeners_
[browser_context
][web_request_event_name
];
1497 for (const EventListener
& listener
: listeners
) {
1498 if (!listener
.ipc_sender
.get()) {
1499 // The IPC sender has been deleted. This listener will be removed soon
1500 // via a call to RemoveEventListener. For now, just skip it.
1504 if (is_web_view_guest
&&
1505 (listener
.embedder_process_id
!= web_view_info
.embedder_process_id
||
1506 listener
.web_view_instance_id
!= web_view_info
.instance_id
)) {
1510 // Filter requests from other extensions / apps. This does not work for
1511 // content scripts, or extension pages in non-extension processes.
1512 if (is_request_from_extension
&&
1513 listener
.embedder_process_id
!= render_process_host_id
) {
1517 if (!listener
.filter
.urls
.is_empty() &&
1518 !listener
.filter
.urls
.MatchesURL(url
)) {
1522 if (web_request_event_router_delegate_
&&
1523 web_request_event_router_delegate_
->OnGetMatchingListenersImplCheck(
1524 listener
.filter
.tab_id
, listener
.filter
.window_id
, request
)) {
1528 const std::vector
<content::ResourceType
>& types
= listener
.filter
.types
;
1529 if (!types
.empty() &&
1530 std::find(types
.begin(), types
.end(), resource_type
) == types
.end()) {
1534 if (!is_web_view_guest
&&
1535 !WebRequestPermissions::CanExtensionAccessURL(
1536 extension_info_map
, listener
.extension_id
, url
, crosses_incognito
,
1537 WebRequestPermissions::REQUIRE_HOST_PERMISSION
)) {
1541 bool blocking_listener
=
1542 (listener
.extra_info_spec
&
1543 (ExtraInfoSpec::BLOCKING
| ExtraInfoSpec::ASYNC_BLOCKING
)) != 0;
1545 // We do not want to notify extensions about XHR requests that are
1546 // triggered by themselves. This is a workaround to prevent deadlocks
1547 // in case of synchronous XHR requests that block the extension renderer
1548 // and therefore prevent the extension from processing the request
1549 // handler. This is only a problem for blocking listeners.
1550 // http://crbug.com/105656
1551 bool synchronous_xhr_from_extension
=
1552 !is_async_request
&& is_request_from_extension
&&
1553 resource_type
== content::RESOURCE_TYPE_XHR
;
1555 // Only send webRequest events for URLs the extension has access to.
1556 if (blocking_listener
&& synchronous_xhr_from_extension
)
1559 matching_listeners
->push_back(&listener
);
1560 *extra_info_spec
|= listener
.extra_info_spec
;
1564 ExtensionWebRequestEventRouter::EventListeners
1565 ExtensionWebRequestEventRouter::GetMatchingListeners(
1566 void* browser_context
,
1567 const InfoMap
* extension_info_map
,
1568 const std::string
& event_name
,
1569 const net::URLRequest
* request
,
1570 int* extra_info_spec
) {
1571 // TODO(mpcomplete): handle browser_context == NULL (should collect all
1573 *extra_info_spec
= 0;
1575 bool is_main_frame
= false;
1577 bool parent_is_main_frame
= false;
1578 int parent_frame_id
= -1;
1579 int render_process_host_id
= -1;
1580 int routing_id
= -1;
1581 ResourceType resource_type
= content::RESOURCE_TYPE_LAST_TYPE
;
1582 const GURL
& url
= request
->url();
1584 ExtractRequestInfoDetails(request
, &is_main_frame
, &frame_id
,
1585 &parent_is_main_frame
, &parent_frame_id
,
1586 &render_process_host_id
,
1587 &routing_id
, &resource_type
);
1589 bool is_request_from_extension
=
1590 IsRequestFromExtension(request
, extension_info_map
);
1592 const ResourceRequestInfo
* info
= ResourceRequestInfo::ForRequest(request
);
1593 // We are conservative here and assume requests are asynchronous in case
1594 // we don't have an info object. We don't want to risk a deadlock.
1595 bool is_async_request
= !info
|| info
->IsAsync();
1597 EventListeners matching_listeners
;
1598 GetMatchingListenersImpl(
1599 browser_context
, request
, extension_info_map
, false, event_name
,
1600 url
, render_process_host_id
, routing_id
, resource_type
,
1601 is_async_request
, is_request_from_extension
, extra_info_spec
,
1602 &matching_listeners
);
1603 void* cross_browser_context
= GetCrossBrowserContext(browser_context
);
1604 if (cross_browser_context
) {
1605 GetMatchingListenersImpl(
1606 cross_browser_context
, request
, extension_info_map
, true, event_name
,
1607 url
, render_process_host_id
, routing_id
, resource_type
,
1608 is_async_request
, is_request_from_extension
, extra_info_spec
,
1609 &matching_listeners
);
1612 return matching_listeners
;
1617 helpers::EventResponseDelta
* CalculateDelta(
1618 ExtensionWebRequestEventRouter::BlockedRequest
* blocked_request
,
1619 ExtensionWebRequestEventRouter::EventResponse
* response
) {
1620 switch (blocked_request
->event
) {
1621 case ExtensionWebRequestEventRouter::kOnBeforeRequest
:
1622 return helpers::CalculateOnBeforeRequestDelta(
1623 response
->extension_id
, response
->extension_install_time
,
1624 response
->cancel
, response
->new_url
);
1625 case ExtensionWebRequestEventRouter::kOnBeforeSendHeaders
: {
1626 net::HttpRequestHeaders
* old_headers
= blocked_request
->request_headers
;
1627 net::HttpRequestHeaders
* new_headers
= response
->request_headers
.get();
1628 return helpers::CalculateOnBeforeSendHeadersDelta(
1629 response
->extension_id
, response
->extension_install_time
,
1630 response
->cancel
, old_headers
, new_headers
);
1632 case ExtensionWebRequestEventRouter::kOnHeadersReceived
: {
1633 const net::HttpResponseHeaders
* old_headers
=
1634 blocked_request
->original_response_headers
.get();
1635 helpers::ResponseHeaders
* new_headers
=
1636 response
->response_headers
.get();
1637 return helpers::CalculateOnHeadersReceivedDelta(
1638 response
->extension_id
,
1639 response
->extension_install_time
,
1645 case ExtensionWebRequestEventRouter::kOnAuthRequired
:
1646 return helpers::CalculateOnAuthRequiredDelta(
1647 response
->extension_id
, response
->extension_install_time
,
1648 response
->cancel
, &response
->auth_credentials
);
1655 base::Value
* SerializeResponseHeaders(const helpers::ResponseHeaders
& headers
) {
1656 scoped_ptr
<base::ListValue
> serialized_headers(new base::ListValue());
1657 for (const auto& it
: headers
) {
1658 serialized_headers
->Append(
1659 helpers::CreateHeaderDictionary(it
.first
, it
.second
));
1661 return serialized_headers
.release();
1664 // Convert a RequestCookieModifications/ResponseCookieModifications object to a
1665 // base::ListValue which summarizes the changes made. This is templated since
1666 // the two types (request/response) are different but contain essentially the
1668 template <typename CookieType
>
1669 base::ListValue
* SummarizeCookieModifications(
1670 const std::vector
<linked_ptr
<CookieType
>>& modifications
) {
1671 scoped_ptr
<base::ListValue
> cookie_modifications(new base::ListValue());
1672 for (const auto& it
: modifications
) {
1673 scoped_ptr
<base::DictionaryValue
> summary(new base::DictionaryValue());
1674 const CookieType
& mod
= *(it
.get());
1677 summary
->SetString(activity_log::kCookieModificationTypeKey
,
1678 activity_log::kCookieModificationAdd
);
1681 summary
->SetString(activity_log::kCookieModificationTypeKey
,
1682 activity_log::kCookieModificationEdit
);
1684 case helpers::REMOVE
:
1685 summary
->SetString(activity_log::kCookieModificationTypeKey
,
1686 activity_log::kCookieModificationRemove
);
1690 if (mod
.filter
->name
) {
1691 summary
->SetString(activity_log::kCookieFilterNameKey
,
1692 *mod
.modification
->name
);
1694 if (mod
.filter
->domain
) {
1695 summary
->SetString(activity_log::kCookieFilterDomainKey
,
1696 *mod
.modification
->name
);
1699 if (mod
.modification
) {
1700 if (mod
.modification
->name
) {
1701 summary
->SetString(activity_log::kCookieModDomainKey
,
1702 *mod
.modification
->name
);
1704 if (mod
.modification
->domain
) {
1705 summary
->SetString(activity_log::kCookieModDomainKey
,
1706 *mod
.modification
->name
);
1709 cookie_modifications
->Append(summary
.release());
1711 return cookie_modifications
.release();
1714 // Converts an EventResponseDelta object to a dictionary value suitable for the
1716 scoped_ptr
<base::DictionaryValue
> SummarizeResponseDelta(
1717 const std::string
& event_name
,
1718 const helpers::EventResponseDelta
& delta
) {
1719 scoped_ptr
<base::DictionaryValue
> details(new base::DictionaryValue());
1721 details
->SetBoolean(activity_log::kCancelKey
, true);
1722 if (!delta
.new_url
.is_empty())
1723 details
->SetString(activity_log::kNewUrlKey
, delta
.new_url
.spec());
1725 scoped_ptr
<base::ListValue
> modified_headers(new base::ListValue());
1726 net::HttpRequestHeaders::Iterator
iter(delta
.modified_request_headers
);
1727 while (iter
.GetNext()) {
1728 modified_headers
->Append(
1729 helpers::CreateHeaderDictionary(iter
.name(), iter
.value()));
1731 if (!modified_headers
->empty()) {
1732 details
->Set(activity_log::kModifiedRequestHeadersKey
,
1733 modified_headers
.release());
1736 scoped_ptr
<base::ListValue
> deleted_headers(new base::ListValue());
1737 deleted_headers
->AppendStrings(delta
.deleted_request_headers
);
1738 if (!deleted_headers
->empty()) {
1739 details
->Set(activity_log::kDeletedRequestHeadersKey
,
1740 deleted_headers
.release());
1743 if (!delta
.added_response_headers
.empty()) {
1744 details
->Set(activity_log::kAddedRequestHeadersKey
,
1745 SerializeResponseHeaders(delta
.added_response_headers
));
1747 if (!delta
.deleted_response_headers
.empty()) {
1748 details
->Set(activity_log::kDeletedResponseHeadersKey
,
1749 SerializeResponseHeaders(delta
.deleted_response_headers
));
1751 if (delta
.auth_credentials
) {
1753 activity_log::kAuthCredentialsKey
,
1754 base::UTF16ToUTF8(delta
.auth_credentials
->username()) + ":*");
1757 if (!delta
.response_cookie_modifications
.empty()) {
1759 activity_log::kResponseCookieModificationsKey
,
1760 SummarizeCookieModifications(delta
.response_cookie_modifications
));
1763 return details
.Pass();
1768 void ExtensionWebRequestEventRouter::LogExtensionActivity(
1769 void* browser_context_id
,
1771 const std::string
& extension_id
,
1773 const std::string
& api_call
,
1774 scoped_ptr
<base::DictionaryValue
> details
) {
1775 if (!BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
1776 BrowserThread::PostTask(
1779 base::Bind(&ExtensionWebRequestEventRouter::LogExtensionActivity
,
1780 base::Unretained(this),
1786 base::Passed(&details
)));
1788 if (web_request_event_router_delegate_
) {
1789 web_request_event_router_delegate_
->LogExtensionActivity(
1790 reinterpret_cast<content::BrowserContext
*>(browser_context_id
),
1791 is_incognito
, extension_id
, url
, api_call
, details
.Pass());
1796 void ExtensionWebRequestEventRouter::DecrementBlockCount(
1797 void* browser_context
,
1798 const std::string
& extension_id
,
1799 const std::string
& event_name
,
1800 uint64_t request_id
,
1801 EventResponse
* response
) {
1802 scoped_ptr
<EventResponse
> response_scoped(response
);
1804 // It's possible that this request was deleted, or cancelled by a previous
1805 // event handler. If so, ignore this response.
1806 auto it
= blocked_requests_
.find(request_id
);
1807 if (it
== blocked_requests_
.end())
1810 BlockedRequest
& blocked_request
= it
->second
;
1811 int num_handlers_blocking
= --blocked_request
.num_handlers_blocking
;
1812 CHECK_GE(num_handlers_blocking
, 0);
1815 helpers::EventResponseDelta
* delta
=
1816 CalculateDelta(&blocked_request
, response
);
1818 LogExtensionActivity(browser_context
,
1819 blocked_request
.is_incognito
,
1821 blocked_request
.request
->url(),
1823 SummarizeResponseDelta(event_name
, *delta
));
1825 blocked_request
.response_deltas
.push_back(
1826 linked_ptr
<helpers::EventResponseDelta
>(delta
));
1829 base::TimeDelta block_time
=
1830 base::Time::Now() - blocked_request
.blocking_time
;
1831 if (!extension_id
.empty()) {
1832 request_time_tracker_
->IncrementExtensionBlockTime(
1833 extension_id
, request_id
, block_time
);
1835 // |extension_id| is empty for requests blocked on startup waiting for the
1836 // declarative rules to be read from disk.
1837 UMA_HISTOGRAM_TIMES("Extensions.NetworkDelayStartup", block_time
);
1840 if (num_handlers_blocking
== 0) {
1841 blocked_request
.request
->LogUnblocked();
1842 ExecuteDeltas(browser_context
, request_id
, true);
1844 // Update the URLRequest to make sure it's tagged with an extension that's
1845 // still blocking it. This may end up being the same extension as before.
1846 std::set
<EventListener
>& listeners
=
1847 listeners_
[browser_context
][event_name
];
1849 for (const auto& listener
: listeners
) {
1850 if (!ContainsKey(listener
.blocked_requests
, request_id
))
1852 std::string delegate_info
=
1853 l10n_util::GetStringFUTF8(IDS_LOAD_STATE_PARAMETER_EXTENSION
,
1854 base::UTF8ToUTF16(listener
.extension_name
));
1855 blocked_request
.request
->LogAndReportBlockedBy(delegate_info
.c_str());
1861 void ExtensionWebRequestEventRouter::SendMessages(
1862 void* browser_context
,
1863 const BlockedRequest
& blocked_request
) {
1864 const helpers::EventResponseDeltas
& deltas
= blocked_request
.response_deltas
;
1865 for (const auto& delta
: deltas
) {
1866 const std::set
<std::string
>& messages
= delta
->messages_to_extension
;
1867 for (const std::string
& message
: messages
) {
1868 scoped_ptr
<base::DictionaryValue
> argument(new base::DictionaryValue
);
1869 ExtractRequestInfo(blocked_request
.request
, argument
.get());
1870 WebViewRendererState::WebViewInfo web_view_info
;
1871 bool is_web_view_guest
= GetWebViewInfo(blocked_request
.request
,
1873 argument
->SetString(keys::kMessageKey
, message
);
1874 argument
->SetString(keys::kStageKey
,
1875 GetRequestStageAsString(blocked_request
.event
));
1877 BrowserThread::PostTask(
1878 BrowserThread::UI
, FROM_HERE
,
1879 base::Bind(&SendOnMessageEventOnUI
, browser_context
,
1880 delta
->extension_id
, is_web_view_guest
, web_view_info
,
1881 base::Passed(&argument
)));
1886 int ExtensionWebRequestEventRouter::ExecuteDeltas(void* browser_context
,
1887 uint64_t request_id
,
1888 bool call_callback
) {
1889 BlockedRequest
& blocked_request
= blocked_requests_
[request_id
];
1890 CHECK_EQ(0, blocked_request
.num_handlers_blocking
);
1891 helpers::EventResponseDeltas
& deltas
= blocked_request
.response_deltas
;
1892 base::TimeDelta block_time
=
1893 base::Time::Now() - blocked_request
.blocking_time
;
1894 request_time_tracker_
->IncrementTotalBlockTime(request_id
, block_time
);
1896 bool credentials_set
= false;
1898 deltas
.sort(&helpers::InDecreasingExtensionInstallationTimeOrder
);
1900 bool canceled
= false;
1901 helpers::MergeCancelOfResponses(blocked_request
.response_deltas
, &canceled
,
1902 blocked_request
.net_log
);
1904 WarningSet warnings
;
1905 if (blocked_request
.event
== kOnBeforeRequest
) {
1906 CHECK(!blocked_request
.callback
.is_null());
1907 helpers::MergeOnBeforeRequestResponses(
1908 blocked_request
.response_deltas
,
1909 blocked_request
.new_url
,
1911 blocked_request
.net_log
);
1912 } else if (blocked_request
.event
== kOnBeforeSendHeaders
) {
1913 CHECK(!blocked_request
.callback
.is_null());
1914 helpers::MergeOnBeforeSendHeadersResponses(
1915 blocked_request
.response_deltas
,
1916 blocked_request
.request_headers
,
1918 blocked_request
.net_log
);
1919 } else if (blocked_request
.event
== kOnHeadersReceived
) {
1920 CHECK(!blocked_request
.callback
.is_null());
1921 helpers::MergeOnHeadersReceivedResponses(
1922 blocked_request
.response_deltas
,
1923 blocked_request
.original_response_headers
.get(),
1924 blocked_request
.override_response_headers
,
1925 blocked_request
.new_url
,
1927 blocked_request
.net_log
);
1928 } else if (blocked_request
.event
== kOnAuthRequired
) {
1929 CHECK(blocked_request
.callback
.is_null());
1930 CHECK(!blocked_request
.auth_callback
.is_null());
1931 credentials_set
= helpers::MergeOnAuthRequiredResponses(
1932 blocked_request
.response_deltas
,
1933 blocked_request
.auth_credentials
,
1935 blocked_request
.net_log
);
1940 SendMessages(browser_context
, blocked_request
);
1942 if (!warnings
.empty()) {
1943 BrowserThread::PostTask(
1946 base::Bind(&WarningService::NotifyWarningsOnUI
,
1947 browser_context
, warnings
));
1951 request_time_tracker_
->SetRequestCanceled(request_id
);
1952 } else if (blocked_request
.new_url
&&
1953 !blocked_request
.new_url
->is_empty()) {
1954 request_time_tracker_
->SetRequestRedirected(request_id
);
1957 // This triggers onErrorOccurred if canceled is true.
1958 int rv
= canceled
? net::ERR_BLOCKED_BY_CLIENT
: net::OK
;
1960 if (!blocked_request
.callback
.is_null()) {
1961 net::CompletionCallback callback
= blocked_request
.callback
;
1962 // Ensure that request is removed before callback because the callback
1963 // might trigger the next event.
1964 blocked_requests_
.erase(request_id
);
1967 } else if (!blocked_request
.auth_callback
.is_null()) {
1968 net::NetworkDelegate::AuthRequiredResponse response
;
1970 response
= net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_CANCEL_AUTH
;
1971 else if (credentials_set
)
1972 response
= net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_SET_AUTH
;
1974 response
= net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION
;
1976 net::NetworkDelegate::AuthCallback callback
= blocked_request
.auth_callback
;
1977 blocked_requests_
.erase(request_id
);
1979 callback
.Run(response
);
1981 blocked_requests_
.erase(request_id
);
1986 bool ExtensionWebRequestEventRouter::ProcessDeclarativeRules(
1987 void* browser_context
,
1988 const InfoMap
* extension_info_map
,
1989 const std::string
& event_name
,
1990 net::URLRequest
* request
,
1991 RequestStage request_stage
,
1992 const net::HttpResponseHeaders
* original_response_headers
) {
1993 WebViewRendererState::WebViewInfo web_view_info
;
1994 bool is_web_view_guest
= GetWebViewInfo(request
, &web_view_info
);
1995 int rules_registry_id
= is_web_view_guest
1996 ? web_view_info
.rules_registry_id
1997 : RulesRegistryService::kDefaultRulesRegistryID
;
1999 RulesRegistryKey
rules_key(browser_context
, rules_registry_id
);
2000 // If this check fails, check that the active stages are up-to-date in
2001 // extensions/browser/api/declarative_webrequest/request_stage.h .
2002 DCHECK(request_stage
& kActiveStages
);
2004 // Rules of the current |browser_context| may apply but we need to check also
2005 // whether there are applicable rules from extensions whose background page
2006 // spans from regular to incognito mode.
2008 // First parameter identifies the registry, the second indicates whether the
2009 // registry belongs to the cross browser_context.
2010 using RelevantRegistry
= std::pair
<WebRequestRulesRegistry
*, bool>;
2011 std::vector
<RelevantRegistry
> relevant_registries
;
2013 auto rules_key_it
= rules_registries_
.find(rules_key
);
2014 if (rules_key_it
!= rules_registries_
.end()) {
2015 relevant_registries
.push_back(
2016 std::make_pair(rules_key_it
->second
.get(), false));
2019 void* cross_browser_context
= GetCrossBrowserContext(browser_context
);
2020 RulesRegistryKey
cross_browser_context_rules_key(cross_browser_context
,
2022 if (cross_browser_context
) {
2023 auto it
= rules_registries_
.find(cross_browser_context_rules_key
);
2024 if (it
!= rules_registries_
.end())
2025 relevant_registries
.push_back(std::make_pair(it
->second
.get(), true));
2028 // The following block is experimentally enabled and its impact on load time
2029 // logged with UMA Extensions.NetworkDelayRegistryLoad. crbug.com/175961
2030 for (auto it
: relevant_registries
) {
2031 WebRequestRulesRegistry
* rules_registry
= it
.first
;
2032 if (rules_registry
->ready().is_signaled())
2035 // The rules registry is still loading. Block this request until it
2037 rules_registry
->ready().Post(
2039 base::Bind(&ExtensionWebRequestEventRouter::OnRulesRegistryReady
,
2040 AsWeakPtr(), browser_context
, event_name
,
2041 request
->identifier(), request_stage
));
2042 BlockedRequest
& blocked_request
= blocked_requests_
[request
->identifier()];
2043 blocked_request
.num_handlers_blocking
++;
2044 blocked_request
.request
= request
;
2045 blocked_request
.is_incognito
|= IsIncognitoBrowserContext(browser_context
);
2046 blocked_request
.blocking_time
= base::Time::Now();
2047 blocked_request
.original_response_headers
= original_response_headers
;
2048 blocked_request
.extension_info_map
= extension_info_map
;
2052 base::Time start
= base::Time::Now();
2054 bool deltas_created
= false;
2055 for (const auto& it
: relevant_registries
) {
2056 WebRequestRulesRegistry
* rules_registry
= it
.first
;
2057 helpers::EventResponseDeltas result
= rules_registry
->CreateDeltas(
2059 WebRequestData(request
, request_stage
, original_response_headers
),
2062 if (!result
.empty()) {
2063 helpers::EventResponseDeltas
& deltas
=
2064 blocked_requests_
[request
->identifier()].response_deltas
;
2065 deltas
.insert(deltas
.end(), result
.begin(), result
.end());
2066 deltas_created
= true;
2070 base::TimeDelta elapsed_time
= start
- base::Time::Now();
2071 UMA_HISTOGRAM_TIMES("Extensions.DeclarativeWebRequestNetworkDelay",
2074 return deltas_created
;
2077 void ExtensionWebRequestEventRouter::OnRulesRegistryReady(
2078 void* browser_context
,
2079 const std::string
& event_name
,
2080 uint64_t request_id
,
2081 RequestStage request_stage
) {
2082 // It's possible that this request was deleted, or cancelled by a previous
2083 // event handler. If so, ignore this response.
2084 auto it
= blocked_requests_
.find(request_id
);
2085 if (it
== blocked_requests_
.end())
2088 BlockedRequest
& blocked_request
= it
->second
;
2089 base::TimeDelta block_time
=
2090 base::Time::Now() - blocked_request
.blocking_time
;
2091 UMA_HISTOGRAM_TIMES("Extensions.NetworkDelayRegistryLoad", block_time
);
2093 ProcessDeclarativeRules(browser_context
,
2094 blocked_request
.extension_info_map
,
2096 blocked_request
.request
,
2098 blocked_request
.original_response_headers
.get());
2099 // Reset to NULL so that nobody relies on this being set.
2100 blocked_request
.extension_info_map
= NULL
;
2101 DecrementBlockCount(
2102 browser_context
, std::string(), event_name
, request_id
, NULL
);
2105 bool ExtensionWebRequestEventRouter::GetAndSetSignaled(uint64_t request_id
,
2106 EventTypes event_type
) {
2107 SignaledRequestMap::iterator iter
= signaled_requests_
.find(request_id
);
2108 if (iter
== signaled_requests_
.end()) {
2109 signaled_requests_
[request_id
] = event_type
;
2112 bool was_signaled_before
= (iter
->second
& event_type
) != 0;
2113 iter
->second
|= event_type
;
2114 return was_signaled_before
;
2117 void ExtensionWebRequestEventRouter::ClearSignaled(uint64_t request_id
,
2118 EventTypes event_type
) {
2119 SignaledRequestMap::iterator iter
= signaled_requests_
.find(request_id
);
2120 if (iter
== signaled_requests_
.end())
2122 iter
->second
&= ~event_type
;
2125 // Special QuotaLimitHeuristic for WebRequestHandlerBehaviorChangedFunction.
2127 // Each call of webRequest.handlerBehaviorChanged() clears the in-memory cache
2128 // of WebKit at the time of the next page load (top level navigation event).
2129 // This quota heuristic is intended to limit the number of times the cache is
2130 // cleared by an extension.
2132 // As we want to account for the number of times the cache is really cleared
2133 // (opposed to the number of times webRequest.handlerBehaviorChanged() is
2134 // called), we cannot decide whether a call of
2135 // webRequest.handlerBehaviorChanged() should trigger a quota violation at the
2136 // time it is called. Instead we only decrement the bucket counter at the time
2137 // when the cache is cleared (when page loads happen).
2138 class ClearCacheQuotaHeuristic
: public QuotaLimitHeuristic
{
2140 ClearCacheQuotaHeuristic(const Config
& config
, BucketMapper
* map
)
2141 : QuotaLimitHeuristic(
2144 "MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES"),
2145 callback_registered_(false),
2146 weak_ptr_factory_(this) {}
2147 ~ClearCacheQuotaHeuristic() override
{}
2148 bool Apply(Bucket
* bucket
, const base::TimeTicks
& event_time
) override
;
2151 // Callback that is triggered by the ExtensionWebRequestEventRouter on a page
2154 // We don't need to take care of the life time of |bucket|: It is owned by the
2155 // BucketMapper of our base class in |QuotaLimitHeuristic::bucket_mapper_|. As
2156 // long as |this| exists, the respective BucketMapper and its bucket will
2158 void OnPageLoad(Bucket
* bucket
);
2160 // Flag to prevent that we register more than one call back in-between
2161 // clearing the cache.
2162 bool callback_registered_
;
2164 base::WeakPtrFactory
<ClearCacheQuotaHeuristic
> weak_ptr_factory_
;
2166 DISALLOW_COPY_AND_ASSIGN(ClearCacheQuotaHeuristic
);
2169 bool ClearCacheQuotaHeuristic::Apply(Bucket
* bucket
,
2170 const base::TimeTicks
& event_time
) {
2171 if (event_time
> bucket
->expiration())
2172 bucket
->Reset(config(), event_time
);
2174 // Call bucket->DeductToken() on a new page load, this is when
2175 // webRequest.handlerBehaviorChanged() clears the cache.
2176 if (!callback_registered_
) {
2177 ExtensionWebRequestEventRouter::GetInstance()->AddCallbackForPageLoad(
2178 base::Bind(&ClearCacheQuotaHeuristic::OnPageLoad
,
2179 weak_ptr_factory_
.GetWeakPtr(),
2181 callback_registered_
= true;
2184 // We only check whether tokens are left here. Deducting a token happens in
2186 return bucket
->has_tokens();
2189 void ClearCacheQuotaHeuristic::OnPageLoad(Bucket
* bucket
) {
2190 callback_registered_
= false;
2191 bucket
->DeductToken();
2194 bool WebRequestInternalAddEventListenerFunction::RunSync() {
2195 // Argument 0 is the callback, which we don't use here.
2196 ExtensionWebRequestEventRouter::RequestFilter filter
;
2197 base::DictionaryValue
* value
= NULL
;
2199 EXTENSION_FUNCTION_VALIDATE(args_
->GetDictionary(1, &value
));
2200 // Failure + an empty error string means a fatal error.
2201 EXTENSION_FUNCTION_VALIDATE(filter
.InitFromValue(*value
, &error_
) ||
2203 if (!error_
.empty())
2206 int extra_info_spec
= 0;
2207 if (HasOptionalArgument(2)) {
2208 base::ListValue
* value
= NULL
;
2209 EXTENSION_FUNCTION_VALIDATE(args_
->GetList(2, &value
));
2210 EXTENSION_FUNCTION_VALIDATE(
2211 ExtensionWebRequestEventRouter::ExtraInfoSpec::InitFromValue(
2212 *value
, &extra_info_spec
));
2215 std::string event_name
;
2216 EXTENSION_FUNCTION_VALIDATE(args_
->GetString(3, &event_name
));
2218 std::string sub_event_name
;
2219 EXTENSION_FUNCTION_VALIDATE(args_
->GetString(4, &sub_event_name
));
2221 int web_view_instance_id
= 0;
2222 EXTENSION_FUNCTION_VALIDATE(args_
->GetInteger(5, &web_view_instance_id
));
2224 base::WeakPtr
<IOThreadExtensionMessageFilter
> ipc_sender
= ipc_sender_weak();
2225 int embedder_process_id
= ipc_sender
? ipc_sender
->render_process_id() : 0;
2227 const Extension
* extension
=
2228 extension_info_map()->extensions().GetByID(extension_id_safe());
2229 std::string extension_name
=
2230 extension
? extension
->name() : extension_id_safe();
2232 if (!web_view_instance_id
) {
2233 // We check automatically whether the extension has the 'webRequest'
2234 // permission. For blocking calls we require the additional permission
2235 // 'webRequestBlocking'.
2236 if ((extra_info_spec
&
2237 (ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING
|
2238 ExtensionWebRequestEventRouter::ExtraInfoSpec::ASYNC_BLOCKING
)) &&
2239 !extension
->permissions_data()->HasAPIPermission(
2240 APIPermission::kWebRequestBlocking
)) {
2241 error_
= keys::kBlockingPermissionRequired
;
2245 // We allow to subscribe to patterns that are broader than the host
2246 // permissions. E.g., we could subscribe to http://www.example.com/*
2247 // while having host permissions for http://www.example.com/foo/* and
2248 // http://www.example.com/bar/*.
2249 // For this reason we do only a coarse check here to warn the extension
2250 // developer if he does something obviously wrong.
2251 if (extension
->permissions_data()
2252 ->GetEffectiveHostPermissions()
2254 error_
= keys::kHostPermissionsRequired
;
2260 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
2261 profile_id(), extension_id_safe(), extension_name
,
2262 GetEventHistogramValue(event_name
), event_name
, sub_event_name
,
2263 filter
, extra_info_spec
, embedder_process_id
, web_view_instance_id
,
2265 EXTENSION_FUNCTION_VALIDATE(success
);
2267 helpers::ClearCacheOnNavigation();
2269 if (!extension_id_safe().empty()) {
2270 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
2271 base::Bind(&helpers::NotifyWebRequestAPIUsed
,
2272 profile_id(), extension_id_safe()));
2278 void WebRequestInternalEventHandledFunction::RespondWithError(
2279 const std::string
& event_name
,
2280 const std::string
& sub_event_name
,
2281 uint64_t request_id
,
2282 scoped_ptr
<ExtensionWebRequestEventRouter::EventResponse
> response
,
2283 const std::string
& error
) {
2285 ExtensionWebRequestEventRouter::GetInstance()->OnEventHandled(
2287 extension_id_safe(),
2291 response
.release());
2294 bool WebRequestInternalEventHandledFunction::RunSync() {
2295 std::string event_name
;
2296 EXTENSION_FUNCTION_VALIDATE(args_
->GetString(0, &event_name
));
2298 std::string sub_event_name
;
2299 EXTENSION_FUNCTION_VALIDATE(args_
->GetString(1, &sub_event_name
));
2301 std::string request_id_str
;
2302 EXTENSION_FUNCTION_VALIDATE(args_
->GetString(2, &request_id_str
));
2303 uint64_t request_id
;
2304 EXTENSION_FUNCTION_VALIDATE(base::StringToUint64(request_id_str
,
2307 scoped_ptr
<ExtensionWebRequestEventRouter::EventResponse
> response
;
2308 if (HasOptionalArgument(3)) {
2309 base::DictionaryValue
* value
= NULL
;
2310 EXTENSION_FUNCTION_VALIDATE(args_
->GetDictionary(3, &value
));
2312 if (!value
->empty()) {
2313 base::Time install_time
=
2314 extension_info_map()->GetInstallTime(extension_id_safe());
2315 response
.reset(new ExtensionWebRequestEventRouter::EventResponse(
2316 extension_id_safe(), install_time
));
2319 if (value
->HasKey("cancel")) {
2320 // Don't allow cancel mixed with other keys.
2321 if (value
->size() != 1) {
2322 RespondWithError(event_name
,
2326 keys::kInvalidBlockingResponse
);
2330 bool cancel
= false;
2331 EXTENSION_FUNCTION_VALIDATE(value
->GetBoolean("cancel", &cancel
));
2332 response
->cancel
= cancel
;
2335 if (value
->HasKey("redirectUrl")) {
2336 std::string new_url_str
;
2337 EXTENSION_FUNCTION_VALIDATE(value
->GetString("redirectUrl",
2339 response
->new_url
= GURL(new_url_str
);
2340 if (!response
->new_url
.is_valid()) {
2341 RespondWithError(event_name
,
2345 ErrorUtils::FormatErrorMessage(
2346 keys::kInvalidRedirectUrl
, new_url_str
));
2351 const bool has_request_headers
= value
->HasKey("requestHeaders");
2352 const bool has_response_headers
= value
->HasKey("responseHeaders");
2353 if (has_request_headers
|| has_response_headers
) {
2354 if (has_request_headers
&& has_response_headers
) {
2355 // Allow only one of the keys, not both.
2356 RespondWithError(event_name
,
2360 keys::kInvalidHeaderKeyCombination
);
2364 base::ListValue
* headers_value
= NULL
;
2365 scoped_ptr
<net::HttpRequestHeaders
> request_headers
;
2366 scoped_ptr
<helpers::ResponseHeaders
> response_headers
;
2367 if (has_request_headers
) {
2368 request_headers
.reset(new net::HttpRequestHeaders());
2369 EXTENSION_FUNCTION_VALIDATE(value
->GetList(keys::kRequestHeadersKey
,
2372 response_headers
.reset(new helpers::ResponseHeaders());
2373 EXTENSION_FUNCTION_VALIDATE(value
->GetList(keys::kResponseHeadersKey
,
2377 for (size_t i
= 0; i
< headers_value
->GetSize(); ++i
) {
2378 base::DictionaryValue
* header_value
= NULL
;
2381 EXTENSION_FUNCTION_VALIDATE(
2382 headers_value
->GetDictionary(i
, &header_value
));
2383 if (!FromHeaderDictionary(header_value
, &name
, &value
)) {
2384 std::string serialized_header
;
2385 base::JSONWriter::Write(*header_value
, &serialized_header
);
2386 RespondWithError(event_name
,
2390 ErrorUtils::FormatErrorMessage(keys::kInvalidHeader
,
2391 serialized_header
));
2394 if (!net::HttpUtil::IsValidHeaderName(name
)) {
2395 RespondWithError(event_name
,
2399 keys::kInvalidHeaderName
);
2402 if (!net::HttpUtil::IsValidHeaderValue(value
)) {
2403 RespondWithError(event_name
,
2407 ErrorUtils::FormatErrorMessage(
2408 keys::kInvalidHeaderValue
, name
));
2411 if (has_request_headers
)
2412 request_headers
->SetHeader(name
, value
);
2414 response_headers
->push_back(helpers::ResponseHeader(name
, value
));
2416 if (has_request_headers
)
2417 response
->request_headers
.reset(request_headers
.release());
2419 response
->response_headers
.reset(response_headers
.release());
2422 if (value
->HasKey(keys::kAuthCredentialsKey
)) {
2423 base::DictionaryValue
* credentials_value
= NULL
;
2424 EXTENSION_FUNCTION_VALIDATE(value
->GetDictionary(
2425 keys::kAuthCredentialsKey
,
2426 &credentials_value
));
2427 base::string16 username
;
2428 base::string16 password
;
2429 EXTENSION_FUNCTION_VALIDATE(
2430 credentials_value
->GetString(keys::kUsernameKey
, &username
));
2431 EXTENSION_FUNCTION_VALIDATE(
2432 credentials_value
->GetString(keys::kPasswordKey
, &password
));
2433 response
->auth_credentials
.reset(
2434 new net::AuthCredentials(username
, password
));
2438 ExtensionWebRequestEventRouter::GetInstance()->OnEventHandled(
2439 profile_id(), extension_id_safe(), event_name
, sub_event_name
, request_id
,
2440 response
.release());
2445 void WebRequestHandlerBehaviorChangedFunction::GetQuotaLimitHeuristics(
2446 QuotaLimitHeuristics
* heuristics
) const {
2447 QuotaLimitHeuristic::Config config
= {
2448 // See web_request.json for current value.
2449 web_request::MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES
,
2450 base::TimeDelta::FromMinutes(10)};
2451 QuotaLimitHeuristic::BucketMapper
* bucket_mapper
=
2452 new QuotaLimitHeuristic::SingletonBucketMapper();
2453 ClearCacheQuotaHeuristic
* heuristic
=
2454 new ClearCacheQuotaHeuristic(config
, bucket_mapper
);
2455 heuristics
->push_back(heuristic
);
2458 void WebRequestHandlerBehaviorChangedFunction::OnQuotaExceeded(
2459 const std::string
& violation_error
) {
2460 // Post warning message.
2461 WarningSet warnings
;
2463 Warning::CreateRepeatedCacheFlushesWarning(extension_id_safe()));
2464 BrowserThread::PostTask(
2467 base::Bind(&WarningService::NotifyWarningsOnUI
, profile_id(), warnings
));
2469 // Continue gracefully.
2473 bool WebRequestHandlerBehaviorChangedFunction::RunSync() {
2474 helpers::ClearCacheOnNavigation();
2478 } // namespace extensions