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 "android_webview/browser/aw_content_browser_client.h"
7 #include "android_webview/browser/aw_browser_context.h"
8 #include "android_webview/browser/aw_browser_main_parts.h"
9 #include "android_webview/browser/aw_browser_permission_request_delegate.h"
10 #include "android_webview/browser/aw_contents_client_bridge_base.h"
11 #include "android_webview/browser/aw_contents_io_thread_client.h"
12 #include "android_webview/browser/aw_cookie_access_policy.h"
13 #include "android_webview/browser/aw_dev_tools_manager_delegate.h"
14 #include "android_webview/browser/aw_printing_message_filter.h"
15 #include "android_webview/browser/aw_quota_permission_context.h"
16 #include "android_webview/browser/aw_web_preferences_populater.h"
17 #include "android_webview/browser/jni_dependency_factory.h"
18 #include "android_webview/browser/net/aw_url_request_context_getter.h"
19 #include "android_webview/browser/net_disk_cache_remover.h"
20 #include "android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.h"
21 #include "android_webview/common/render_view_messages.h"
22 #include "android_webview/common/url_constants.h"
23 #include "base/android/locale_utils.h"
24 #include "base/base_paths_android.h"
25 #include "base/path_service.h"
26 #include "components/cdm/browser/cdm_message_filter_android.h"
27 #include "content/public/browser/access_token_store.h"
28 #include "content/public/browser/browser_message_filter.h"
29 #include "content/public/browser/browser_thread.h"
30 #include "content/public/browser/child_process_security_policy.h"
31 #include "content/public/browser/permission_type.h"
32 #include "content/public/browser/render_process_host.h"
33 #include "content/public/browser/render_view_host.h"
34 #include "content/public/browser/web_contents.h"
35 #include "content/public/common/url_constants.h"
36 #include "content/public/common/web_preferences.h"
37 #include "net/android/network_library.h"
38 #include "net/ssl/ssl_cert_request_info.h"
39 #include "net/ssl/ssl_info.h"
40 #include "ui/base/resource/resource_bundle.h"
41 #include "ui/resources/grit/ui_resources.h"
43 using content::BrowserThread
;
44 using content::ResourceType
;
46 namespace android_webview
{
49 // TODO(sgurun) move this to its own file.
50 // This class filters out incoming aw_contents related IPC messages for the
51 // renderer process on the IPC thread.
52 class AwContentsMessageFilter
: public content::BrowserMessageFilter
{
54 explicit AwContentsMessageFilter(int process_id
);
56 // BrowserMessageFilter methods.
57 virtual void OverrideThreadForMessage(
58 const IPC::Message
& message
,
59 BrowserThread::ID
* thread
) override
;
60 virtual bool OnMessageReceived(
61 const IPC::Message
& message
) override
;
63 void OnShouldOverrideUrlLoading(int routing_id
,
64 const base::string16
& url
,
65 bool* ignore_navigation
);
66 void OnSubFrameCreated(int parent_render_frame_id
, int child_render_frame_id
);
69 virtual ~AwContentsMessageFilter();
73 DISALLOW_COPY_AND_ASSIGN(AwContentsMessageFilter
);
76 AwContentsMessageFilter::AwContentsMessageFilter(int process_id
)
77 : BrowserMessageFilter(AndroidWebViewMsgStart
),
78 process_id_(process_id
) {
81 AwContentsMessageFilter::~AwContentsMessageFilter() {
84 void AwContentsMessageFilter::OverrideThreadForMessage(
85 const IPC::Message
& message
, BrowserThread::ID
* thread
) {
86 if (message
.type() == AwViewHostMsg_ShouldOverrideUrlLoading::ID
) {
87 *thread
= BrowserThread::UI
;
91 bool AwContentsMessageFilter::OnMessageReceived(const IPC::Message
& message
) {
93 IPC_BEGIN_MESSAGE_MAP(AwContentsMessageFilter
, message
)
94 IPC_MESSAGE_HANDLER(AwViewHostMsg_ShouldOverrideUrlLoading
,
95 OnShouldOverrideUrlLoading
)
96 IPC_MESSAGE_HANDLER(AwViewHostMsg_SubFrameCreated
, OnSubFrameCreated
)
97 IPC_MESSAGE_UNHANDLED(handled
= false)
102 void AwContentsMessageFilter::OnShouldOverrideUrlLoading(
104 const base::string16
& url
,
105 bool* ignore_navigation
) {
106 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
107 *ignore_navigation
= false;
108 AwContentsClientBridgeBase
* client
=
109 AwContentsClientBridgeBase::FromID(process_id_
, render_frame_id
);
111 *ignore_navigation
= client
->ShouldOverrideUrlLoading(url
);
113 LOG(WARNING
) << "Failed to find the associated render view host for url: "
118 void AwContentsMessageFilter::OnSubFrameCreated(int parent_render_frame_id
,
119 int child_render_frame_id
) {
120 AwContentsIoThreadClient::SubFrameCreated(
121 process_id_
, parent_render_frame_id
, child_render_frame_id
);
124 class AwAccessTokenStore
: public content::AccessTokenStore
{
126 AwAccessTokenStore() { }
128 // content::AccessTokenStore implementation
129 virtual void LoadAccessTokens(
130 const LoadAccessTokensCallbackType
& request
) override
{
131 AccessTokenStore::AccessTokenSet access_token_set
;
132 // AccessTokenSet and net::URLRequestContextGetter not used on Android,
133 // but Run needs to be called to finish the geolocation setup.
134 request
.Run(access_token_set
, NULL
);
136 virtual void SaveAccessToken(const GURL
& server_url
,
137 const base::string16
& access_token
) override
{ }
140 virtual ~AwAccessTokenStore() { }
142 DISALLOW_COPY_AND_ASSIGN(AwAccessTokenStore
);
147 std::string
AwContentBrowserClient::GetAcceptLangsImpl() {
148 // Start with the currnet locale.
149 std::string langs
= base::android::GetDefaultLocale();
151 // If we're not en-US, add in en-US which will be
152 // used with a lower q-value.
153 if (base::StringToLowerASCII(langs
) != "en-us") {
159 AwBrowserContext
* AwContentBrowserClient::GetAwBrowserContext() {
160 return AwBrowserContext::GetDefault();
163 AwContentBrowserClient::AwContentBrowserClient(
164 JniDependencyFactory
* native_factory
)
165 : native_factory_(native_factory
) {
166 base::FilePath user_data_dir
;
167 if (!PathService::Get(base::DIR_ANDROID_APP_DATA
, &user_data_dir
)) {
168 NOTREACHED() << "Failed to get app data directory for Android WebView";
170 browser_context_
.reset(
171 new AwBrowserContext(user_data_dir
, native_factory_
));
174 AwContentBrowserClient::~AwContentBrowserClient() {
177 void AwContentBrowserClient::AddCertificate(net::CertificateMimeType cert_type
,
178 const void* cert_data
,
180 int render_process_id
,
181 int render_frame_id
) {
183 net::android::StoreCertificate(cert_type
, cert_data
, cert_size
);
186 content::BrowserMainParts
* AwContentBrowserClient::CreateBrowserMainParts(
187 const content::MainFunctionParams
& parameters
) {
188 return new AwBrowserMainParts(browser_context_
.get());
191 content::WebContentsViewDelegate
*
192 AwContentBrowserClient::GetWebContentsViewDelegate(
193 content::WebContents
* web_contents
) {
194 return native_factory_
->CreateViewDelegate(web_contents
);
197 void AwContentBrowserClient::RenderProcessWillLaunch(
198 content::RenderProcessHost
* host
) {
199 // If WebView becomes multi-process capable, this may be insecure.
200 // More benefit can be derived from the ChildProcessSecurotyPolicy by
201 // deferring the GrantScheme calls until we know that a given child process
202 // really does need that priviledge. Check here to ensure we rethink this
203 // when the time comes. See crbug.com/156062.
204 CHECK(content::RenderProcessHost::run_renderer_in_process());
206 // Grant content: and file: scheme to the whole process, since we impose
207 // per-view access checks.
208 content::ChildProcessSecurityPolicy::GetInstance()->GrantScheme(
209 host
->GetID(), android_webview::kContentScheme
);
210 content::ChildProcessSecurityPolicy::GetInstance()->GrantScheme(
211 host
->GetID(), url::kFileScheme
);
213 host
->AddFilter(new AwContentsMessageFilter(host
->GetID()));
214 host
->AddFilter(new cdm::CdmMessageFilterAndroid());
215 host
->AddFilter(new AwPrintingMessageFilter(host
->GetID()));
218 net::URLRequestContextGetter
* AwContentBrowserClient::CreateRequestContext(
219 content::BrowserContext
* browser_context
,
220 content::ProtocolHandlerMap
* protocol_handlers
,
221 content::URLRequestInterceptorScopedVector request_interceptors
) {
222 DCHECK_EQ(browser_context_
.get(), browser_context
);
223 return browser_context_
->CreateRequestContext(protocol_handlers
,
224 request_interceptors
.Pass());
227 net::URLRequestContextGetter
*
228 AwContentBrowserClient::CreateRequestContextForStoragePartition(
229 content::BrowserContext
* browser_context
,
230 const base::FilePath
& partition_path
,
232 content::ProtocolHandlerMap
* protocol_handlers
,
233 content::URLRequestInterceptorScopedVector request_interceptors
) {
234 DCHECK_EQ(browser_context_
.get(), browser_context
);
235 // TODO(mkosiba,kinuko): request_interceptors should be hooked up in the
236 // downstream. (crbug.com/350286)
237 return browser_context_
->CreateRequestContextForStoragePartition(
238 partition_path
, in_memory
, protocol_handlers
,
239 request_interceptors
.Pass());
242 std::string
AwContentBrowserClient::GetCanonicalEncodingNameByAliasName(
243 const std::string
& alias_name
) {
247 void AwContentBrowserClient::AppendExtraCommandLineSwitches(
248 base::CommandLine
* command_line
,
249 int child_process_id
) {
250 NOTREACHED() << "Android WebView does not support multi-process yet";
253 std::string
AwContentBrowserClient::GetApplicationLocale() {
254 return base::android::GetDefaultLocale();
257 std::string
AwContentBrowserClient::GetAcceptLangs(
258 content::BrowserContext
* context
) {
259 return GetAcceptLangsImpl();
262 const gfx::ImageSkia
* AwContentBrowserClient::GetDefaultFavicon() {
263 ResourceBundle
& rb
= ResourceBundle::GetSharedInstance();
264 // TODO(boliu): Bundle our own default favicon?
265 return rb
.GetImageSkiaNamed(IDR_DEFAULT_FAVICON
);
268 bool AwContentBrowserClient::AllowAppCache(const GURL
& manifest_url
,
269 const GURL
& first_party
,
270 content::ResourceContext
* context
) {
271 // WebView doesn't have a per-site policy for locally stored data,
272 // instead AppCache can be disabled for individual WebViews.
277 bool AwContentBrowserClient::AllowGetCookie(const GURL
& url
,
278 const GURL
& first_party
,
279 const net::CookieList
& cookie_list
,
280 content::ResourceContext
* context
,
281 int render_process_id
,
282 int render_frame_id
) {
283 return AwCookieAccessPolicy::GetInstance()->AllowGetCookie(url
,
291 bool AwContentBrowserClient::AllowSetCookie(const GURL
& url
,
292 const GURL
& first_party
,
293 const std::string
& cookie_line
,
294 content::ResourceContext
* context
,
295 int render_process_id
,
297 net::CookieOptions
* options
) {
298 return AwCookieAccessPolicy::GetInstance()->AllowSetCookie(url
,
307 bool AwContentBrowserClient::AllowWorkerDatabase(
309 const base::string16
& name
,
310 const base::string16
& display_name
,
311 unsigned long estimated_size
,
312 content::ResourceContext
* context
,
313 const std::vector
<std::pair
<int, int> >& render_frames
) {
314 // Android WebView does not yet support web workers.
318 void AwContentBrowserClient::AllowWorkerFileSystem(
320 content::ResourceContext
* context
,
321 const std::vector
<std::pair
<int, int> >& render_frames
,
322 base::Callback
<void(bool)> callback
) {
323 // Android WebView does not yet support web workers.
327 bool AwContentBrowserClient::AllowWorkerIndexedDB(
329 const base::string16
& name
,
330 content::ResourceContext
* context
,
331 const std::vector
<std::pair
<int, int> >& render_frames
) {
332 // Android WebView does not yet support web workers.
336 content::QuotaPermissionContext
*
337 AwContentBrowserClient::CreateQuotaPermissionContext() {
338 return new AwQuotaPermissionContext
;
341 void AwContentBrowserClient::AllowCertificateError(
342 int render_process_id
,
345 const net::SSLInfo
& ssl_info
,
346 const GURL
& request_url
,
347 ResourceType resource_type
,
349 bool strict_enforcement
,
350 bool expired_previous_decision
,
351 const base::Callback
<void(bool)>& callback
,
352 content::CertificateRequestResultType
* result
) {
353 AwContentsClientBridgeBase
* client
=
354 AwContentsClientBridgeBase::FromID(render_process_id
, render_frame_id
);
355 bool cancel_request
= true;
357 client
->AllowCertificateError(cert_error
,
363 *result
= content::CERTIFICATE_REQUEST_RESULT_TYPE_DENY
;
366 void AwContentBrowserClient::SelectClientCertificate(
367 int render_process_id
,
369 net::SSLCertRequestInfo
* cert_request_info
,
370 const base::Callback
<void(net::X509Certificate
*)>& callback
) {
371 AwContentsClientBridgeBase
* client
=
372 AwContentsClientBridgeBase::FromID(render_process_id
, render_frame_id
);
374 client
->SelectClientCertificate(cert_request_info
, callback
);
380 void AwContentBrowserClient::RequestPermission(
381 content::PermissionType permission
,
382 content::WebContents
* web_contents
,
384 const GURL
& requesting_frame
,
386 const base::Callback
<void(bool)>& result_callback
) {
387 int render_process_id
= web_contents
->GetRenderProcessHost()->GetID();
388 int render_view_id
= web_contents
->GetRenderViewHost()->GetRoutingID();
389 GURL origin
= requesting_frame
.GetOrigin();
390 AwBrowserPermissionRequestDelegate
* delegate
=
391 AwBrowserPermissionRequestDelegate::FromID(render_process_id
,
393 switch (permission
) {
394 case content::PERMISSION_GEOLOCATION
:
396 DVLOG(0) << "Dropping GeolocationPermission request";
397 result_callback
.Run(false);
400 delegate
->RequestGeolocationPermission(origin
, result_callback
);
402 case content::PERMISSION_PROTECTED_MEDIA_IDENTIFIER
:
404 DVLOG(0) << "Dropping ProtectedMediaIdentifierPermission request";
405 result_callback
.Run(false);
408 delegate
->RequestProtectedMediaIdentifierPermission(origin
,
411 case content::PERMISSION_MIDI_SYSEX
:
412 case content::PERMISSION_NOTIFICATIONS
:
413 case content::PERMISSION_PUSH_MESSAGING
:
414 NOTIMPLEMENTED() << "RequestPermission not implemented for "
417 case content::PERMISSION_NUM
:
418 NOTREACHED() << "Invalid RequestPermission for " << permission
;
423 void AwContentBrowserClient::CancelPermissionRequest(
424 content::PermissionType permission
,
425 content::WebContents
* web_contents
,
427 const GURL
& origin
) {
428 int render_process_id
= web_contents
->GetRenderProcessHost()->GetID();
429 int render_view_id
= web_contents
->GetRenderViewHost()->GetRoutingID();
430 AwBrowserPermissionRequestDelegate
* delegate
=
431 AwBrowserPermissionRequestDelegate::FromID(render_process_id
,
435 switch (permission
) {
436 case content::PERMISSION_GEOLOCATION
:
437 delegate
->CancelGeolocationPermissionRequests(origin
);
439 case content::PERMISSION_PROTECTED_MEDIA_IDENTIFIER
:
440 delegate
->CancelProtectedMediaIdentifierPermissionRequests(origin
);
442 case content::PERMISSION_MIDI_SYSEX
:
443 case content::PERMISSION_NOTIFICATIONS
:
444 case content::PERMISSION_PUSH_MESSAGING
:
445 NOTIMPLEMENTED() << "CancelPermission not implemented for " << permission
;
447 case content::PERMISSION_NUM
:
448 NOTREACHED() << "Invalid CancelPermission for " << permission
;
453 bool AwContentBrowserClient::CanCreateWindow(
454 const GURL
& opener_url
,
455 const GURL
& opener_top_level_frame_url
,
456 const GURL
& source_origin
,
457 WindowContainerType container_type
,
458 const GURL
& target_url
,
459 const content::Referrer
& referrer
,
460 WindowOpenDisposition disposition
,
461 const blink::WebWindowFeatures
& features
,
463 bool opener_suppressed
,
464 content::ResourceContext
* context
,
465 int render_process_id
,
467 bool* no_javascript_access
) {
468 // We unconditionally allow popup windows at this stage and will give
469 // the embedder the opporunity to handle displaying of the popup in
470 // WebContentsDelegate::AddContents (via the
471 // AwContentsClient.onCreateWindow callback).
472 // Note that if the embedder has blocked support for creating popup
473 // windows through AwSettings, then we won't get to this point as
474 // the popup creation will have been blocked at the WebKit level.
475 if (no_javascript_access
) {
476 *no_javascript_access
= false;
481 void AwContentBrowserClient::ResourceDispatcherHostCreated() {
482 AwResourceDispatcherHostDelegate::ResourceDispatcherHostCreated();
485 net::NetLog
* AwContentBrowserClient::GetNetLog() {
486 return browser_context_
->GetAwURLRequestContext()->GetNetLog();
489 content::AccessTokenStore
* AwContentBrowserClient::CreateAccessTokenStore() {
490 return new AwAccessTokenStore();
493 bool AwContentBrowserClient::IsFastShutdownPossible() {
494 NOTREACHED() << "Android WebView is single process, so IsFastShutdownPossible"
495 << " should never be called";
499 void AwContentBrowserClient::ClearCache(content::RenderViewHost
* rvh
) {
500 RemoveHttpDiskCache(rvh
->GetProcess()->GetBrowserContext(),
501 rvh
->GetProcess()->GetID());
504 void AwContentBrowserClient::ClearCookies(content::RenderViewHost
* rvh
) {
505 // TODO(boliu): Implement.
509 base::FilePath
AwContentBrowserClient::GetDefaultDownloadDirectory() {
510 // Android WebView does not currently use the Chromium downloads system.
511 // Download requests are cancelled immedately when recognized; see
512 // AwResourceDispatcherHost::CreateResourceHandlerForDownload. However the
513 // download system still tries to start up and calls this before recognizing
514 // the request has been cancelled.
515 return base::FilePath();
518 std::string
AwContentBrowserClient::GetDefaultDownloadName() {
519 NOTREACHED() << "Android WebView does not use chromium downloads";
520 return std::string();
523 void AwContentBrowserClient::DidCreatePpapiPlugin(
524 content::BrowserPpapiHost
* browser_host
) {
525 NOTREACHED() << "Android WebView does not support plugins";
528 bool AwContentBrowserClient::AllowPepperSocketAPI(
529 content::BrowserContext
* browser_context
,
532 const content::SocketPermissionRequest
* params
) {
533 NOTREACHED() << "Android WebView does not support plugins";
537 void AwContentBrowserClient::OverrideWebkitPrefs(
538 content::RenderViewHost
* rvh
,
540 content::WebPreferences
* web_prefs
) {
541 if (!preferences_populater_
.get()) {
542 preferences_populater_
= make_scoped_ptr(native_factory_
->
543 CreateWebPreferencesPopulater());
545 preferences_populater_
->PopulateFor(
546 content::WebContents::FromRenderViewHost(rvh
), web_prefs
);
549 #if defined(VIDEO_HOLE)
550 content::ExternalVideoSurfaceContainer
*
551 AwContentBrowserClient::OverrideCreateExternalVideoSurfaceContainer(
552 content::WebContents
* web_contents
) {
553 return native_factory_
->CreateExternalVideoSurfaceContainer(web_contents
);
557 content::DevToolsManagerDelegate
*
558 AwContentBrowserClient::GetDevToolsManagerDelegate() {
559 return new AwDevToolsManagerDelegate();
562 } // namespace android_webview