Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / android_webview / native / cookie_manager.cc
1 // Copyright (c) 2011 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/native/cookie_manager.h"
6
7 #include "android_webview/browser/aw_browser_context.h"
8 #include "android_webview/browser/aw_cookie_access_policy.h"
9 #include "android_webview/browser/net/init_native_callback.h"
10 #include "android_webview/browser/scoped_allow_wait_for_legacy_web_view_api.h"
11 #include "android_webview/native/aw_browser_dependency_factory.h"
12 #include "base/android/jni_string.h"
13 #include "base/android/path_utils.h"
14 #include "base/bind.h"
15 #include "base/bind_helpers.h"
16 #include "base/files/file_path.h"
17 #include "base/files/file_util.h"
18 #include "base/lazy_instance.h"
19 #include "base/message_loop/message_loop.h"
20 #include "base/message_loop/message_loop_proxy.h"
21 #include "base/path_service.h"
22 #include "base/synchronization/lock.h"
23 #include "base/synchronization/waitable_event.h"
24 #include "base/threading/sequenced_worker_pool.h"
25 #include "base/threading/thread.h"
26 #include "base/threading/thread_restrictions.h"
27 #include "content/public/browser/browser_context.h"
28 #include "content/public/browser/browser_thread.h"
29 #include "content/public/browser/cookie_crypto_delegate.h"
30 #include "content/public/browser/cookie_store_factory.h"
31 #include "jni/AwCookieManager_jni.h"
32 #include "net/cookies/cookie_monster.h"
33 #include "net/cookies/cookie_options.h"
34 #include "net/url_request/url_request_context.h"
35 #include "url/url_constants.h"
36
37 using base::FilePath;
38 using base::WaitableEvent;
39 using base::android::ConvertJavaStringToUTF8;
40 using base::android::ConvertJavaStringToUTF16;
41 using base::android::ScopedJavaGlobalRef;
42 using content::BrowserThread;
43 using net::CookieList;
44 using net::CookieMonster;
45
46 // In the future, we may instead want to inject an explicit CookieStore
47 // dependency into this object during process initialization to avoid
48 // depending on the URLRequestContext.
49 // See issue http://crbug.com/157683
50
51 // On the CookieManager methods without a callback and methods with a callback
52 // when that callback is null can be called from any thread, including threads
53 // without a message loop. Methods with a non-null callback must be called on
54 // a thread with a running message loop.
55
56 namespace android_webview {
57
58 namespace {
59
60 typedef base::Callback<void(bool)> BoolCallback;
61 typedef base::Callback<void(int)> IntCallback;
62
63 // Holds a Java BooleanCookieCallback, knows how to invoke it and turn it
64 // into a base callback.
65 class BoolCookieCallbackHolder {
66  public:
67   BoolCookieCallbackHolder(JNIEnv* env, jobject callback) {
68     callback_.Reset(env, callback);
69   }
70
71   void Invoke(bool result) {
72     if (!callback_.is_null()) {
73       JNIEnv* env = base::android::AttachCurrentThread();
74       Java_AwCookieManager_invokeBooleanCookieCallback(
75           env, callback_.obj(), result);
76     }
77   }
78
79   static BoolCallback ConvertToCallback(
80       scoped_ptr<BoolCookieCallbackHolder> me) {
81     return base::Bind(&BoolCookieCallbackHolder::Invoke,
82                       base::Owned(me.release()));
83   }
84
85  private:
86   ScopedJavaGlobalRef<jobject> callback_;
87   DISALLOW_COPY_AND_ASSIGN(BoolCookieCallbackHolder);
88 };
89
90 // Construct a closure which signals a waitable event if and when the closure
91 // is called the waitable event must still exist.
92 static base::Closure SignalEventClosure(WaitableEvent* completion) {
93   return base::Bind(&WaitableEvent::Signal, base::Unretained(completion));
94 }
95
96 static void DiscardBool(const base::Closure& f, bool b) {
97   f.Run();
98 }
99
100 static BoolCallback BoolCallbackAdapter(const base::Closure& f) {
101   return base::Bind(&DiscardBool, f);
102 }
103
104 static void DiscardInt(const base::Closure& f, int i) {
105   f.Run();
106 }
107
108 static IntCallback IntCallbackAdapter(const base::Closure& f) {
109   return base::Bind(&DiscardInt, f);
110 }
111
112 // Are cookies allowed for file:// URLs by default?
113 const bool kDefaultFileSchemeAllowed = false;
114
115 void ImportLegacyCookieStore(const FilePath& cookie_store_path) {
116   // We use the old cookie store to create the new cookie store only if the
117   // new cookie store does not exist.
118   if (base::PathExists(cookie_store_path))
119     return;
120
121   // WebViewClassic gets the database path from Context and appends a
122   // hardcoded name. See:
123   // https://android.googlesource.com/platform/frameworks/base/+/bf6f6f9d/core/java/android/webkit/JniUtil.java
124   // https://android.googlesource.com/platform/external/webkit/+/7151e/
125   //     Source/WebKit/android/WebCoreSupport/WebCookieJar.cpp
126   FilePath old_cookie_store_path;
127   base::android::GetDatabaseDirectory(&old_cookie_store_path);
128   old_cookie_store_path = old_cookie_store_path.Append(
129       FILE_PATH_LITERAL("webviewCookiesChromium.db"));
130   if (base::PathExists(old_cookie_store_path) &&
131       !base::Move(old_cookie_store_path, cookie_store_path)) {
132     LOG(WARNING) << "Failed to move old cookie store path from "
133                  << old_cookie_store_path.AsUTF8Unsafe() << " to "
134                  << cookie_store_path.AsUTF8Unsafe();
135   }
136 }
137
138 void GetUserDataDir(FilePath* user_data_dir) {
139   if (!PathService::Get(base::DIR_ANDROID_APP_DATA, user_data_dir)) {
140     NOTREACHED() << "Failed to get app data directory for Android WebView";
141   }
142 }
143
144 class CookieManager {
145  public:
146   static CookieManager* GetInstance();
147
148   scoped_refptr<net::CookieStore> GetCookieStore();
149
150   void SetShouldAcceptCookies(bool accept);
151   bool GetShouldAcceptCookies();
152   void SetCookie(const GURL& host,
153                  const std::string& cookie_value,
154                  scoped_ptr<BoolCookieCallbackHolder> callback);
155   void SetCookieSync(const GURL& host,
156                  const std::string& cookie_value);
157   std::string GetCookie(const GURL& host);
158   void RemoveSessionCookies(scoped_ptr<BoolCookieCallbackHolder> callback);
159   void RemoveAllCookies(scoped_ptr<BoolCookieCallbackHolder> callback);
160   void RemoveAllCookiesSync();
161   void RemoveSessionCookiesSync();
162   void RemoveExpiredCookies();
163   void FlushCookieStore();
164   bool HasCookies();
165   bool AllowFileSchemeCookies();
166   void SetAcceptFileSchemeCookies(bool accept);
167
168  private:
169   friend struct base::DefaultLazyInstanceTraits<CookieManager>;
170
171   CookieManager();
172   ~CookieManager();
173
174   void ExecCookieTaskSync(const base::Callback<void(BoolCallback)>& task);
175   void ExecCookieTaskSync(const base::Callback<void(IntCallback)>& task);
176   void ExecCookieTaskSync(const base::Callback<void(base::Closure)>& task);
177   void ExecCookieTask(const base::Closure& task);
178
179   void SetCookieHelper(
180       const GURL& host,
181       const std::string& value,
182       BoolCallback callback);
183
184   void GetCookieValueAsyncHelper(const GURL& host,
185                                  std::string* result,
186                                  base::Closure complete);
187   void GetCookieValueCompleted(base::Closure complete,
188                                std::string* result,
189                                const std::string& value);
190
191   void RemoveSessionCookiesHelper(BoolCallback callback);
192   void RemoveAllCookiesHelper(BoolCallback callback);
193   void RemoveCookiesCompleted(BoolCallback callback, int num_deleted);
194
195   void FlushCookieStoreAsyncHelper(base::Closure complete);
196
197   void HasCookiesAsyncHelper(bool* result, base::Closure complete);
198   void HasCookiesCompleted(base::Closure complete,
199                            bool* result,
200                            const CookieList& cookies);
201
202   void CreateCookieMonster(
203     const FilePath& user_data_dir,
204     const scoped_refptr<base::SequencedTaskRunner>& client_task_runner,
205     const scoped_refptr<base::SequencedTaskRunner>& background_task_runner);
206   void EnsureCookieMonsterExistsLocked();
207   bool AllowFileSchemeCookiesLocked();
208   void SetAcceptFileSchemeCookiesLocked(bool accept);
209
210   scoped_refptr<net::CookieMonster> cookie_monster_;
211   scoped_refptr<base::MessageLoopProxy> cookie_monster_proxy_;
212   base::Lock cookie_monster_lock_;
213
214   scoped_ptr<base::Thread> cookie_monster_client_thread_;
215   scoped_ptr<base::Thread> cookie_monster_backend_thread_;
216
217   DISALLOW_COPY_AND_ASSIGN(CookieManager);
218 };
219
220 base::LazyInstance<CookieManager>::Leaky g_lazy_instance;
221
222 // static
223 CookieManager* CookieManager::GetInstance() {
224   return g_lazy_instance.Pointer();
225 }
226
227 CookieManager::CookieManager() {
228 }
229
230 CookieManager::~CookieManager() {
231 }
232
233 void CookieManager::CreateCookieMonster(
234     const FilePath& user_data_dir,
235     const scoped_refptr<base::SequencedTaskRunner>& client_task_runner,
236     const scoped_refptr<base::SequencedTaskRunner>& background_task_runner) {
237   FilePath cookie_store_path =
238       user_data_dir.Append(FILE_PATH_LITERAL("Cookies"));
239
240   background_task_runner->PostTask(
241       FROM_HERE,
242       base::Bind(ImportLegacyCookieStore, cookie_store_path));
243
244   content::CookieStoreConfig cookie_config(
245       cookie_store_path,
246       content::CookieStoreConfig::RESTORED_SESSION_COOKIES,
247       NULL, NULL);
248   cookie_config.client_task_runner = client_task_runner;
249   cookie_config.background_task_runner = background_task_runner;
250   net::CookieStore* cookie_store = content::CreateCookieStore(cookie_config);
251   cookie_monster_ = cookie_store->GetCookieMonster();
252   SetAcceptFileSchemeCookiesLocked(kDefaultFileSchemeAllowed);
253 }
254
255 void CookieManager::EnsureCookieMonsterExistsLocked() {
256   cookie_monster_lock_.AssertAcquired();
257   if (cookie_monster_.get()) {
258     return;
259   }
260
261   // Create cookie monster using WebView-specific threads, as the rest of the
262   // browser has not been started yet.
263   FilePath user_data_dir;
264   GetUserDataDir(&user_data_dir);
265   cookie_monster_client_thread_.reset(
266       new base::Thread("CookieMonsterClient"));
267   cookie_monster_client_thread_->Start();
268   cookie_monster_proxy_ = cookie_monster_client_thread_->message_loop_proxy();
269   cookie_monster_backend_thread_.reset(
270       new base::Thread("CookieMonsterBackend"));
271   cookie_monster_backend_thread_->Start();
272
273   CreateCookieMonster(user_data_dir,
274                       cookie_monster_proxy_,
275                       cookie_monster_backend_thread_->message_loop_proxy());
276 }
277
278 // Executes the |task| on the |cookie_monster_proxy_| message loop and
279 // waits for it to complete before returning.
280
281 // To execute a CookieTask synchronously you must arrange for Signal to be
282 // called on the waitable event at some point. You can call the bool or int
283 // versions of ExecCookieTaskSync, these will supply the caller with a dummy
284 // callback which takes an int/bool, throws it away and calls Signal.
285 // Alternatively you can call the version which supplies a Closure in which
286 // case you must call Run on it when you want the unblock the calling code.
287
288 // Ignore a bool callback.
289 void CookieManager::ExecCookieTaskSync(
290     const base::Callback<void(BoolCallback)>& task) {
291   WaitableEvent completion(false, false);
292   ExecCookieTask(
293       base::Bind(task, BoolCallbackAdapter(SignalEventClosure(&completion))));
294   ScopedAllowWaitForLegacyWebViewApi wait;
295   completion.Wait();
296 }
297
298 // Ignore an int callback.
299 void CookieManager::ExecCookieTaskSync(
300     const base::Callback<void(IntCallback)>& task) {
301   WaitableEvent completion(false, false);
302   ExecCookieTask(
303       base::Bind(task, IntCallbackAdapter(SignalEventClosure(&completion))));
304   ScopedAllowWaitForLegacyWebViewApi wait;
305   completion.Wait();
306 }
307
308 // Call the supplied closure when you want to signal that the blocked code can
309 // continue.
310 void CookieManager::ExecCookieTaskSync(
311     const base::Callback<void(base::Closure)>& task) {
312   WaitableEvent completion(false, false);
313   ExecCookieTask(base::Bind(task, SignalEventClosure(&completion)));
314   ScopedAllowWaitForLegacyWebViewApi wait;
315   completion.Wait();
316 }
317
318 // Executes the |task| on the |cookie_monster_proxy_| message loop.
319 void CookieManager::ExecCookieTask(const base::Closure& task) {
320   base::AutoLock lock(cookie_monster_lock_);
321   EnsureCookieMonsterExistsLocked();
322   cookie_monster_proxy_->PostTask(FROM_HERE, task);
323 }
324
325 scoped_refptr<net::CookieStore> CookieManager::GetCookieStore() {
326   base::AutoLock lock(cookie_monster_lock_);
327   EnsureCookieMonsterExistsLocked();
328   return cookie_monster_;
329 }
330
331 void CookieManager::SetShouldAcceptCookies(bool accept) {
332   AwCookieAccessPolicy::GetInstance()->SetShouldAcceptCookies(accept);
333 }
334
335 bool CookieManager::GetShouldAcceptCookies() {
336   return AwCookieAccessPolicy::GetInstance()->GetShouldAcceptCookies();
337 }
338
339 void CookieManager::SetCookie(
340     const GURL& host,
341     const std::string& cookie_value,
342     scoped_ptr<BoolCookieCallbackHolder> callback_holder) {
343   BoolCallback callback =
344       BoolCookieCallbackHolder::ConvertToCallback(callback_holder.Pass());
345   ExecCookieTask(base::Bind(&CookieManager::SetCookieHelper,
346                             base::Unretained(this),
347                             host,
348                             cookie_value,
349                             callback));
350 }
351
352 void CookieManager::SetCookieSync(const GURL& host,
353                               const std::string& cookie_value) {
354   ExecCookieTaskSync(base::Bind(&CookieManager::SetCookieHelper,
355                             base::Unretained(this),
356                             host,
357                             cookie_value));
358 }
359
360 void CookieManager::SetCookieHelper(
361     const GURL& host,
362     const std::string& value,
363     const BoolCallback callback) {
364   net::CookieOptions options;
365   options.set_include_httponly();
366
367   cookie_monster_->SetCookieWithOptionsAsync(
368       host, value, options, callback);
369 }
370
371 std::string CookieManager::GetCookie(const GURL& host) {
372   std::string cookie_value;
373   ExecCookieTaskSync(base::Bind(&CookieManager::GetCookieValueAsyncHelper,
374                             base::Unretained(this),
375                             host,
376                             &cookie_value));
377   return cookie_value;
378 }
379
380 void CookieManager::GetCookieValueAsyncHelper(
381     const GURL& host,
382     std::string* result,
383     base::Closure complete) {
384   net::CookieOptions options;
385   options.set_include_httponly();
386
387   cookie_monster_->GetCookiesWithOptionsAsync(
388       host,
389       options,
390       base::Bind(&CookieManager::GetCookieValueCompleted,
391                  base::Unretained(this),
392                  complete,
393                  result));
394 }
395
396 void CookieManager::GetCookieValueCompleted(base::Closure complete,
397                                             std::string* result,
398                                             const std::string& value) {
399   *result = value;
400   complete.Run();
401 }
402
403 void CookieManager::RemoveSessionCookies(
404     scoped_ptr<BoolCookieCallbackHolder> callback_holder) {
405   BoolCallback callback =
406       BoolCookieCallbackHolder::ConvertToCallback(callback_holder.Pass());
407   ExecCookieTask(base::Bind(&CookieManager::RemoveSessionCookiesHelper,
408                             base::Unretained(this),
409                             callback));
410 }
411
412 void CookieManager::RemoveSessionCookiesSync() {
413   ExecCookieTaskSync(base::Bind(&CookieManager::RemoveSessionCookiesHelper,
414                             base::Unretained(this)));
415 }
416
417 void CookieManager::RemoveSessionCookiesHelper(
418     BoolCallback callback) {
419   cookie_monster_->DeleteSessionCookiesAsync(
420       base::Bind(&CookieManager::RemoveCookiesCompleted,
421                  base::Unretained(this),
422                  callback));
423 }
424
425 void CookieManager::RemoveCookiesCompleted(
426     BoolCallback callback,
427     int num_deleted) {
428   callback.Run(num_deleted > 0);
429 }
430
431 void CookieManager::RemoveAllCookies(
432     scoped_ptr<BoolCookieCallbackHolder> callback_holder) {
433   BoolCallback callback =
434       BoolCookieCallbackHolder::ConvertToCallback(callback_holder.Pass());
435   ExecCookieTask(base::Bind(&CookieManager::RemoveAllCookiesHelper,
436                             base::Unretained(this),
437                             callback));
438 }
439
440 void CookieManager::RemoveAllCookiesSync() {
441   ExecCookieTaskSync(base::Bind(&CookieManager::RemoveAllCookiesHelper,
442                             base::Unretained(this)));
443 }
444
445 void CookieManager::RemoveAllCookiesHelper(
446     const BoolCallback callback) {
447   cookie_monster_->DeleteAllAsync(
448       base::Bind(&CookieManager::RemoveCookiesCompleted,
449                  base::Unretained(this),
450                  callback));
451 }
452
453 void CookieManager::RemoveExpiredCookies() {
454   // HasCookies will call GetAllCookiesAsync, which in turn will force a GC.
455   HasCookies();
456 }
457
458 void CookieManager::FlushCookieStore() {
459   ExecCookieTaskSync(base::Bind(&CookieManager::FlushCookieStoreAsyncHelper,
460                             base::Unretained(this)));
461 }
462
463 void CookieManager::FlushCookieStoreAsyncHelper(
464     base::Closure complete) {
465   cookie_monster_->FlushStore(complete);
466 }
467
468 bool CookieManager::HasCookies() {
469   bool has_cookies;
470   ExecCookieTaskSync(base::Bind(&CookieManager::HasCookiesAsyncHelper,
471                             base::Unretained(this),
472                             &has_cookies));
473   return has_cookies;
474 }
475
476 // TODO(kristianm): Simplify this, copying the entire list around
477 // should not be needed.
478 void CookieManager::HasCookiesAsyncHelper(bool* result,
479                                           base::Closure complete) {
480   cookie_monster_->GetAllCookiesAsync(
481       base::Bind(&CookieManager::HasCookiesCompleted,
482                  base::Unretained(this),
483                  complete,
484                  result));
485 }
486
487 void CookieManager::HasCookiesCompleted(base::Closure complete,
488                                         bool* result,
489                                         const CookieList& cookies) {
490   *result = cookies.size() != 0;
491   complete.Run();
492 }
493
494 bool CookieManager::AllowFileSchemeCookies() {
495   base::AutoLock lock(cookie_monster_lock_);
496   EnsureCookieMonsterExistsLocked();
497   return AllowFileSchemeCookiesLocked();
498 }
499
500 bool CookieManager::AllowFileSchemeCookiesLocked() {
501   return cookie_monster_->IsCookieableScheme(url::kFileScheme);
502 }
503
504 void CookieManager::SetAcceptFileSchemeCookies(bool accept) {
505   base::AutoLock lock(cookie_monster_lock_);
506   EnsureCookieMonsterExistsLocked();
507   SetAcceptFileSchemeCookiesLocked(accept);
508 }
509
510 void CookieManager::SetAcceptFileSchemeCookiesLocked(bool accept) {
511   // The docs on CookieManager base class state the API must not be called after
512   // creating a CookieManager instance (which contradicts its own internal
513   // implementation) but this code does rely on the essence of that comment, as
514   // the monster will DCHECK here if it has already been lazy initialized (i.e.
515   // if cookies have been read or written from the store). If that turns out to
516   // be a problemin future, it looks like it maybe possible to relax the DCHECK.
517   cookie_monster_->SetEnableFileScheme(accept);
518 }
519
520 }  // namespace
521
522 static void SetShouldAcceptCookies(JNIEnv* env, jobject obj, jboolean accept) {
523   CookieManager::GetInstance()->SetShouldAcceptCookies(accept);
524 }
525
526 static jboolean GetShouldAcceptCookies(JNIEnv* env, jobject obj) {
527   return CookieManager::GetInstance()->GetShouldAcceptCookies();
528 }
529
530 static void SetCookie(JNIEnv* env,
531                       jobject obj,
532                       jstring url,
533                       jstring value,
534                       jobject java_callback) {
535   GURL host(ConvertJavaStringToUTF16(env, url));
536   std::string cookie_value(ConvertJavaStringToUTF8(env, value));
537   scoped_ptr<BoolCookieCallbackHolder> callback(
538       new BoolCookieCallbackHolder(env, java_callback));
539   CookieManager::GetInstance()->SetCookie(host, cookie_value, callback.Pass());
540 }
541
542 static void SetCookieSync(JNIEnv* env,
543                       jobject obj,
544                       jstring url,
545                       jstring value) {
546   GURL host(ConvertJavaStringToUTF16(env, url));
547   std::string cookie_value(ConvertJavaStringToUTF8(env, value));
548
549   CookieManager::GetInstance()->SetCookieSync(host, cookie_value);
550 }
551
552 static jstring GetCookie(JNIEnv* env, jobject obj, jstring url) {
553   GURL host(ConvertJavaStringToUTF16(env, url));
554
555   return base::android::ConvertUTF8ToJavaString(
556       env,
557       CookieManager::GetInstance()->GetCookie(host)).Release();
558 }
559
560 static void RemoveSessionCookies(JNIEnv* env,
561                                 jobject obj,
562                                 jobject java_callback) {
563   scoped_ptr<BoolCookieCallbackHolder> callback(
564       new BoolCookieCallbackHolder(env, java_callback));
565   CookieManager::GetInstance()->RemoveSessionCookies(callback.Pass());
566 }
567
568 static void RemoveSessionCookiesSync(JNIEnv* env, jobject obj) {
569     CookieManager::GetInstance()->RemoveSessionCookiesSync();
570 }
571
572 static void RemoveAllCookies(JNIEnv* env, jobject obj, jobject java_callback) {
573   scoped_ptr<BoolCookieCallbackHolder> callback(
574       new BoolCookieCallbackHolder(env, java_callback));
575   CookieManager::GetInstance()->RemoveAllCookies(callback.Pass());
576 }
577
578 static void RemoveAllCookiesSync(JNIEnv* env, jobject obj) {
579   CookieManager::GetInstance()->RemoveAllCookiesSync();
580 }
581
582 static void RemoveExpiredCookies(JNIEnv* env, jobject obj) {
583   CookieManager::GetInstance()->RemoveExpiredCookies();
584 }
585
586 static void FlushCookieStore(JNIEnv* env, jobject obj) {
587   CookieManager::GetInstance()->FlushCookieStore();
588 }
589
590 static jboolean HasCookies(JNIEnv* env, jobject obj) {
591   return CookieManager::GetInstance()->HasCookies();
592 }
593
594 static jboolean AllowFileSchemeCookies(JNIEnv* env, jobject obj) {
595   return CookieManager::GetInstance()->AllowFileSchemeCookies();
596 }
597
598 static void SetAcceptFileSchemeCookies(JNIEnv* env, jobject obj,
599                                        jboolean accept) {
600   return CookieManager::GetInstance()->SetAcceptFileSchemeCookies(accept);
601 }
602
603 scoped_refptr<net::CookieStore> CreateCookieStore(
604     AwBrowserContext* browser_context) {
605   return CookieManager::GetInstance()->GetCookieStore();
606 }
607
608 bool RegisterCookieManager(JNIEnv* env) {
609   return RegisterNativesImpl(env);
610 }
611
612 }  // android_webview namespace