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