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