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.
5 #include "android_webview/native/cookie_manager.h"
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"
38 using base::android::ConvertJavaStringToUTF8
;
39 using base::android::ConvertJavaStringToUTF16
;
40 using content::BrowserThread
;
41 using net::CookieList
;
42 using net::CookieMonster
;
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
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
54 namespace android_webview
{
58 // Are cookies allowed for file:// URLs by default?
59 const bool kDefaultFileSchemeAllowed
= false;
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
))
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();
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";
92 static CookieManager
* GetInstance();
94 scoped_refptr
<net::CookieStore
> CreateBrowserThreadCookieStore(
95 AwBrowserContext
* browser_context
);
97 void SetAcceptCookie(bool accept
);
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();
106 bool AllowFileSchemeCookies();
107 void SetAcceptFileSchemeCookies(bool accept
);
110 friend struct base::DefaultLazyInstanceTraits
<CookieManager
>;
115 typedef base::Callback
<void(base::WaitableEvent
*)> CookieTask
;
116 void ExecCookieTask(const CookieTask
& task
);
118 void SetCookieAsyncHelper(
120 const std::string
& value
,
121 base::WaitableEvent
* completion
);
122 void SetCookieCompleted(base::WaitableEvent
* completion
, bool success
);
124 void GetCookieValueAsyncHelper(
127 base::WaitableEvent
* completion
);
128 void GetCookieValueCompleted(base::WaitableEvent
* completion
,
130 const std::string
& value
);
132 void RemoveSessionCookieAsyncHelper(base::WaitableEvent
* completion
);
133 void RemoveAllCookieAsyncHelper(base::WaitableEvent
* completion
);
134 void RemoveCookiesCompleted(base::WaitableEvent
* completion
, int num_deleted
);
136 void FlushCookieStoreAsyncHelper(base::WaitableEvent
* completion
);
138 void HasCookiesAsyncHelper(bool* result
,
139 base::WaitableEvent
* completion
);
140 void HasCookiesCompleted(base::WaitableEvent
* completion
,
142 const CookieList
& cookies
);
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
);
152 scoped_refptr
<net::CookieMonster
> cookie_monster_
;
153 scoped_refptr
<base::MessageLoopProxy
> cookie_monster_proxy_
;
154 base::Lock cookie_monster_lock_
;
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_
;
161 DISALLOW_COPY_AND_ASSIGN(CookieManager
);
164 base::LazyInstance
<CookieManager
>::Leaky g_lazy_instance
;
167 CookieManager
* CookieManager::GetInstance() {
168 return g_lazy_instance
.Pointer();
171 CookieManager::CookieManager() {
174 CookieManager::~CookieManager() {
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"));
184 background_task_runner
->PostTask(
186 base::Bind(ImportLegacyCookieStore
, cookie_store_path
));
188 content::CookieStoreConfig
cookie_config(
190 content::CookieStoreConfig::RESTORED_SESSION_COOKIES
,
192 cookie_config
.client_task_runner
= client_task_runner
;
193 cookie_config
.background_task_runner
= background_task_runner
;
194 net::CookieStore
* cookie_store
= content::CreateCookieStore(cookie_config
);
195 cookie_monster_
= cookie_store
->GetCookieMonster();
196 SetAcceptFileSchemeCookiesLocked(kDefaultFileSchemeAllowed
);
199 void CookieManager::EnsureCookieMonsterExistsLocked() {
200 cookie_monster_lock_
.AssertAcquired();
201 if (cookie_monster_
.get()) {
205 // Create cookie monster using WebView-specific threads, as the rest of the
206 // browser has not been started yet.
207 FilePath user_data_dir
;
208 GetUserDataDir(&user_data_dir
);
209 cookie_monster_client_thread_
.reset(
210 new base::Thread("CookieMonsterClient"));
211 cookie_monster_client_thread_
->Start();
212 cookie_monster_proxy_
= cookie_monster_client_thread_
->message_loop_proxy();
213 cookie_monster_backend_thread_
.reset(
214 new base::Thread("CookieMonsterBackend"));
215 cookie_monster_backend_thread_
->Start();
217 CreateCookieMonster(user_data_dir
,
218 cookie_monster_proxy_
,
219 cookie_monster_backend_thread_
->message_loop_proxy());
222 // Executes the |task| on the |cookie_monster_proxy_| message loop.
223 void CookieManager::ExecCookieTask(const CookieTask
& task
) {
224 base::WaitableEvent
completion(false, false);
225 base::AutoLock
lock(cookie_monster_lock_
);
227 EnsureCookieMonsterExistsLocked();
229 cookie_monster_proxy_
->PostTask(FROM_HERE
, base::Bind(task
, &completion
));
231 // We always wait for the posted task to complete, even when it doesn't return
232 // a value, because previous versions of the CookieManager API were
233 // synchronous in most/all cases and the caller may be relying on this.
234 ScopedAllowWaitForLegacyWebViewApi wait
;
238 scoped_refptr
<net::CookieStore
> CookieManager::CreateBrowserThreadCookieStore(
239 AwBrowserContext
* browser_context
) {
240 base::AutoLock
lock(cookie_monster_lock_
);
242 if (cookie_monster_client_thread_
) {
243 // We created a cookie monster already on its own threads; we'll just keep
244 // using it rather than creating one on the normal Chromium threads.
245 // CookieMonster is threadsafe, so this is fine.
246 return cookie_monster_
;
249 // Go ahead and create the cookie monster using the normal Chromium threads.
250 DCHECK(!cookie_monster_
.get());
251 DCHECK(BrowserThread::IsMessageLoopValid(BrowserThread::IO
));
253 FilePath user_data_dir
;
254 GetUserDataDir(&user_data_dir
);
255 DCHECK(browser_context
->GetPath() == user_data_dir
);
257 cookie_monster_proxy_
=
258 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO
);
259 scoped_refptr
<base::SequencedTaskRunner
> background_task_runner
=
260 BrowserThread::GetBlockingPool()->GetSequencedTaskRunner(
261 BrowserThread::GetBlockingPool()->GetSequenceToken());
262 CreateCookieMonster(user_data_dir
,
263 cookie_monster_proxy_
,
264 background_task_runner
);
265 return cookie_monster_
;
268 void CookieManager::SetAcceptCookie(bool accept
) {
269 AwCookieAccessPolicy::GetInstance()->SetGlobalAllowAccess(accept
);
272 bool CookieManager::AcceptCookie() {
273 return AwCookieAccessPolicy::GetInstance()->GetGlobalAllowAccess();
276 void CookieManager::SetCookie(const GURL
& host
,
277 const std::string
& cookie_value
) {
278 ExecCookieTask(base::Bind(&CookieManager::SetCookieAsyncHelper
,
279 base::Unretained(this),
284 void CookieManager::SetCookieAsyncHelper(
286 const std::string
& value
,
287 base::WaitableEvent
* completion
) {
288 net::CookieOptions options
;
289 options
.set_include_httponly();
291 cookie_monster_
->SetCookieWithOptionsAsync(
292 host
, value
, options
,
293 base::Bind(&CookieManager::SetCookieCompleted
,
294 base::Unretained(this),
298 void CookieManager::SetCookieCompleted(base::WaitableEvent
* completion
,
300 // The CookieManager API does not return a value for SetCookie,
301 // so we don't need to propagate the |success| value back to the caller.
302 completion
->Signal();
305 std::string
CookieManager::GetCookie(const GURL
& host
) {
306 std::string cookie_value
;
307 ExecCookieTask(base::Bind(&CookieManager::GetCookieValueAsyncHelper
,
308 base::Unretained(this),
315 void CookieManager::GetCookieValueAsyncHelper(
318 base::WaitableEvent
* completion
) {
319 net::CookieOptions options
;
320 options
.set_include_httponly();
322 cookie_monster_
->GetCookiesWithOptionsAsync(
325 base::Bind(&CookieManager::GetCookieValueCompleted
,
326 base::Unretained(this),
331 void CookieManager::GetCookieValueCompleted(base::WaitableEvent
* completion
,
333 const std::string
& value
) {
335 completion
->Signal();
338 void CookieManager::RemoveSessionCookie() {
339 ExecCookieTask(base::Bind(&CookieManager::RemoveSessionCookieAsyncHelper
,
340 base::Unretained(this)));
343 void CookieManager::RemoveSessionCookieAsyncHelper(
344 base::WaitableEvent
* completion
) {
345 cookie_monster_
->DeleteSessionCookiesAsync(
346 base::Bind(&CookieManager::RemoveCookiesCompleted
,
347 base::Unretained(this),
351 void CookieManager::RemoveCookiesCompleted(base::WaitableEvent
* completion
,
353 // The CookieManager API does not return a value for removeSessionCookie or
354 // removeAllCookie, so we don't need to propagate the |num_deleted| value back
356 completion
->Signal();
359 void CookieManager::RemoveAllCookie() {
360 ExecCookieTask(base::Bind(&CookieManager::RemoveAllCookieAsyncHelper
,
361 base::Unretained(this)));
364 void CookieManager::RemoveAllCookieAsyncHelper(
365 base::WaitableEvent
* completion
) {
366 cookie_monster_
->DeleteAllAsync(
367 base::Bind(&CookieManager::RemoveCookiesCompleted
,
368 base::Unretained(this),
372 void CookieManager::RemoveExpiredCookie() {
373 // HasCookies will call GetAllCookiesAsync, which in turn will force a GC.
377 void CookieManager::FlushCookieStoreAsyncHelper(
378 base::WaitableEvent
* completion
) {
379 cookie_monster_
->FlushStore(base::Bind(&base::WaitableEvent::Signal
,
380 base::Unretained(completion
)));
383 void CookieManager::FlushCookieStore() {
384 ExecCookieTask(base::Bind(&CookieManager::FlushCookieStoreAsyncHelper
,
385 base::Unretained(this)));
388 bool CookieManager::HasCookies() {
390 ExecCookieTask(base::Bind(&CookieManager::HasCookiesAsyncHelper
,
391 base::Unretained(this),
396 // TODO(kristianm): Simplify this, copying the entire list around
397 // should not be needed.
398 void CookieManager::HasCookiesAsyncHelper(bool* result
,
399 base::WaitableEvent
* completion
) {
400 cookie_monster_
->GetAllCookiesAsync(
401 base::Bind(&CookieManager::HasCookiesCompleted
,
402 base::Unretained(this),
407 void CookieManager::HasCookiesCompleted(base::WaitableEvent
* completion
,
409 const CookieList
& cookies
) {
410 *result
= cookies
.size() != 0;
411 completion
->Signal();
414 bool CookieManager::AllowFileSchemeCookies() {
415 base::AutoLock
lock(cookie_monster_lock_
);
416 EnsureCookieMonsterExistsLocked();
417 return AllowFileSchemeCookiesLocked();
420 bool CookieManager::AllowFileSchemeCookiesLocked() {
421 return cookie_monster_
->IsCookieableScheme(content::kFileScheme
);
424 void CookieManager::SetAcceptFileSchemeCookies(bool accept
) {
425 base::AutoLock
lock(cookie_monster_lock_
);
426 EnsureCookieMonsterExistsLocked();
427 SetAcceptFileSchemeCookiesLocked(accept
);
430 void CookieManager::SetAcceptFileSchemeCookiesLocked(bool accept
) {
431 // The docs on CookieManager base class state the API must not be called after
432 // creating a CookieManager instance (which contradicts its own internal
433 // implementation) but this code does rely on the essence of that comment, as
434 // the monster will DCHECK here if it has already been lazy initialized (i.e.
435 // if cookies have been read or written from the store). If that turns out to
436 // be a problemin future, it looks like it maybe possible to relax the DCHECK.
437 cookie_monster_
->SetEnableFileScheme(accept
);
442 static void SetAcceptCookie(JNIEnv
* env
, jobject obj
, jboolean accept
) {
443 CookieManager::GetInstance()->SetAcceptCookie(accept
);
446 static jboolean
AcceptCookie(JNIEnv
* env
, jobject obj
) {
447 return CookieManager::GetInstance()->AcceptCookie();
450 static void SetCookie(JNIEnv
* env
, jobject obj
, jstring url
, jstring value
) {
451 GURL
host(ConvertJavaStringToUTF16(env
, url
));
452 std::string
cookie_value(ConvertJavaStringToUTF8(env
, value
));
454 CookieManager::GetInstance()->SetCookie(host
, cookie_value
);
457 static jstring
GetCookie(JNIEnv
* env
, jobject obj
, jstring url
) {
458 GURL
host(ConvertJavaStringToUTF16(env
, url
));
460 return base::android::ConvertUTF8ToJavaString(
462 CookieManager::GetInstance()->GetCookie(host
)).Release();
465 static void RemoveSessionCookie(JNIEnv
* env
, jobject obj
) {
466 CookieManager::GetInstance()->RemoveSessionCookie();
469 static void RemoveAllCookie(JNIEnv
* env
, jobject obj
) {
470 CookieManager::GetInstance()->RemoveAllCookie();
473 static void RemoveExpiredCookie(JNIEnv
* env
, jobject obj
) {
474 CookieManager::GetInstance()->RemoveExpiredCookie();
477 static void FlushCookieStore(JNIEnv
* env
, jobject obj
) {
478 CookieManager::GetInstance()->FlushCookieStore();
481 static jboolean
HasCookies(JNIEnv
* env
, jobject obj
) {
482 return CookieManager::GetInstance()->HasCookies();
485 static jboolean
AllowFileSchemeCookies(JNIEnv
* env
, jobject obj
) {
486 return CookieManager::GetInstance()->AllowFileSchemeCookies();
489 static void SetAcceptFileSchemeCookies(JNIEnv
* env
, jobject obj
,
491 return CookieManager::GetInstance()->SetAcceptFileSchemeCookies(accept
);
494 scoped_refptr
<net::CookieStore
> CreateCookieStore(
495 AwBrowserContext
* browser_context
) {
496 return CookieManager::GetInstance()->CreateBrowserThreadCookieStore(
500 bool RegisterCookieManager(JNIEnv
* env
) {
501 return RegisterNativesImpl(env
);
504 } // android_webview namespace