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