• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/file_util.h"
17 #include "base/files/file_path.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 "content/public/common/url_constants.h"
32 #include "jni/AwCookieManager_jni.h"
33 #include "net/cookies/cookie_monster.h"
34 #include "net/cookies/cookie_options.h"
35 #include "net/url_request/url_request_context.h"
36 
37 using base::FilePath;
38 using base::android::ConvertJavaStringToUTF8;
39 using base::android::ConvertJavaStringToUTF16;
40 using content::BrowserThread;
41 using net::CookieList;
42 using net::CookieMonster;
43 
44 // In the future, we may instead want to inject an explicit CookieStore
45 // dependency into this object during process initialization to avoid
46 // depending on the URLRequestContext.
47 // See issue http://crbug.com/157683
48 
49 // All functions on the CookieManager can be called from any thread, including
50 // threads without a message loop. BrowserThread::IO is used to call methods
51 // on CookieMonster that needs to be called, and called back, on a chrome
52 // thread.
53 
54 namespace android_webview {
55 
56 namespace {
57 
58 // Are cookies allowed for file:// URLs by default?
59 const bool kDefaultFileSchemeAllowed = false;
60 
ImportLegacyCookieStore(const FilePath & cookie_store_path)61 void ImportLegacyCookieStore(const FilePath& cookie_store_path) {
62   // We use the old cookie store to create the new cookie store only if the
63   // new cookie store does not exist.
64   if (base::PathExists(cookie_store_path))
65     return;
66 
67   // WebViewClassic gets the database path from Context and appends a
68   // hardcoded name. See:
69   // https://android.googlesource.com/platform/frameworks/base/+/bf6f6f9d/core/java/android/webkit/JniUtil.java
70   // https://android.googlesource.com/platform/external/webkit/+/7151e/
71   //     Source/WebKit/android/WebCoreSupport/WebCookieJar.cpp
72   FilePath old_cookie_store_path;
73   base::android::GetDatabaseDirectory(&old_cookie_store_path);
74   old_cookie_store_path = old_cookie_store_path.Append(
75       FILE_PATH_LITERAL("webviewCookiesChromium.db"));
76   if (base::PathExists(old_cookie_store_path) &&
77       !base::Move(old_cookie_store_path, cookie_store_path)) {
78     LOG(WARNING) << "Failed to move old cookie store path from "
79                  << old_cookie_store_path.AsUTF8Unsafe() << " to "
80                  << cookie_store_path.AsUTF8Unsafe();
81   }
82 }
83 
GetUserDataDir(FilePath * user_data_dir)84 void GetUserDataDir(FilePath* user_data_dir) {
85   if (!PathService::Get(base::DIR_ANDROID_APP_DATA, user_data_dir)) {
86     NOTREACHED() << "Failed to get app data directory for Android WebView";
87   }
88 }
89 
90 class CookieManager {
91  public:
92   static CookieManager* GetInstance();
93 
94   scoped_refptr<net::CookieStore> CreateBrowserThreadCookieStore(
95       AwBrowserContext* browser_context);
96 
97   void SetAcceptCookie(bool accept);
98   bool AcceptCookie();
99   void SetCookie(const GURL& host, const std::string& cookie_value);
100   std::string GetCookie(const GURL& host);
101   void RemoveSessionCookie();
102   void RemoveAllCookie();
103   void RemoveExpiredCookie();
104   void FlushCookieStore();
105   bool HasCookies();
106   bool AllowFileSchemeCookies();
107   void SetAcceptFileSchemeCookies(bool accept);
108 
109  private:
110   friend struct base::DefaultLazyInstanceTraits<CookieManager>;
111 
112   CookieManager();
113   ~CookieManager();
114 
115   typedef base::Callback<void(base::WaitableEvent*)> CookieTask;
116   void ExecCookieTask(const CookieTask& task);
117 
118   void SetCookieAsyncHelper(
119       const GURL& host,
120       const std::string& value,
121       base::WaitableEvent* completion);
122   void SetCookieCompleted(base::WaitableEvent* completion, bool success);
123 
124   void GetCookieValueAsyncHelper(
125       const GURL& host,
126       std::string* result,
127       base::WaitableEvent* completion);
128   void GetCookieValueCompleted(base::WaitableEvent* completion,
129                                std::string* result,
130                                const std::string& value);
131 
132   void RemoveSessionCookieAsyncHelper(base::WaitableEvent* completion);
133   void RemoveAllCookieAsyncHelper(base::WaitableEvent* completion);
134   void RemoveCookiesCompleted(base::WaitableEvent* completion, int num_deleted);
135 
136   void FlushCookieStoreAsyncHelper(base::WaitableEvent* completion);
137 
138   void HasCookiesAsyncHelper(bool* result,
139                              base::WaitableEvent* completion);
140   void HasCookiesCompleted(base::WaitableEvent* completion,
141                            bool* result,
142                            const CookieList& cookies);
143 
144   void CreateCookieMonster(
145     const FilePath& user_data_dir,
146     const scoped_refptr<base::SequencedTaskRunner>& client_task_runner,
147     const scoped_refptr<base::SequencedTaskRunner>& background_task_runner);
148   void EnsureCookieMonsterExistsLocked();
149   bool AllowFileSchemeCookiesLocked();
150   void SetAcceptFileSchemeCookiesLocked(bool accept);
151 
152   scoped_refptr<net::CookieMonster> cookie_monster_;
153   scoped_refptr<base::MessageLoopProxy> cookie_monster_proxy_;
154   base::Lock cookie_monster_lock_;
155 
156   // Both these threads are normally NULL. They only exist if CookieManager was
157   // accessed before Chromium was started.
158   scoped_ptr<base::Thread> cookie_monster_client_thread_;
159   scoped_ptr<base::Thread> cookie_monster_backend_thread_;
160 
161   DISALLOW_COPY_AND_ASSIGN(CookieManager);
162 };
163 
164 base::LazyInstance<CookieManager>::Leaky g_lazy_instance;
165 
166 // static
GetInstance()167 CookieManager* CookieManager::GetInstance() {
168   return g_lazy_instance.Pointer();
169 }
170 
CookieManager()171 CookieManager::CookieManager() {
172 }
173 
~CookieManager()174 CookieManager::~CookieManager() {
175 }
176 
CreateCookieMonster(const FilePath & user_data_dir,const scoped_refptr<base::SequencedTaskRunner> & client_task_runner,const scoped_refptr<base::SequencedTaskRunner> & background_task_runner)177 void CookieManager::CreateCookieMonster(
178     const FilePath& user_data_dir,
179     const scoped_refptr<base::SequencedTaskRunner>& client_task_runner,
180     const scoped_refptr<base::SequencedTaskRunner>& background_task_runner) {
181   FilePath cookie_store_path =
182       user_data_dir.Append(FILE_PATH_LITERAL("Cookies"));
183 
184   background_task_runner->PostTask(
185       FROM_HERE,
186       base::Bind(ImportLegacyCookieStore, cookie_store_path));
187 
188   net::CookieStore* cookie_store = content::CreatePersistentCookieStore(
189     cookie_store_path,
190     true,
191     NULL,
192     NULL,
193     client_task_runner,
194     background_task_runner,
195     scoped_ptr<content::CookieCryptoDelegate>());
196   cookie_monster_ = cookie_store->GetCookieMonster();
197   cookie_monster_->SetPersistSessionCookies(true);
198   SetAcceptFileSchemeCookiesLocked(kDefaultFileSchemeAllowed);
199 }
200 
EnsureCookieMonsterExistsLocked()201 void CookieManager::EnsureCookieMonsterExistsLocked() {
202   cookie_monster_lock_.AssertAcquired();
203   if (cookie_monster_.get()) {
204     return;
205   }
206 
207   // Create cookie monster using WebView-specific threads, as the rest of the
208   // browser has not been started yet.
209   FilePath user_data_dir;
210   GetUserDataDir(&user_data_dir);
211   cookie_monster_client_thread_.reset(
212       new base::Thread("CookieMonsterClient"));
213   cookie_monster_client_thread_->Start();
214   cookie_monster_proxy_ = cookie_monster_client_thread_->message_loop_proxy();
215   cookie_monster_backend_thread_.reset(
216       new base::Thread("CookieMonsterBackend"));
217   cookie_monster_backend_thread_->Start();
218 
219   CreateCookieMonster(user_data_dir,
220                       cookie_monster_proxy_,
221                       cookie_monster_backend_thread_->message_loop_proxy());
222 }
223 
224 // Executes the |task| on the |cookie_monster_proxy_| message loop.
ExecCookieTask(const CookieTask & task)225 void CookieManager::ExecCookieTask(const CookieTask& task) {
226   base::WaitableEvent completion(false, false);
227   base::AutoLock lock(cookie_monster_lock_);
228 
229   EnsureCookieMonsterExistsLocked();
230 
231   cookie_monster_proxy_->PostTask(FROM_HERE, base::Bind(task, &completion));
232 
233   // We always wait for the posted task to complete, even when it doesn't return
234   // a value, because previous versions of the CookieManager API were
235   // synchronous in most/all cases and the caller may be relying on this.
236   ScopedAllowWaitForLegacyWebViewApi wait;
237   completion.Wait();
238 }
239 
CreateBrowserThreadCookieStore(AwBrowserContext * browser_context)240 scoped_refptr<net::CookieStore> CookieManager::CreateBrowserThreadCookieStore(
241     AwBrowserContext* browser_context) {
242   base::AutoLock lock(cookie_monster_lock_);
243 
244   if (cookie_monster_client_thread_) {
245     // We created a cookie monster already on its own threads; we'll just keep
246     // using it rather than creating one on the normal Chromium threads.
247     // CookieMonster is threadsafe, so this is fine.
248     return cookie_monster_;
249   }
250 
251   // Go ahead and create the cookie monster using the normal Chromium threads.
252   DCHECK(!cookie_monster_.get());
253   DCHECK(BrowserThread::IsMessageLoopValid(BrowserThread::IO));
254 
255   FilePath user_data_dir;
256   GetUserDataDir(&user_data_dir);
257   DCHECK(browser_context->GetPath() == user_data_dir);
258 
259   cookie_monster_proxy_ =
260       BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
261   scoped_refptr<base::SequencedTaskRunner> background_task_runner =
262       BrowserThread::GetBlockingPool()->GetSequencedTaskRunner(
263           BrowserThread::GetBlockingPool()->GetSequenceToken());
264   CreateCookieMonster(user_data_dir,
265                       cookie_monster_proxy_,
266                       background_task_runner);
267   return cookie_monster_;
268 }
269 
SetAcceptCookie(bool accept)270 void CookieManager::SetAcceptCookie(bool accept) {
271   AwCookieAccessPolicy::GetInstance()->SetGlobalAllowAccess(accept);
272 }
273 
AcceptCookie()274 bool CookieManager::AcceptCookie() {
275   return AwCookieAccessPolicy::GetInstance()->GetGlobalAllowAccess();
276 }
277 
SetCookie(const GURL & host,const std::string & cookie_value)278 void CookieManager::SetCookie(const GURL& host,
279                               const std::string& cookie_value) {
280   ExecCookieTask(base::Bind(&CookieManager::SetCookieAsyncHelper,
281                             base::Unretained(this),
282                             host,
283                             cookie_value));
284 }
285 
SetCookieAsyncHelper(const GURL & host,const std::string & value,base::WaitableEvent * completion)286 void CookieManager::SetCookieAsyncHelper(
287     const GURL& host,
288     const std::string& value,
289     base::WaitableEvent* completion) {
290   net::CookieOptions options;
291   options.set_include_httponly();
292 
293   cookie_monster_->SetCookieWithOptionsAsync(
294       host, value, options,
295       base::Bind(&CookieManager::SetCookieCompleted,
296                  base::Unretained(this),
297                  completion));
298 }
299 
SetCookieCompleted(base::WaitableEvent * completion,bool success)300 void CookieManager::SetCookieCompleted(base::WaitableEvent* completion,
301                                        bool success) {
302   // The CookieManager API does not return a value for SetCookie,
303   // so we don't need to propagate the |success| value back to the caller.
304   completion->Signal();
305 }
306 
GetCookie(const GURL & host)307 std::string CookieManager::GetCookie(const GURL& host) {
308   std::string cookie_value;
309   ExecCookieTask(base::Bind(&CookieManager::GetCookieValueAsyncHelper,
310                             base::Unretained(this),
311                             host,
312                             &cookie_value));
313 
314   return cookie_value;
315 }
316 
GetCookieValueAsyncHelper(const GURL & host,std::string * result,base::WaitableEvent * completion)317 void CookieManager::GetCookieValueAsyncHelper(
318     const GURL& host,
319     std::string* result,
320     base::WaitableEvent* completion) {
321   net::CookieOptions options;
322   options.set_include_httponly();
323 
324   cookie_monster_->GetCookiesWithOptionsAsync(
325       host,
326       options,
327       base::Bind(&CookieManager::GetCookieValueCompleted,
328                  base::Unretained(this),
329                  completion,
330                  result));
331 }
332 
GetCookieValueCompleted(base::WaitableEvent * completion,std::string * result,const std::string & value)333 void CookieManager::GetCookieValueCompleted(base::WaitableEvent* completion,
334                                             std::string* result,
335                                             const std::string& value) {
336   *result = value;
337   completion->Signal();
338 }
339 
RemoveSessionCookie()340 void CookieManager::RemoveSessionCookie() {
341   ExecCookieTask(base::Bind(&CookieManager::RemoveSessionCookieAsyncHelper,
342                             base::Unretained(this)));
343 }
344 
RemoveSessionCookieAsyncHelper(base::WaitableEvent * completion)345 void CookieManager::RemoveSessionCookieAsyncHelper(
346     base::WaitableEvent* completion) {
347   cookie_monster_->DeleteSessionCookiesAsync(
348       base::Bind(&CookieManager::RemoveCookiesCompleted,
349                  base::Unretained(this),
350                  completion));
351 }
352 
RemoveCookiesCompleted(base::WaitableEvent * completion,int num_deleted)353 void CookieManager::RemoveCookiesCompleted(base::WaitableEvent* completion,
354                                            int num_deleted) {
355   // The CookieManager API does not return a value for removeSessionCookie or
356   // removeAllCookie, so we don't need to propagate the |num_deleted| value back
357   // to the caller.
358   completion->Signal();
359 }
360 
RemoveAllCookie()361 void CookieManager::RemoveAllCookie() {
362   ExecCookieTask(base::Bind(&CookieManager::RemoveAllCookieAsyncHelper,
363                             base::Unretained(this)));
364 }
365 
RemoveAllCookieAsyncHelper(base::WaitableEvent * completion)366 void CookieManager::RemoveAllCookieAsyncHelper(
367     base::WaitableEvent* completion) {
368   cookie_monster_->DeleteAllAsync(
369       base::Bind(&CookieManager::RemoveCookiesCompleted,
370                  base::Unretained(this),
371                  completion));
372 }
373 
RemoveExpiredCookie()374 void CookieManager::RemoveExpiredCookie() {
375   // HasCookies will call GetAllCookiesAsync, which in turn will force a GC.
376   HasCookies();
377 }
378 
FlushCookieStoreAsyncHelper(base::WaitableEvent * completion)379 void CookieManager::FlushCookieStoreAsyncHelper(
380     base::WaitableEvent* completion) {
381   cookie_monster_->FlushStore(base::Bind(&base::WaitableEvent::Signal,
382                                          base::Unretained(completion)));
383 }
384 
FlushCookieStore()385 void CookieManager::FlushCookieStore() {
386   ExecCookieTask(base::Bind(&CookieManager::FlushCookieStoreAsyncHelper,
387                             base::Unretained(this)));
388 }
389 
HasCookies()390 bool CookieManager::HasCookies() {
391   bool has_cookies;
392   ExecCookieTask(base::Bind(&CookieManager::HasCookiesAsyncHelper,
393                             base::Unretained(this),
394                             &has_cookies));
395   return has_cookies;
396 }
397 
398 // TODO(kristianm): Simplify this, copying the entire list around
399 // should not be needed.
HasCookiesAsyncHelper(bool * result,base::WaitableEvent * completion)400 void CookieManager::HasCookiesAsyncHelper(bool* result,
401                                   base::WaitableEvent* completion) {
402   cookie_monster_->GetAllCookiesAsync(
403       base::Bind(&CookieManager::HasCookiesCompleted,
404                  base::Unretained(this),
405                  completion,
406                  result));
407 }
408 
HasCookiesCompleted(base::WaitableEvent * completion,bool * result,const CookieList & cookies)409 void CookieManager::HasCookiesCompleted(base::WaitableEvent* completion,
410                                         bool* result,
411                                         const CookieList& cookies) {
412   *result = cookies.size() != 0;
413   completion->Signal();
414 }
415 
AllowFileSchemeCookies()416 bool CookieManager::AllowFileSchemeCookies() {
417   base::AutoLock lock(cookie_monster_lock_);
418   EnsureCookieMonsterExistsLocked();
419   return AllowFileSchemeCookiesLocked();
420 }
421 
AllowFileSchemeCookiesLocked()422 bool CookieManager::AllowFileSchemeCookiesLocked() {
423   return cookie_monster_->IsCookieableScheme(chrome::kFileScheme);
424 }
425 
SetAcceptFileSchemeCookies(bool accept)426 void CookieManager::SetAcceptFileSchemeCookies(bool accept) {
427   base::AutoLock lock(cookie_monster_lock_);
428   EnsureCookieMonsterExistsLocked();
429   SetAcceptFileSchemeCookiesLocked(accept);
430 }
431 
SetAcceptFileSchemeCookiesLocked(bool accept)432 void CookieManager::SetAcceptFileSchemeCookiesLocked(bool accept) {
433   // The docs on CookieManager base class state the API must not be called after
434   // creating a CookieManager instance (which contradicts its own internal
435   // implementation) but this code does rely on the essence of that comment, as
436   // the monster will DCHECK here if it has already been lazy initialized (i.e.
437   // if cookies have been read or written from the store). If that turns out to
438   // be a problemin future, it looks like it maybe possible to relax the DCHECK.
439   cookie_monster_->SetEnableFileScheme(accept);
440 }
441 
442 }  // namespace
443 
SetAcceptCookie(JNIEnv * env,jobject obj,jboolean accept)444 static void SetAcceptCookie(JNIEnv* env, jobject obj, jboolean accept) {
445   CookieManager::GetInstance()->SetAcceptCookie(accept);
446 }
447 
AcceptCookie(JNIEnv * env,jobject obj)448 static jboolean AcceptCookie(JNIEnv* env, jobject obj) {
449   return CookieManager::GetInstance()->AcceptCookie();
450 }
451 
SetCookie(JNIEnv * env,jobject obj,jstring url,jstring value)452 static void SetCookie(JNIEnv* env, jobject obj, jstring url, jstring value) {
453   GURL host(ConvertJavaStringToUTF16(env, url));
454   std::string cookie_value(ConvertJavaStringToUTF8(env, value));
455 
456   CookieManager::GetInstance()->SetCookie(host, cookie_value);
457 }
458 
GetCookie(JNIEnv * env,jobject obj,jstring url)459 static jstring GetCookie(JNIEnv* env, jobject obj, jstring url) {
460   GURL host(ConvertJavaStringToUTF16(env, url));
461 
462   return base::android::ConvertUTF8ToJavaString(
463       env,
464       CookieManager::GetInstance()->GetCookie(host)).Release();
465 }
466 
RemoveSessionCookie(JNIEnv * env,jobject obj)467 static void RemoveSessionCookie(JNIEnv* env, jobject obj) {
468   CookieManager::GetInstance()->RemoveSessionCookie();
469 }
470 
RemoveAllCookie(JNIEnv * env,jobject obj)471 static void RemoveAllCookie(JNIEnv* env, jobject obj) {
472   CookieManager::GetInstance()->RemoveAllCookie();
473 }
474 
RemoveExpiredCookie(JNIEnv * env,jobject obj)475 static void RemoveExpiredCookie(JNIEnv* env, jobject obj) {
476   CookieManager::GetInstance()->RemoveExpiredCookie();
477 }
478 
FlushCookieStore(JNIEnv * env,jobject obj)479 static void FlushCookieStore(JNIEnv* env, jobject obj) {
480   CookieManager::GetInstance()->FlushCookieStore();
481 }
482 
HasCookies(JNIEnv * env,jobject obj)483 static jboolean HasCookies(JNIEnv* env, jobject obj) {
484   return CookieManager::GetInstance()->HasCookies();
485 }
486 
AllowFileSchemeCookies(JNIEnv * env,jobject obj)487 static jboolean AllowFileSchemeCookies(JNIEnv* env, jobject obj) {
488   return CookieManager::GetInstance()->AllowFileSchemeCookies();
489 }
490 
SetAcceptFileSchemeCookies(JNIEnv * env,jobject obj,jboolean accept)491 static void SetAcceptFileSchemeCookies(JNIEnv* env, jobject obj,
492                                        jboolean accept) {
493   return CookieManager::GetInstance()->SetAcceptFileSchemeCookies(accept);
494 }
495 
CreateCookieStore(AwBrowserContext * browser_context)496 scoped_refptr<net::CookieStore> CreateCookieStore(
497     AwBrowserContext* browser_context) {
498   return CookieManager::GetInstance()->CreateBrowserThreadCookieStore(
499       browser_context);
500 }
501 
RegisterCookieManager(JNIEnv * env)502 bool RegisterCookieManager(JNIEnv* env) {
503   return RegisterNativesImpl(env);
504 }
505 
506 }  // android_webview namespace
507