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 SetAcceptThirdPartyCookie(bool accept);
100 bool AcceptThirdPartyCookie();
101 void SetCookie(const GURL& host, const std::string& cookie_value);
102 std::string GetCookie(const GURL& host);
103 void RemoveSessionCookie();
104 void RemoveAllCookie();
105 void RemoveExpiredCookie();
106 void FlushCookieStore();
108 bool AllowFileSchemeCookies();
109 void SetAcceptFileSchemeCookies(bool accept);
112 friend struct base::DefaultLazyInstanceTraits<CookieManager>;
117 typedef base::Callback<void(base::WaitableEvent*)> CookieTask;
118 void ExecCookieTask(const CookieTask& task);
120 void SetCookieAsyncHelper(
122 const std::string& value,
123 base::WaitableEvent* completion);
124 void SetCookieCompleted(base::WaitableEvent* completion, bool success);
126 void GetCookieValueAsyncHelper(
129 base::WaitableEvent* completion);
130 void GetCookieValueCompleted(base::WaitableEvent* completion,
132 const std::string& value);
134 void RemoveSessionCookieAsyncHelper(base::WaitableEvent* completion);
135 void RemoveAllCookieAsyncHelper(base::WaitableEvent* completion);
136 void RemoveCookiesCompleted(base::WaitableEvent* completion, int num_deleted);
138 void FlushCookieStoreAsyncHelper(base::WaitableEvent* completion);
140 void HasCookiesAsyncHelper(bool* result,
141 base::WaitableEvent* completion);
142 void HasCookiesCompleted(base::WaitableEvent* completion,
144 const CookieList& cookies);
146 void CreateCookieMonster(
147 const FilePath& user_data_dir,
148 const scoped_refptr<base::SequencedTaskRunner>& client_task_runner,
149 const scoped_refptr<base::SequencedTaskRunner>& background_task_runner);
150 void EnsureCookieMonsterExistsLocked();
151 bool AllowFileSchemeCookiesLocked();
152 void SetAcceptFileSchemeCookiesLocked(bool accept);
154 scoped_refptr<net::CookieMonster> cookie_monster_;
155 scoped_refptr<base::MessageLoopProxy> cookie_monster_proxy_;
156 base::Lock cookie_monster_lock_;
158 // Both these threads are normally NULL. They only exist if CookieManager was
159 // accessed before Chromium was started.
160 scoped_ptr<base::Thread> cookie_monster_client_thread_;
161 scoped_ptr<base::Thread> cookie_monster_backend_thread_;
163 DISALLOW_COPY_AND_ASSIGN(CookieManager);
166 base::LazyInstance<CookieManager>::Leaky g_lazy_instance;
169 CookieManager* CookieManager::GetInstance() {
170 return g_lazy_instance.Pointer();
173 CookieManager::CookieManager() {
176 CookieManager::~CookieManager() {
179 void CookieManager::CreateCookieMonster(
180 const FilePath& user_data_dir,
181 const scoped_refptr<base::SequencedTaskRunner>& client_task_runner,
182 const scoped_refptr<base::SequencedTaskRunner>& background_task_runner) {
183 FilePath cookie_store_path =
184 user_data_dir.Append(FILE_PATH_LITERAL("Cookies"));
186 background_task_runner->PostTask(
188 base::Bind(ImportLegacyCookieStore, cookie_store_path));
190 content::CookieStoreConfig cookie_config(
192 content::CookieStoreConfig::RESTORED_SESSION_COOKIES,
194 cookie_config.client_task_runner = client_task_runner;
195 cookie_config.background_task_runner = background_task_runner;
196 net::CookieStore* cookie_store = content::CreateCookieStore(cookie_config);
197 cookie_monster_ = cookie_store->GetCookieMonster();
198 SetAcceptFileSchemeCookiesLocked(kDefaultFileSchemeAllowed);
201 void CookieManager::EnsureCookieMonsterExistsLocked() {
202 cookie_monster_lock_.AssertAcquired();
203 if (cookie_monster_.get()) {
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();
219 CreateCookieMonster(user_data_dir,
220 cookie_monster_proxy_,
221 cookie_monster_backend_thread_->message_loop_proxy());
224 // Executes the |task| on the |cookie_monster_proxy_| message loop.
225 void CookieManager::ExecCookieTask(const CookieTask& task) {
226 base::WaitableEvent completion(false, false);
227 base::AutoLock lock(cookie_monster_lock_);
229 EnsureCookieMonsterExistsLocked();
231 cookie_monster_proxy_->PostTask(FROM_HERE, base::Bind(task, &completion));
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;
240 scoped_refptr<net::CookieStore> CookieManager::CreateBrowserThreadCookieStore(
241 AwBrowserContext* browser_context) {
242 base::AutoLock lock(cookie_monster_lock_);
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_;
251 // Go ahead and create the cookie monster using the normal Chromium threads.
252 DCHECK(!cookie_monster_.get());
253 DCHECK(BrowserThread::IsMessageLoopValid(BrowserThread::IO));
255 FilePath user_data_dir;
256 GetUserDataDir(&user_data_dir);
257 DCHECK(browser_context->GetPath() == user_data_dir);
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_;
270 void CookieManager::SetAcceptCookie(bool accept) {
271 AwCookieAccessPolicy::GetInstance()->SetGlobalAllowAccess(accept);
274 bool CookieManager::AcceptCookie() {
275 return AwCookieAccessPolicy::GetInstance()->GetGlobalAllowAccess();
278 void CookieManager::SetAcceptThirdPartyCookie(bool accept) {
279 AwCookieAccessPolicy::GetInstance()->SetThirdPartyAllowAccess(accept);
282 bool CookieManager::AcceptThirdPartyCookie() {
283 return AwCookieAccessPolicy::GetInstance()->GetThirdPartyAllowAccess();
286 void CookieManager::SetCookie(const GURL& host,
287 const std::string& cookie_value) {
288 ExecCookieTask(base::Bind(&CookieManager::SetCookieAsyncHelper,
289 base::Unretained(this),
294 void CookieManager::SetCookieAsyncHelper(
296 const std::string& value,
297 base::WaitableEvent* completion) {
298 net::CookieOptions options;
299 options.set_include_httponly();
301 cookie_monster_->SetCookieWithOptionsAsync(
302 host, value, options,
303 base::Bind(&CookieManager::SetCookieCompleted,
304 base::Unretained(this),
308 void CookieManager::SetCookieCompleted(base::WaitableEvent* completion,
310 // The CookieManager API does not return a value for SetCookie,
311 // so we don't need to propagate the |success| value back to the caller.
312 completion->Signal();
315 std::string CookieManager::GetCookie(const GURL& host) {
316 std::string cookie_value;
317 ExecCookieTask(base::Bind(&CookieManager::GetCookieValueAsyncHelper,
318 base::Unretained(this),
325 void CookieManager::GetCookieValueAsyncHelper(
328 base::WaitableEvent* completion) {
329 net::CookieOptions options;
330 options.set_include_httponly();
332 cookie_monster_->GetCookiesWithOptionsAsync(
335 base::Bind(&CookieManager::GetCookieValueCompleted,
336 base::Unretained(this),
341 void CookieManager::GetCookieValueCompleted(base::WaitableEvent* completion,
343 const std::string& value) {
345 completion->Signal();
348 void CookieManager::RemoveSessionCookie() {
349 ExecCookieTask(base::Bind(&CookieManager::RemoveSessionCookieAsyncHelper,
350 base::Unretained(this)));
353 void CookieManager::RemoveSessionCookieAsyncHelper(
354 base::WaitableEvent* completion) {
355 cookie_monster_->DeleteSessionCookiesAsync(
356 base::Bind(&CookieManager::RemoveCookiesCompleted,
357 base::Unretained(this),
361 void CookieManager::RemoveCookiesCompleted(base::WaitableEvent* completion,
363 // The CookieManager API does not return a value for removeSessionCookie or
364 // removeAllCookie, so we don't need to propagate the |num_deleted| value back
366 completion->Signal();
369 void CookieManager::RemoveAllCookie() {
370 ExecCookieTask(base::Bind(&CookieManager::RemoveAllCookieAsyncHelper,
371 base::Unretained(this)));
374 void CookieManager::RemoveAllCookieAsyncHelper(
375 base::WaitableEvent* completion) {
376 cookie_monster_->DeleteAllAsync(
377 base::Bind(&CookieManager::RemoveCookiesCompleted,
378 base::Unretained(this),
382 void CookieManager::RemoveExpiredCookie() {
383 // HasCookies will call GetAllCookiesAsync, which in turn will force a GC.
387 void CookieManager::FlushCookieStoreAsyncHelper(
388 base::WaitableEvent* completion) {
389 cookie_monster_->FlushStore(base::Bind(&base::WaitableEvent::Signal,
390 base::Unretained(completion)));
393 void CookieManager::FlushCookieStore() {
394 ExecCookieTask(base::Bind(&CookieManager::FlushCookieStoreAsyncHelper,
395 base::Unretained(this)));
398 bool CookieManager::HasCookies() {
400 ExecCookieTask(base::Bind(&CookieManager::HasCookiesAsyncHelper,
401 base::Unretained(this),
406 // TODO(kristianm): Simplify this, copying the entire list around
407 // should not be needed.
408 void CookieManager::HasCookiesAsyncHelper(bool* result,
409 base::WaitableEvent* completion) {
410 cookie_monster_->GetAllCookiesAsync(
411 base::Bind(&CookieManager::HasCookiesCompleted,
412 base::Unretained(this),
417 void CookieManager::HasCookiesCompleted(base::WaitableEvent* completion,
419 const CookieList& cookies) {
420 *result = cookies.size() != 0;
421 completion->Signal();
424 bool CookieManager::AllowFileSchemeCookies() {
425 base::AutoLock lock(cookie_monster_lock_);
426 EnsureCookieMonsterExistsLocked();
427 return AllowFileSchemeCookiesLocked();
430 bool CookieManager::AllowFileSchemeCookiesLocked() {
431 return cookie_monster_->IsCookieableScheme(content::kFileScheme);
434 void CookieManager::SetAcceptFileSchemeCookies(bool accept) {
435 base::AutoLock lock(cookie_monster_lock_);
436 EnsureCookieMonsterExistsLocked();
437 SetAcceptFileSchemeCookiesLocked(accept);
440 void CookieManager::SetAcceptFileSchemeCookiesLocked(bool accept) {
441 // The docs on CookieManager base class state the API must not be called after
442 // creating a CookieManager instance (which contradicts its own internal
443 // implementation) but this code does rely on the essence of that comment, as
444 // the monster will DCHECK here if it has already been lazy initialized (i.e.
445 // if cookies have been read or written from the store). If that turns out to
446 // be a problemin future, it looks like it maybe possible to relax the DCHECK.
447 cookie_monster_->SetEnableFileScheme(accept);
452 static void SetAcceptCookie(JNIEnv* env, jobject obj, jboolean accept) {
453 CookieManager::GetInstance()->SetAcceptCookie(accept);
456 static jboolean AcceptCookie(JNIEnv* env, jobject obj) {
457 return CookieManager::GetInstance()->AcceptCookie();
460 static void SetAcceptThirdPartyCookie(JNIEnv* env,
463 CookieManager::GetInstance()->SetAcceptThirdPartyCookie(accept);
466 static jboolean AcceptThirdPartyCookie(JNIEnv* env, jobject obj) {
467 return CookieManager::GetInstance()->AcceptThirdPartyCookie();
470 static void SetCookie(JNIEnv* env, jobject obj, jstring url, jstring value) {
471 GURL host(ConvertJavaStringToUTF16(env, url));
472 std::string cookie_value(ConvertJavaStringToUTF8(env, value));
474 CookieManager::GetInstance()->SetCookie(host, cookie_value);
477 static jstring GetCookie(JNIEnv* env, jobject obj, jstring url) {
478 GURL host(ConvertJavaStringToUTF16(env, url));
480 return base::android::ConvertUTF8ToJavaString(
482 CookieManager::GetInstance()->GetCookie(host)).Release();
485 static void RemoveSessionCookie(JNIEnv* env, jobject obj) {
486 CookieManager::GetInstance()->RemoveSessionCookie();
489 static void RemoveAllCookie(JNIEnv* env, jobject obj) {
490 CookieManager::GetInstance()->RemoveAllCookie();
493 static void RemoveExpiredCookie(JNIEnv* env, jobject obj) {
494 CookieManager::GetInstance()->RemoveExpiredCookie();
497 static void FlushCookieStore(JNIEnv* env, jobject obj) {
498 CookieManager::GetInstance()->FlushCookieStore();
501 static jboolean HasCookies(JNIEnv* env, jobject obj) {
502 return CookieManager::GetInstance()->HasCookies();
505 static jboolean AllowFileSchemeCookies(JNIEnv* env, jobject obj) {
506 return CookieManager::GetInstance()->AllowFileSchemeCookies();
509 static void SetAcceptFileSchemeCookies(JNIEnv* env, jobject obj,
511 return CookieManager::GetInstance()->SetAcceptFileSchemeCookies(accept);
514 scoped_refptr<net::CookieStore> CreateCookieStore(
515 AwBrowserContext* browser_context) {
516 return CookieManager::GetInstance()->CreateBrowserThreadCookieStore(
520 bool RegisterCookieManager(JNIEnv* env) {
521 return RegisterNativesImpl(env);
524 } // android_webview namespace