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