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. 4 5 #include "android_webview/browser/aw_content_browser_client.h" 6 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_quota_permission_context.h" 14 #include "android_webview/browser/aw_web_preferences_populater.h" 15 #include "android_webview/browser/jni_dependency_factory.h" 16 #include "android_webview/browser/net_disk_cache_remover.h" 17 #include "android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.h" 18 #include "android_webview/common/render_view_messages.h" 19 #include "android_webview/common/url_constants.h" 20 #include "base/base_paths_android.h" 21 #include "base/path_service.h" 22 #include "components/cdm/browser/cdm_message_filter_android.h" 23 #include "content/public/browser/access_token_store.h" 24 #include "content/public/browser/browser_message_filter.h" 25 #include "content/public/browser/browser_thread.h" 26 #include "content/public/browser/child_process_security_policy.h" 27 #include "content/public/browser/render_process_host.h" 28 #include "content/public/browser/render_view_host.h" 29 #include "content/public/browser/web_contents.h" 30 #include "content/public/common/url_constants.h" 31 #include "grit/ui_resources.h" 32 #include "net/android/network_library.h" 33 #include "net/ssl/ssl_cert_request_info.h" 34 #include "net/ssl/ssl_info.h" 35 #include "ui/base/l10n/l10n_util_android.h" 36 #include "ui/base/resource/resource_bundle.h" 37 #include "webkit/common/webpreferences.h" 38 39 using content::BrowserThread; 40 41 namespace android_webview { 42 namespace { 43 44 // TODO(sgurun) move this to its own file. 45 // This class filters out incoming aw_contents related IPC messages for the 46 // renderer process on the IPC thread. 47 class AwContentsMessageFilter : public content::BrowserMessageFilter { 48 public: 49 explicit AwContentsMessageFilter(int process_id); 50 51 // BrowserMessageFilter methods. 52 virtual void OverrideThreadForMessage( 53 const IPC::Message& message, 54 BrowserThread::ID* thread) OVERRIDE; 55 virtual bool OnMessageReceived( 56 const IPC::Message& message) OVERRIDE; 57 58 void OnShouldOverrideUrlLoading(int routing_id, 59 const base::string16& url, 60 bool* ignore_navigation); 61 void OnSubFrameCreated(int parent_render_frame_id, int child_render_frame_id); 62 63 private: 64 virtual ~AwContentsMessageFilter(); 65 66 int process_id_; 67 68 DISALLOW_COPY_AND_ASSIGN(AwContentsMessageFilter); 69 }; 70 71 AwContentsMessageFilter::AwContentsMessageFilter(int process_id) 72 : BrowserMessageFilter(AndroidWebViewMsgStart), 73 process_id_(process_id) { 74 } 75 76 AwContentsMessageFilter::~AwContentsMessageFilter() { 77 } 78 79 void AwContentsMessageFilter::OverrideThreadForMessage( 80 const IPC::Message& message, BrowserThread::ID* thread) { 81 if (message.type() == AwViewHostMsg_ShouldOverrideUrlLoading::ID) { 82 *thread = BrowserThread::UI; 83 } 84 } 85 86 bool AwContentsMessageFilter::OnMessageReceived(const IPC::Message& message) { 87 bool handled = true; 88 IPC_BEGIN_MESSAGE_MAP(AwContentsMessageFilter, message) 89 IPC_MESSAGE_HANDLER(AwViewHostMsg_ShouldOverrideUrlLoading, 90 OnShouldOverrideUrlLoading) 91 IPC_MESSAGE_HANDLER(AwViewHostMsg_SubFrameCreated, OnSubFrameCreated) 92 IPC_MESSAGE_UNHANDLED(handled = false) 93 IPC_END_MESSAGE_MAP() 94 return handled; 95 } 96 97 void AwContentsMessageFilter::OnShouldOverrideUrlLoading( 98 int render_frame_id, 99 const base::string16& url, 100 bool* ignore_navigation) { 101 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 102 *ignore_navigation = false; 103 AwContentsClientBridgeBase* client = 104 AwContentsClientBridgeBase::FromID(process_id_, render_frame_id); 105 if (client) { 106 *ignore_navigation = client->ShouldOverrideUrlLoading(url); 107 } else { 108 LOG(WARNING) << "Failed to find the associated render view host for url: " 109 << url; 110 } 111 } 112 113 void AwContentsMessageFilter::OnSubFrameCreated(int parent_render_frame_id, 114 int child_render_frame_id) { 115 AwContentsIoThreadClient::SubFrameCreated( 116 process_id_, parent_render_frame_id, child_render_frame_id); 117 } 118 119 class AwAccessTokenStore : public content::AccessTokenStore { 120 public: 121 AwAccessTokenStore() { } 122 123 // content::AccessTokenStore implementation 124 virtual void LoadAccessTokens( 125 const LoadAccessTokensCallbackType& request) OVERRIDE { 126 AccessTokenStore::AccessTokenSet access_token_set; 127 // AccessTokenSet and net::URLRequestContextGetter not used on Android, 128 // but Run needs to be called to finish the geolocation setup. 129 request.Run(access_token_set, NULL); 130 } 131 virtual void SaveAccessToken(const GURL& server_url, 132 const base::string16& access_token) OVERRIDE { } 133 134 private: 135 virtual ~AwAccessTokenStore() { } 136 137 DISALLOW_COPY_AND_ASSIGN(AwAccessTokenStore); 138 }; 139 140 void CancelProtectedMediaIdentifierPermissionRequests( 141 int render_process_id, 142 int render_view_id, 143 const GURL& origin) { 144 AwBrowserPermissionRequestDelegate* delegate = 145 AwBrowserPermissionRequestDelegate::FromID(render_process_id, 146 render_view_id); 147 if (delegate) 148 delegate->CancelProtectedMediaIdentifierPermissionRequests(origin); 149 } 150 151 void CancelGeolocationPermissionRequests( 152 int render_process_id, 153 int render_view_id, 154 const GURL& origin) { 155 AwBrowserPermissionRequestDelegate* delegate = 156 AwBrowserPermissionRequestDelegate::FromID(render_process_id, 157 render_view_id); 158 if (delegate) 159 delegate->CancelGeolocationPermissionRequests(origin); 160 } 161 162 } // namespace 163 164 std::string AwContentBrowserClient::GetAcceptLangsImpl() { 165 // Start with the currnet locale. 166 std::string langs = l10n_util::GetDefaultLocale(); 167 168 // If we're not en-US, add in en-US which will be 169 // used with a lower q-value. 170 if (StringToLowerASCII(langs) != "en-us") { 171 langs += ",en-US"; 172 } 173 return langs; 174 } 175 176 AwBrowserContext* AwContentBrowserClient::GetAwBrowserContext() { 177 return AwBrowserContext::GetDefault(); 178 } 179 180 AwContentBrowserClient::AwContentBrowserClient( 181 JniDependencyFactory* native_factory) 182 : native_factory_(native_factory) { 183 base::FilePath user_data_dir; 184 if (!PathService::Get(base::DIR_ANDROID_APP_DATA, &user_data_dir)) { 185 NOTREACHED() << "Failed to get app data directory for Android WebView"; 186 } 187 browser_context_.reset( 188 new AwBrowserContext(user_data_dir, native_factory_)); 189 } 190 191 AwContentBrowserClient::~AwContentBrowserClient() { 192 } 193 194 void AwContentBrowserClient::AddCertificate(net::CertificateMimeType cert_type, 195 const void* cert_data, 196 size_t cert_size, 197 int render_process_id, 198 int render_frame_id) { 199 if (cert_size > 0) 200 net::android::StoreCertificate(cert_type, cert_data, cert_size); 201 } 202 203 content::BrowserMainParts* AwContentBrowserClient::CreateBrowserMainParts( 204 const content::MainFunctionParams& parameters) { 205 return new AwBrowserMainParts(browser_context_.get()); 206 } 207 208 content::WebContentsViewDelegate* 209 AwContentBrowserClient::GetWebContentsViewDelegate( 210 content::WebContents* web_contents) { 211 return native_factory_->CreateViewDelegate(web_contents); 212 } 213 214 void AwContentBrowserClient::RenderProcessWillLaunch( 215 content::RenderProcessHost* host) { 216 // If WebView becomes multi-process capable, this may be insecure. 217 // More benefit can be derived from the ChildProcessSecurotyPolicy by 218 // deferring the GrantScheme calls until we know that a given child process 219 // really does need that priviledge. Check here to ensure we rethink this 220 // when the time comes. See crbug.com/156062. 221 CHECK(content::RenderProcessHost::run_renderer_in_process()); 222 223 // Grant content: and file: scheme to the whole process, since we impose 224 // per-view access checks. 225 content::ChildProcessSecurityPolicy::GetInstance()->GrantScheme( 226 host->GetID(), android_webview::kContentScheme); 227 content::ChildProcessSecurityPolicy::GetInstance()->GrantScheme( 228 host->GetID(), url::kFileScheme); 229 230 host->AddFilter(new AwContentsMessageFilter(host->GetID())); 231 host->AddFilter(new cdm::CdmMessageFilterAndroid()); 232 } 233 234 net::URLRequestContextGetter* AwContentBrowserClient::CreateRequestContext( 235 content::BrowserContext* browser_context, 236 content::ProtocolHandlerMap* protocol_handlers, 237 content::URLRequestInterceptorScopedVector request_interceptors) { 238 DCHECK(browser_context_.get() == browser_context); 239 return browser_context_->CreateRequestContext(protocol_handlers, 240 request_interceptors.Pass()); 241 } 242 243 net::URLRequestContextGetter* 244 AwContentBrowserClient::CreateRequestContextForStoragePartition( 245 content::BrowserContext* browser_context, 246 const base::FilePath& partition_path, 247 bool in_memory, 248 content::ProtocolHandlerMap* protocol_handlers, 249 content::URLRequestInterceptorScopedVector request_interceptors) { 250 DCHECK(browser_context_.get() == browser_context); 251 // TODO(mkosiba,kinuko): request_interceptors should be hooked up in the 252 // downstream. (crbug.com/350286) 253 return browser_context_->CreateRequestContextForStoragePartition( 254 partition_path, in_memory, protocol_handlers, 255 request_interceptors.Pass()); 256 } 257 258 std::string AwContentBrowserClient::GetCanonicalEncodingNameByAliasName( 259 const std::string& alias_name) { 260 return alias_name; 261 } 262 263 void AwContentBrowserClient::AppendExtraCommandLineSwitches( 264 base::CommandLine* command_line, 265 int child_process_id) { 266 NOTREACHED() << "Android WebView does not support multi-process yet"; 267 } 268 269 std::string AwContentBrowserClient::GetApplicationLocale() { 270 return l10n_util::GetDefaultLocale(); 271 } 272 273 std::string AwContentBrowserClient::GetAcceptLangs( 274 content::BrowserContext* context) { 275 return GetAcceptLangsImpl(); 276 } 277 278 const gfx::ImageSkia* AwContentBrowserClient::GetDefaultFavicon() { 279 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); 280 // TODO(boliu): Bundle our own default favicon? 281 return rb.GetImageSkiaNamed(IDR_DEFAULT_FAVICON); 282 } 283 284 bool AwContentBrowserClient::AllowAppCache(const GURL& manifest_url, 285 const GURL& first_party, 286 content::ResourceContext* context) { 287 // WebView doesn't have a per-site policy for locally stored data, 288 // instead AppCache can be disabled for individual WebViews. 289 return true; 290 } 291 292 293 bool AwContentBrowserClient::AllowGetCookie(const GURL& url, 294 const GURL& first_party, 295 const net::CookieList& cookie_list, 296 content::ResourceContext* context, 297 int render_process_id, 298 int render_frame_id) { 299 return AwCookieAccessPolicy::GetInstance()->AllowGetCookie(url, 300 first_party, 301 cookie_list, 302 context, 303 render_process_id, 304 render_frame_id); 305 } 306 307 bool AwContentBrowserClient::AllowSetCookie(const GURL& url, 308 const GURL& first_party, 309 const std::string& cookie_line, 310 content::ResourceContext* context, 311 int render_process_id, 312 int render_frame_id, 313 net::CookieOptions* options) { 314 return AwCookieAccessPolicy::GetInstance()->AllowSetCookie(url, 315 first_party, 316 cookie_line, 317 context, 318 render_process_id, 319 render_frame_id, 320 options); 321 } 322 323 bool AwContentBrowserClient::AllowWorkerDatabase( 324 const GURL& url, 325 const base::string16& name, 326 const base::string16& display_name, 327 unsigned long estimated_size, 328 content::ResourceContext* context, 329 const std::vector<std::pair<int, int> >& render_frames) { 330 // Android WebView does not yet support web workers. 331 return false; 332 } 333 334 bool AwContentBrowserClient::AllowWorkerFileSystem( 335 const GURL& url, 336 content::ResourceContext* context, 337 const std::vector<std::pair<int, int> >& render_frames) { 338 // Android WebView does not yet support web workers. 339 return false; 340 } 341 342 bool AwContentBrowserClient::AllowWorkerIndexedDB( 343 const GURL& url, 344 const base::string16& name, 345 content::ResourceContext* context, 346 const std::vector<std::pair<int, int> >& render_frames) { 347 // Android WebView does not yet support web workers. 348 return false; 349 } 350 351 content::QuotaPermissionContext* 352 AwContentBrowserClient::CreateQuotaPermissionContext() { 353 return new AwQuotaPermissionContext; 354 } 355 356 void AwContentBrowserClient::AllowCertificateError( 357 int render_process_id, 358 int render_frame_id, 359 int cert_error, 360 const net::SSLInfo& ssl_info, 361 const GURL& request_url, 362 ResourceType::Type resource_type, 363 bool overridable, 364 bool strict_enforcement, 365 const base::Callback<void(bool)>& callback, 366 content::CertificateRequestResultType* result) { 367 AwContentsClientBridgeBase* client = 368 AwContentsClientBridgeBase::FromID(render_process_id, render_frame_id); 369 bool cancel_request = true; 370 if (client) 371 client->AllowCertificateError(cert_error, 372 ssl_info.cert.get(), 373 request_url, 374 callback, 375 &cancel_request); 376 if (cancel_request) 377 *result = content::CERTIFICATE_REQUEST_RESULT_TYPE_DENY; 378 } 379 380 void AwContentBrowserClient::SelectClientCertificate( 381 int render_process_id, 382 int render_frame_id, 383 const net::HttpNetworkSession* network_session, 384 net::SSLCertRequestInfo* cert_request_info, 385 const base::Callback<void(net::X509Certificate*)>& callback) { 386 AwContentsClientBridgeBase* client = 387 AwContentsClientBridgeBase::FromID(render_process_id, render_frame_id); 388 if (client) { 389 client->SelectClientCertificate(cert_request_info, callback); 390 } else { 391 callback.Run(NULL); 392 } 393 } 394 395 blink::WebNotificationPresenter::Permission 396 AwContentBrowserClient::CheckDesktopNotificationPermission( 397 const GURL& source_url, 398 content::ResourceContext* context, 399 int render_process_id) { 400 // Android WebView does not support notifications, so return Denied here. 401 return blink::WebNotificationPresenter::PermissionDenied; 402 } 403 404 void AwContentBrowserClient::ShowDesktopNotification( 405 const content::ShowDesktopNotificationHostMsgParams& params, 406 content::RenderFrameHost* render_frame_host, 407 content::DesktopNotificationDelegate* delegate, 408 base::Closure* cancel_callback) { 409 NOTREACHED() << "Android WebView does not support desktop notifications."; 410 } 411 412 void AwContentBrowserClient::RequestGeolocationPermission( 413 content::WebContents* web_contents, 414 int bridge_id, 415 const GURL& requesting_frame, 416 bool user_gesture, 417 base::Callback<void(bool)> result_callback, 418 base::Closure* cancel_callback) { 419 int render_process_id = web_contents->GetRenderProcessHost()->GetID(); 420 int render_view_id = web_contents->GetRenderViewHost()->GetRoutingID(); 421 AwBrowserPermissionRequestDelegate* delegate = 422 AwBrowserPermissionRequestDelegate::FromID(render_process_id, 423 render_view_id); 424 if (delegate == NULL) { 425 DVLOG(0) << "Dropping GeolocationPermission request"; 426 result_callback.Run(false); 427 return; 428 } 429 430 GURL origin = requesting_frame.GetOrigin(); 431 if (cancel_callback) { 432 *cancel_callback = base::Bind( 433 CancelGeolocationPermissionRequests, render_process_id, render_view_id, 434 origin); 435 } 436 delegate->RequestGeolocationPermission(origin, result_callback); 437 } 438 439 void AwContentBrowserClient::RequestMidiSysExPermission( 440 content::WebContents* web_contents, 441 int bridge_id, 442 const GURL& requesting_frame, 443 bool user_gesture, 444 base::Callback<void(bool)> result_callback, 445 base::Closure* cancel_callback) { 446 // TODO(toyoshim): Android WebView is not supported yet. 447 // See http://crbug.com/339767. 448 result_callback.Run(false); 449 } 450 451 void AwContentBrowserClient::RequestProtectedMediaIdentifierPermission( 452 content::WebContents* web_contents, 453 const GURL& origin, 454 base::Callback<void(bool)> result_callback, 455 base::Closure* cancel_callback) { 456 int render_process_id = web_contents->GetRenderProcessHost()->GetID(); 457 int render_view_id = web_contents->GetRenderViewHost()->GetRoutingID(); 458 AwBrowserPermissionRequestDelegate* delegate = 459 AwBrowserPermissionRequestDelegate::FromID(render_process_id, 460 render_view_id); 461 if (delegate == NULL) { 462 DVLOG(0) << "Dropping ProtectedMediaIdentifierPermission request"; 463 result_callback.Run(false); 464 return; 465 } 466 467 if (cancel_callback) { 468 *cancel_callback = base::Bind( 469 CancelProtectedMediaIdentifierPermissionRequests, 470 render_process_id, render_view_id, origin); 471 } 472 delegate->RequestProtectedMediaIdentifierPermission(origin, result_callback); 473 } 474 475 bool AwContentBrowserClient::CanCreateWindow( 476 const GURL& opener_url, 477 const GURL& opener_top_level_frame_url, 478 const GURL& source_origin, 479 WindowContainerType container_type, 480 const GURL& target_url, 481 const content::Referrer& referrer, 482 WindowOpenDisposition disposition, 483 const blink::WebWindowFeatures& features, 484 bool user_gesture, 485 bool opener_suppressed, 486 content::ResourceContext* context, 487 int render_process_id, 488 int opener_id, 489 bool* no_javascript_access) { 490 // We unconditionally allow popup windows at this stage and will give 491 // the embedder the opporunity to handle displaying of the popup in 492 // WebContentsDelegate::AddContents (via the 493 // AwContentsClient.onCreateWindow callback). 494 // Note that if the embedder has blocked support for creating popup 495 // windows through AwSettings, then we won't get to this point as 496 // the popup creation will have been blocked at the WebKit level. 497 if (no_javascript_access) { 498 *no_javascript_access = false; 499 } 500 return true; 501 } 502 503 std::string AwContentBrowserClient::GetWorkerProcessTitle(const GURL& url, 504 content::ResourceContext* context) { 505 NOTREACHED() << "Android WebView does not yet support web workers."; 506 return std::string(); 507 } 508 509 510 void AwContentBrowserClient::ResourceDispatcherHostCreated() { 511 AwResourceDispatcherHostDelegate::ResourceDispatcherHostCreated(); 512 } 513 514 net::NetLog* AwContentBrowserClient::GetNetLog() { 515 // TODO(boliu): Implement AwNetLog. 516 return NULL; 517 } 518 519 content::AccessTokenStore* AwContentBrowserClient::CreateAccessTokenStore() { 520 return new AwAccessTokenStore(); 521 } 522 523 bool AwContentBrowserClient::IsFastShutdownPossible() { 524 NOTREACHED() << "Android WebView is single process, so IsFastShutdownPossible" 525 << " should never be called"; 526 return false; 527 } 528 529 void AwContentBrowserClient::UpdateInspectorSetting( 530 content::RenderViewHost* rvh, 531 const std::string& key, 532 const std::string& value) { 533 // TODO(boliu): Implement persisting inspector settings. 534 NOTIMPLEMENTED(); 535 } 536 537 void AwContentBrowserClient::ClearCache(content::RenderViewHost* rvh) { 538 RemoveHttpDiskCache(rvh->GetProcess()->GetBrowserContext(), 539 rvh->GetProcess()->GetID()); 540 } 541 542 void AwContentBrowserClient::ClearCookies(content::RenderViewHost* rvh) { 543 // TODO(boliu): Implement. 544 NOTIMPLEMENTED(); 545 } 546 547 base::FilePath AwContentBrowserClient::GetDefaultDownloadDirectory() { 548 // Android WebView does not currently use the Chromium downloads system. 549 // Download requests are cancelled immedately when recognized; see 550 // AwResourceDispatcherHost::CreateResourceHandlerForDownload. However the 551 // download system still tries to start up and calls this before recognizing 552 // the request has been cancelled. 553 return base::FilePath(); 554 } 555 556 std::string AwContentBrowserClient::GetDefaultDownloadName() { 557 NOTREACHED() << "Android WebView does not use chromium downloads"; 558 return std::string(); 559 } 560 561 void AwContentBrowserClient::DidCreatePpapiPlugin( 562 content::BrowserPpapiHost* browser_host) { 563 NOTREACHED() << "Android WebView does not support plugins"; 564 } 565 566 bool AwContentBrowserClient::AllowPepperSocketAPI( 567 content::BrowserContext* browser_context, 568 const GURL& url, 569 bool private_api, 570 const content::SocketPermissionRequest* params) { 571 NOTREACHED() << "Android WebView does not support plugins"; 572 return false; 573 } 574 575 void AwContentBrowserClient::OverrideWebkitPrefs(content::RenderViewHost* rvh, 576 const GURL& url, 577 WebPreferences* web_prefs) { 578 if (!preferences_populater_.get()) { 579 preferences_populater_ = make_scoped_ptr(native_factory_-> 580 CreateWebPreferencesPopulater()); 581 } 582 preferences_populater_->PopulateFor( 583 content::WebContents::FromRenderViewHost(rvh), web_prefs); 584 } 585 586 #if defined(VIDEO_HOLE) 587 content::ExternalVideoSurfaceContainer* 588 AwContentBrowserClient::OverrideCreateExternalVideoSurfaceContainer( 589 content::WebContents* web_contents) { 590 return native_factory_->CreateExternalVideoSurfaceContainer(web_contents); 591 } 592 #endif 593 594 } // namespace android_webview 595