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