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 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
60 private:
61 virtual ~AwContentsMessageFilter();
62
63 int process_id_;
64
65 DISALLOW_COPY_AND_ASSIGN(AwContentsMessageFilter);
66 };
67
AwContentsMessageFilter(int process_id)68 AwContentsMessageFilter::AwContentsMessageFilter(int process_id)
69 : process_id_(process_id) {
70 }
71
~AwContentsMessageFilter()72 AwContentsMessageFilter::~AwContentsMessageFilter() {
73 }
74
OverrideThreadForMessage(const IPC::Message & message,BrowserThread::ID * thread)75 void AwContentsMessageFilter::OverrideThreadForMessage(
76 const IPC::Message& message, BrowserThread::ID* thread) {
77 if (message.type() == AwViewHostMsg_ShouldOverrideUrlLoading::ID) {
78 *thread = BrowserThread::UI;
79 }
80 }
81
OnMessageReceived(const IPC::Message & message,bool * message_was_ok)82 bool 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
OnShouldOverrideUrlLoading(int routing_id,const base::string16 & url,bool * ignore_navigation)93 void 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
109 class AwAccessTokenStore : public content::AccessTokenStore {
110 public:
AwAccessTokenStore()111 AwAccessTokenStore() { }
112
113 // content::AccessTokenStore implementation
LoadAccessTokens(const LoadAccessTokensCallbackType & request)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 }
SaveAccessToken(const GURL & server_url,const string16 & access_token)121 virtual void SaveAccessToken(const GURL& server_url,
122 const string16& access_token) OVERRIDE { }
123
124 private:
~AwAccessTokenStore()125 virtual ~AwAccessTokenStore() { }
126
127 DISALLOW_COPY_AND_ASSIGN(AwAccessTokenStore);
128 };
129
130 }
131
GetAcceptLangsImpl()132 std::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
GetAwBrowserContext()144 AwBrowserContext* AwContentBrowserClient::GetAwBrowserContext() {
145 return AwBrowserContext::GetDefault();
146 }
147
AwContentBrowserClient(JniDependencyFactory * native_factory)148 AwContentBrowserClient::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
~AwContentBrowserClient()159 AwContentBrowserClient::~AwContentBrowserClient() {
160 }
161
AddCertificate(net::URLRequest * request,net::CertificateMimeType cert_type,const void * cert_data,size_t cert_size,int render_process_id,int render_view_id)162 void 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
CreateBrowserMainParts(const content::MainFunctionParams & parameters)172 content::BrowserMainParts* AwContentBrowserClient::CreateBrowserMainParts(
173 const content::MainFunctionParams& parameters) {
174 return new AwBrowserMainParts(browser_context_.get());
175 }
176
177 content::WebContentsViewDelegate*
GetWebContentsViewDelegate(content::WebContents * web_contents)178 AwContentBrowserClient::GetWebContentsViewDelegate(
179 content::WebContents* web_contents) {
180 return native_factory_->CreateViewDelegate(web_contents);
181 }
182
RenderProcessHostCreated(content::RenderProcessHost * host)183 void 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
202 net::URLRequestContextGetter*
CreateRequestContext(content::BrowserContext * browser_context,content::ProtocolHandlerMap * protocol_handlers)203 AwContentBrowserClient::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
210 net::URLRequestContextGetter*
CreateRequestContextForStoragePartition(content::BrowserContext * browser_context,const base::FilePath & partition_path,bool in_memory,content::ProtocolHandlerMap * protocol_handlers)211 AwContentBrowserClient::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
GetCanonicalEncodingNameByAliasName(const std::string & alias_name)221 std::string AwContentBrowserClient::GetCanonicalEncodingNameByAliasName(
222 const std::string& alias_name) {
223 return alias_name;
224 }
225
AppendExtraCommandLineSwitches(CommandLine * command_line,int child_process_id)226 void AwContentBrowserClient::AppendExtraCommandLineSwitches(
227 CommandLine* command_line,
228 int child_process_id) {
229 NOTREACHED() << "Android WebView does not support multi-process yet";
230 }
231
GetApplicationLocale()232 std::string AwContentBrowserClient::GetApplicationLocale() {
233 return l10n_util::GetDefaultLocale();
234 }
235
GetAcceptLangs(content::BrowserContext * context)236 std::string AwContentBrowserClient::GetAcceptLangs(
237 content::BrowserContext* context) {
238 return GetAcceptLangsImpl();
239 }
240
GetDefaultFavicon()241 gfx::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
AllowAppCache(const GURL & manifest_url,const GURL & first_party,content::ResourceContext * context)247 bool 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
AllowGetCookie(const GURL & url,const GURL & first_party,const net::CookieList & cookie_list,content::ResourceContext * context,int render_process_id,int render_view_id)256 bool 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
AllowSetCookie(const GURL & url,const GURL & first_party,const std::string & cookie_line,content::ResourceContext * context,int render_process_id,int render_view_id,net::CookieOptions * options)270 bool 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
AllowWorkerDatabase(const GURL & url,const string16 & name,const string16 & display_name,unsigned long estimated_size,content::ResourceContext * context,const std::vector<std::pair<int,int>> & render_views)286 bool 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
AllowWorkerFileSystem(const GURL & url,content::ResourceContext * context,const std::vector<std::pair<int,int>> & render_views)297 bool 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
AllowWorkerIndexedDB(const GURL & url,const string16 & name,content::ResourceContext * context,const std::vector<std::pair<int,int>> & render_views)305 bool 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
314 content::QuotaPermissionContext*
CreateQuotaPermissionContext()315 AwContentBrowserClient::CreateQuotaPermissionContext() {
316 return new AwQuotaPermissionContext;
317 }
318
AllowCertificateError(int render_process_id,int render_view_id,int cert_error,const net::SSLInfo & ssl_info,const GURL & request_url,ResourceType::Type resource_type,bool overridable,bool strict_enforcement,const base::Callback<void (bool)> & callback,content::CertificateRequestResultType * result)319 void 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
SelectClientCertificate(int render_process_id,int render_view_id,const net::HttpNetworkSession * network_session,net::SSLCertRequestInfo * cert_request_info,const base::Callback<void (net::X509Certificate *)> & callback)344 void 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
356 blink::WebNotificationPresenter::Permission
CheckDesktopNotificationPermission(const GURL & source_url,content::ResourceContext * context,int render_process_id)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
ShowDesktopNotification(const content::ShowDesktopNotificationHostMsgParams & params,int render_process_id,int render_view_id,bool worker)365 void 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
CancelDesktopNotification(int render_process_id,int render_view_id,int notification_id)373 void 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
CanCreateWindow(const GURL & opener_url,const GURL & opener_top_level_frame_url,const GURL & source_origin,WindowContainerType container_type,const GURL & target_url,const content::Referrer & referrer,WindowOpenDisposition disposition,const blink::WebWindowFeatures & features,bool user_gesture,bool opener_suppressed,content::ResourceContext * context,int render_process_id,bool is_guest,int opener_id,bool * no_javascript_access)380 bool 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
GetWorkerProcessTitle(const GURL & url,content::ResourceContext * context)409 std::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
ResourceDispatcherHostCreated()416 void AwContentBrowserClient::ResourceDispatcherHostCreated() {
417 AwResourceDispatcherHostDelegate::ResourceDispatcherHostCreated();
418 }
419
GetNetLog()420 net::NetLog* AwContentBrowserClient::GetNetLog() {
421 // TODO(boliu): Implement AwNetLog.
422 return NULL;
423 }
424
CreateAccessTokenStore()425 content::AccessTokenStore* AwContentBrowserClient::CreateAccessTokenStore() {
426 return new AwAccessTokenStore();
427 }
428
IsFastShutdownPossible()429 bool AwContentBrowserClient::IsFastShutdownPossible() {
430 NOTREACHED() << "Android WebView is single process, so IsFastShutdownPossible"
431 << " should never be called";
432 return false;
433 }
434
UpdateInspectorSetting(content::RenderViewHost * rvh,const std::string & key,const std::string & value)435 void 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
ClearCache(content::RenderViewHost * rvh)443 void AwContentBrowserClient::ClearCache(content::RenderViewHost* rvh) {
444 RemoveHttpDiskCache(rvh->GetProcess()->GetBrowserContext(),
445 rvh->GetProcess()->GetID());
446 }
447
ClearCookies(content::RenderViewHost * rvh)448 void AwContentBrowserClient::ClearCookies(content::RenderViewHost* rvh) {
449 // TODO(boliu): Implement.
450 NOTIMPLEMENTED();
451 }
452
GetDefaultDownloadDirectory()453 base::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
GetDefaultDownloadName()462 std::string AwContentBrowserClient::GetDefaultDownloadName() {
463 NOTREACHED() << "Android WebView does not use chromium downloads";
464 return std::string();
465 }
466
DidCreatePpapiPlugin(content::BrowserPpapiHost * browser_host)467 void AwContentBrowserClient::DidCreatePpapiPlugin(
468 content::BrowserPpapiHost* browser_host) {
469 NOTREACHED() << "Android WebView does not support plugins";
470 }
471
AllowPepperSocketAPI(content::BrowserContext * browser_context,const GURL & url,bool private_api,const content::SocketPermissionRequest * params)472 bool 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
OverrideWebkitPrefs(content::RenderViewHost * rvh,const GURL & url,WebPreferences * web_prefs)481 void 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