Roll src/third_party/WebKit 46ff567:25f83be (svn 200502:200512)
[chromium-blink-merge.git] / android_webview / native / cookie_manager.cc
blobb7243bd8544c54b13cf2fa3fb309a9942c3180d2
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/files/file_path.h"
17 #include "base/files/file_util.h"
18 #include "base/lazy_instance.h"
19 #include "base/location.h"
20 #include "base/path_service.h"
21 #include "base/single_thread_task_runner.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_store_factory.h"
30 #include "jni/AwCookieManager_jni.h"
31 #include "net/cookies/cookie_monster.h"
32 #include "net/cookies/cookie_options.h"
33 #include "net/extras/sqlite/cookie_crypto_delegate.h"
34 #include "net/url_request/url_request_context.h"
35 #include "url/url_constants.h"
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;
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
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.
56 namespace android_webview {
58 namespace {
60 typedef base::Callback<void(bool)> BoolCallback;
61 typedef base::Callback<void(int)> IntCallback;
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);
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);
79 static BoolCallback ConvertToCallback(
80 scoped_ptr<BoolCookieCallbackHolder> me) {
81 return base::Bind(&BoolCookieCallbackHolder::Invoke,
82 base::Owned(me.release()));
85 private:
86 ScopedJavaGlobalRef<jobject> callback_;
87 DISALLOW_COPY_AND_ASSIGN(BoolCookieCallbackHolder);
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));
96 static void DiscardBool(const base::Closure& f, bool b) {
97 f.Run();
100 static BoolCallback BoolCallbackAdapter(const base::Closure& f) {
101 return base::Bind(&DiscardBool, f);
104 static void DiscardInt(const base::Closure& f, int i) {
105 f.Run();
108 static IntCallback IntCallbackAdapter(const base::Closure& f) {
109 return base::Bind(&DiscardInt, f);
112 // Are cookies allowed for file:// URLs by default?
113 const bool kDefaultFileSchemeAllowed = false;
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;
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();
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";
144 class CookieManager {
145 public:
146 static CookieManager* GetInstance();
148 scoped_refptr<net::CookieStore> GetCookieStore();
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);
168 private:
169 friend struct base::DefaultLazyInstanceTraits<CookieManager>;
171 CookieManager();
172 ~CookieManager();
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);
179 void SetCookieHelper(
180 const GURL& host,
181 const std::string& value,
182 BoolCallback callback);
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);
191 void RemoveSessionCookiesHelper(BoolCallback callback);
192 void RemoveAllCookiesHelper(BoolCallback callback);
193 void RemoveCookiesCompleted(BoolCallback callback, int num_deleted);
195 void FlushCookieStoreAsyncHelper(base::Closure complete);
197 void HasCookiesAsyncHelper(bool* result, base::Closure complete);
198 void HasCookiesCompleted(base::Closure complete,
199 bool* result,
200 const CookieList& cookies);
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);
210 scoped_refptr<net::CookieMonster> cookie_monster_;
211 scoped_refptr<base::SingleThreadTaskRunner> cookie_monster_task_runner_;
212 base::Lock cookie_monster_lock_;
214 scoped_ptr<base::Thread> cookie_monster_client_thread_;
215 scoped_ptr<base::Thread> cookie_monster_backend_thread_;
217 DISALLOW_COPY_AND_ASSIGN(CookieManager);
220 base::LazyInstance<CookieManager>::Leaky g_lazy_instance;
222 // static
223 CookieManager* CookieManager::GetInstance() {
224 return g_lazy_instance.Pointer();
227 CookieManager::CookieManager() {
230 CookieManager::~CookieManager() {
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"));
240 background_task_runner->PostTask(
241 FROM_HERE,
242 base::Bind(ImportLegacyCookieStore, cookie_store_path));
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);
255 void CookieManager::EnsureCookieMonsterExistsLocked() {
256 cookie_monster_lock_.AssertAcquired();
257 if (cookie_monster_.get()) {
258 return;
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_task_runner_ = cookie_monster_client_thread_->task_runner();
269 cookie_monster_backend_thread_.reset(
270 new base::Thread("CookieMonsterBackend"));
271 cookie_monster_backend_thread_->Start();
273 CreateCookieMonster(user_data_dir, cookie_monster_task_runner_,
274 cookie_monster_backend_thread_->task_runner());
277 // Executes the |task| on the |cookie_monster_proxy_| message loop and
278 // waits for it to complete before returning.
280 // To execute a CookieTask synchronously you must arrange for Signal to be
281 // called on the waitable event at some point. You can call the bool or int
282 // versions of ExecCookieTaskSync, these will supply the caller with a dummy
283 // callback which takes an int/bool, throws it away and calls Signal.
284 // Alternatively you can call the version which supplies a Closure in which
285 // case you must call Run on it when you want the unblock the calling code.
287 // Ignore a bool callback.
288 void CookieManager::ExecCookieTaskSync(
289 const base::Callback<void(BoolCallback)>& task) {
290 WaitableEvent completion(false, false);
291 ExecCookieTask(
292 base::Bind(task, BoolCallbackAdapter(SignalEventClosure(&completion))));
293 ScopedAllowWaitForLegacyWebViewApi wait;
294 completion.Wait();
297 // Ignore an int callback.
298 void CookieManager::ExecCookieTaskSync(
299 const base::Callback<void(IntCallback)>& task) {
300 WaitableEvent completion(false, false);
301 ExecCookieTask(
302 base::Bind(task, IntCallbackAdapter(SignalEventClosure(&completion))));
303 ScopedAllowWaitForLegacyWebViewApi wait;
304 completion.Wait();
307 // Call the supplied closure when you want to signal that the blocked code can
308 // continue.
309 void CookieManager::ExecCookieTaskSync(
310 const base::Callback<void(base::Closure)>& task) {
311 WaitableEvent completion(false, false);
312 ExecCookieTask(base::Bind(task, SignalEventClosure(&completion)));
313 ScopedAllowWaitForLegacyWebViewApi wait;
314 completion.Wait();
317 // Executes the |task| on the |cookie_monster_proxy_| message loop.
318 void CookieManager::ExecCookieTask(const base::Closure& task) {
319 base::AutoLock lock(cookie_monster_lock_);
320 EnsureCookieMonsterExistsLocked();
321 cookie_monster_task_runner_->PostTask(FROM_HERE, task);
324 scoped_refptr<net::CookieStore> CookieManager::GetCookieStore() {
325 base::AutoLock lock(cookie_monster_lock_);
326 EnsureCookieMonsterExistsLocked();
327 return cookie_monster_;
330 void CookieManager::SetShouldAcceptCookies(bool accept) {
331 AwCookieAccessPolicy::GetInstance()->SetShouldAcceptCookies(accept);
334 bool CookieManager::GetShouldAcceptCookies() {
335 return AwCookieAccessPolicy::GetInstance()->GetShouldAcceptCookies();
338 void CookieManager::SetCookie(
339 const GURL& host,
340 const std::string& cookie_value,
341 scoped_ptr<BoolCookieCallbackHolder> callback_holder) {
342 BoolCallback callback =
343 BoolCookieCallbackHolder::ConvertToCallback(callback_holder.Pass());
344 ExecCookieTask(base::Bind(&CookieManager::SetCookieHelper,
345 base::Unretained(this),
346 host,
347 cookie_value,
348 callback));
351 void CookieManager::SetCookieSync(const GURL& host,
352 const std::string& cookie_value) {
353 ExecCookieTaskSync(base::Bind(&CookieManager::SetCookieHelper,
354 base::Unretained(this),
355 host,
356 cookie_value));
359 void CookieManager::SetCookieHelper(
360 const GURL& host,
361 const std::string& value,
362 const BoolCallback callback) {
363 net::CookieOptions options;
364 options.set_include_httponly();
366 cookie_monster_->SetCookieWithOptionsAsync(
367 host, value, options, callback);
370 std::string CookieManager::GetCookie(const GURL& host) {
371 std::string cookie_value;
372 ExecCookieTaskSync(base::Bind(&CookieManager::GetCookieValueAsyncHelper,
373 base::Unretained(this),
374 host,
375 &cookie_value));
376 return cookie_value;
379 void CookieManager::GetCookieValueAsyncHelper(
380 const GURL& host,
381 std::string* result,
382 base::Closure complete) {
383 net::CookieOptions options;
384 options.set_include_httponly();
386 cookie_monster_->GetCookiesWithOptionsAsync(
387 host,
388 options,
389 base::Bind(&CookieManager::GetCookieValueCompleted,
390 base::Unretained(this),
391 complete,
392 result));
395 void CookieManager::GetCookieValueCompleted(base::Closure complete,
396 std::string* result,
397 const std::string& value) {
398 *result = value;
399 complete.Run();
402 void CookieManager::RemoveSessionCookies(
403 scoped_ptr<BoolCookieCallbackHolder> callback_holder) {
404 BoolCallback callback =
405 BoolCookieCallbackHolder::ConvertToCallback(callback_holder.Pass());
406 ExecCookieTask(base::Bind(&CookieManager::RemoveSessionCookiesHelper,
407 base::Unretained(this),
408 callback));
411 void CookieManager::RemoveSessionCookiesSync() {
412 ExecCookieTaskSync(base::Bind(&CookieManager::RemoveSessionCookiesHelper,
413 base::Unretained(this)));
416 void CookieManager::RemoveSessionCookiesHelper(
417 BoolCallback callback) {
418 cookie_monster_->DeleteSessionCookiesAsync(
419 base::Bind(&CookieManager::RemoveCookiesCompleted,
420 base::Unretained(this),
421 callback));
424 void CookieManager::RemoveCookiesCompleted(
425 BoolCallback callback,
426 int num_deleted) {
427 callback.Run(num_deleted > 0);
430 void CookieManager::RemoveAllCookies(
431 scoped_ptr<BoolCookieCallbackHolder> callback_holder) {
432 BoolCallback callback =
433 BoolCookieCallbackHolder::ConvertToCallback(callback_holder.Pass());
434 ExecCookieTask(base::Bind(&CookieManager::RemoveAllCookiesHelper,
435 base::Unretained(this),
436 callback));
439 void CookieManager::RemoveAllCookiesSync() {
440 ExecCookieTaskSync(base::Bind(&CookieManager::RemoveAllCookiesHelper,
441 base::Unretained(this)));
444 void CookieManager::RemoveAllCookiesHelper(
445 const BoolCallback callback) {
446 cookie_monster_->DeleteAllAsync(
447 base::Bind(&CookieManager::RemoveCookiesCompleted,
448 base::Unretained(this),
449 callback));
452 void CookieManager::RemoveExpiredCookies() {
453 // HasCookies will call GetAllCookiesAsync, which in turn will force a GC.
454 HasCookies();
457 void CookieManager::FlushCookieStore() {
458 ExecCookieTaskSync(base::Bind(&CookieManager::FlushCookieStoreAsyncHelper,
459 base::Unretained(this)));
462 void CookieManager::FlushCookieStoreAsyncHelper(
463 base::Closure complete) {
464 cookie_monster_->FlushStore(complete);
467 bool CookieManager::HasCookies() {
468 bool has_cookies;
469 ExecCookieTaskSync(base::Bind(&CookieManager::HasCookiesAsyncHelper,
470 base::Unretained(this),
471 &has_cookies));
472 return has_cookies;
475 // TODO(kristianm): Simplify this, copying the entire list around
476 // should not be needed.
477 void CookieManager::HasCookiesAsyncHelper(bool* result,
478 base::Closure complete) {
479 cookie_monster_->GetAllCookiesAsync(
480 base::Bind(&CookieManager::HasCookiesCompleted,
481 base::Unretained(this),
482 complete,
483 result));
486 void CookieManager::HasCookiesCompleted(base::Closure complete,
487 bool* result,
488 const CookieList& cookies) {
489 *result = cookies.size() != 0;
490 complete.Run();
493 bool CookieManager::AllowFileSchemeCookies() {
494 base::AutoLock lock(cookie_monster_lock_);
495 EnsureCookieMonsterExistsLocked();
496 return AllowFileSchemeCookiesLocked();
499 bool CookieManager::AllowFileSchemeCookiesLocked() {
500 return cookie_monster_->IsCookieableScheme(url::kFileScheme);
503 void CookieManager::SetAcceptFileSchemeCookies(bool accept) {
504 base::AutoLock lock(cookie_monster_lock_);
505 EnsureCookieMonsterExistsLocked();
506 SetAcceptFileSchemeCookiesLocked(accept);
509 void CookieManager::SetAcceptFileSchemeCookiesLocked(bool accept) {
510 cookie_monster_->SetEnableFileScheme(accept);
513 } // namespace
515 static void SetShouldAcceptCookies(JNIEnv* env, jobject obj, jboolean accept) {
516 CookieManager::GetInstance()->SetShouldAcceptCookies(accept);
519 static jboolean GetShouldAcceptCookies(JNIEnv* env, jobject obj) {
520 return CookieManager::GetInstance()->GetShouldAcceptCookies();
523 static void SetCookie(JNIEnv* env,
524 jobject obj,
525 jstring url,
526 jstring value,
527 jobject java_callback) {
528 GURL host(ConvertJavaStringToUTF16(env, url));
529 std::string cookie_value(ConvertJavaStringToUTF8(env, value));
530 scoped_ptr<BoolCookieCallbackHolder> callback(
531 new BoolCookieCallbackHolder(env, java_callback));
532 CookieManager::GetInstance()->SetCookie(host, cookie_value, callback.Pass());
535 static void SetCookieSync(JNIEnv* env,
536 jobject obj,
537 jstring url,
538 jstring value) {
539 GURL host(ConvertJavaStringToUTF16(env, url));
540 std::string cookie_value(ConvertJavaStringToUTF8(env, value));
542 CookieManager::GetInstance()->SetCookieSync(host, cookie_value);
545 static jstring GetCookie(JNIEnv* env, jobject obj, jstring url) {
546 GURL host(ConvertJavaStringToUTF16(env, url));
548 return base::android::ConvertUTF8ToJavaString(
549 env,
550 CookieManager::GetInstance()->GetCookie(host)).Release();
553 static void RemoveSessionCookies(JNIEnv* env,
554 jobject obj,
555 jobject java_callback) {
556 scoped_ptr<BoolCookieCallbackHolder> callback(
557 new BoolCookieCallbackHolder(env, java_callback));
558 CookieManager::GetInstance()->RemoveSessionCookies(callback.Pass());
561 static void RemoveSessionCookiesSync(JNIEnv* env, jobject obj) {
562 CookieManager::GetInstance()->RemoveSessionCookiesSync();
565 static void RemoveAllCookies(JNIEnv* env, jobject obj, jobject java_callback) {
566 scoped_ptr<BoolCookieCallbackHolder> callback(
567 new BoolCookieCallbackHolder(env, java_callback));
568 CookieManager::GetInstance()->RemoveAllCookies(callback.Pass());
571 static void RemoveAllCookiesSync(JNIEnv* env, jobject obj) {
572 CookieManager::GetInstance()->RemoveAllCookiesSync();
575 static void RemoveExpiredCookies(JNIEnv* env, jobject obj) {
576 CookieManager::GetInstance()->RemoveExpiredCookies();
579 static void FlushCookieStore(JNIEnv* env, jobject obj) {
580 CookieManager::GetInstance()->FlushCookieStore();
583 static jboolean HasCookies(JNIEnv* env, jobject obj) {
584 return CookieManager::GetInstance()->HasCookies();
587 static jboolean AllowFileSchemeCookies(JNIEnv* env, jobject obj) {
588 return CookieManager::GetInstance()->AllowFileSchemeCookies();
591 static void SetAcceptFileSchemeCookies(JNIEnv* env, jobject obj,
592 jboolean accept) {
593 return CookieManager::GetInstance()->SetAcceptFileSchemeCookies(accept);
596 scoped_refptr<net::CookieStore> CreateCookieStore(
597 AwBrowserContext* browser_context) {
598 return CookieManager::GetInstance()->GetCookieStore();
601 bool RegisterCookieManager(JNIEnv* env) {
602 return RegisterNativesImpl(env);
605 } // android_webview namespace