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/browser/cookie_manager.h"
6
7 #include <stdint.h>
8
9 #include <memory>
10 #include <utility>
11 #include <vector>
12
13 #include "android_webview/browser/aw_browser_context.h"
14 #include "android_webview/browser/aw_cookie_access_policy.h"
15 #include "android_webview/browser_jni_headers/AwCookieManager_jni.h"
16 #include "base/android/build_info.h"
17 #include "base/android/callback_android.h"
18 #include "base/android/jni_string.h"
19 #include "base/android/path_utils.h"
20 #include "base/bind.h"
21 #include "base/callback_helpers.h"
22 #include "base/containers/circular_deque.h"
23 #include "base/files/file_util.h"
24 #include "base/location.h"
25 #include "base/logging.h"
26 #include "base/memory/ref_counted.h"
27 #include "base/metrics/histogram_functions.h"
28 #include "base/metrics/histogram_macros.h"
29 #include "base/no_destructor.h"
30 #include "base/optional.h"
31 #include "base/path_service.h"
32 #include "base/single_thread_task_runner.h"
33 #include "base/synchronization/lock.h"
34 #include "base/synchronization/waitable_event.h"
35 #include "base/threading/thread.h"
36 #include "base/threading/thread_restrictions.h"
37 #include "base/time/time.h"
38 #include "content/public/browser/browser_thread.h"
39 #include "content/public/browser/cookie_store_factory.h"
40 #include "net/cookies/canonical_cookie.h"
41 #include "net/cookies/cookie_constants.h"
42 #include "net/cookies/cookie_inclusion_status.h"
43 #include "net/cookies/cookie_monster.h"
44 #include "net/cookies/cookie_options.h"
45 #include "net/cookies/cookie_store.h"
46 #include "net/cookies/cookie_util.h"
47 #include "net/cookies/parsed_cookie.h"
48 #include "net/url_request/url_request_context.h"
49 #include "services/network/cookie_access_delegate_impl.h"
50 #include "services/network/network_service.h"
51 #include "services/network/public/mojom/cookie_manager.mojom.h"
52 #include "url/url_constants.h"
53
54 using base::WaitableEvent;
55 using base::android::ConvertJavaStringToUTF16;
56 using base::android::ConvertJavaStringToUTF8;
57 using base::android::JavaParamRef;
58 using base::android::ScopedJavaGlobalRef;
59 using base::android::ScopedJavaLocalRef;
60 using content::BrowserThread;
61 using net::CookieList;
62
63 // In the future, we may instead want to inject an explicit CookieStore
64 // dependency into this object during process initialization to avoid
65 // depending on the URLRequestContext.
66 // See issue http://crbug.com/157683
67
68 // On the CookieManager methods without a callback and methods with a callback
69 // when that callback is null can be called from any thread, including threads
70 // without a message loop. Methods with a non-null callback must be called on
71 // a thread with a running message loop.
72
73 namespace android_webview {
74
75 namespace {
76
MaybeRunCookieCallback(base::OnceCallback<void (bool)> callback,const bool & result)77 void MaybeRunCookieCallback(base::OnceCallback<void(bool)> callback,
78 const bool& result) {
79 if (callback)
80 std::move(callback).Run(result);
81 }
82
83 const char kSecureCookieHistogramName[] = "Android.WebView.SecureCookieAction";
84
85 // These values are persisted to logs. Entries should not be renumbered and
86 // numeric values should never be reused.
87 enum class SecureCookieAction {
88 kInvalidUrl = 0,
89 kAlreadySecureScheme = 1,
90 kInvalidCookie = 2,
91 kNotASecureCookie = 3,
92 kFixedUp = 4,
93 kDisallowedAndroidR = 5,
94 kMaxValue = kDisallowedAndroidR,
95 };
96
97 // Since this function parses the set-cookie line into a ParsedCookie, it is
98 // convenient to hook into here to get the SameSite value from the parsed
99 // cookie for histogramming.
MaybeFixUpSchemeForSecureCookieAndGetSameSite(const GURL & host,const std::string & value,bool workaround_http_secure_cookies,net::CookieSameSiteString * samesite_out,bool * should_allow_cookie)100 GURL MaybeFixUpSchemeForSecureCookieAndGetSameSite(
101 const GURL& host,
102 const std::string& value,
103 bool workaround_http_secure_cookies,
104 net::CookieSameSiteString* samesite_out,
105 bool* should_allow_cookie) {
106 net::ParsedCookie parsed_cookie(value);
107
108 // Grab the SameSite value for histogramming.
109 DCHECK(samesite_out);
110 parsed_cookie.SameSite(samesite_out);
111
112 *should_allow_cookie = true;
113
114 // Log message for catching strict secure cookies related bugs.
115 // TODO(ntfschr): try to remove this, based on UMA stats
116 // (https://crbug.com/933981)
117 if (!host.is_valid()) {
118 base::UmaHistogramEnumeration(kSecureCookieHistogramName,
119 SecureCookieAction::kInvalidUrl);
120 return host;
121 }
122 if (host.has_scheme() && !host.SchemeIs(url::kHttpScheme)) {
123 base::UmaHistogramEnumeration(kSecureCookieHistogramName,
124 SecureCookieAction::kAlreadySecureScheme);
125 return host;
126 }
127 if (!parsed_cookie.IsValid()) {
128 base::UmaHistogramEnumeration(kSecureCookieHistogramName,
129 SecureCookieAction::kInvalidCookie);
130 return host;
131 }
132 if (!parsed_cookie.IsSecure()) {
133 base::UmaHistogramEnumeration(kSecureCookieHistogramName,
134 SecureCookieAction::kNotASecureCookie);
135 return host;
136 }
137
138 LOG(ERROR) << "Strict Secure Cookie policy does not allow setting a "
139 "secure cookie for "
140 << host.spec()
141 << " for apps targeting >= R. Please either use the 'https:' "
142 "scheme for this URL or omit the 'Secure' directive in the "
143 "cookie value.";
144 if (!workaround_http_secure_cookies) {
145 // Don't allow setting this cookie if we target >= R.
146 *should_allow_cookie = false;
147 base::UmaHistogramEnumeration(kSecureCookieHistogramName,
148 SecureCookieAction::kDisallowedAndroidR);
149 return host;
150 }
151
152 base::UmaHistogramEnumeration(kSecureCookieHistogramName,
153 SecureCookieAction::kFixedUp);
154 GURL::Replacements replace_host;
155 replace_host.SetSchemeStr(url::kHttpsScheme);
156 return host.ReplaceComponents(replace_host);
157 }
158
159 // Construct a closure which signals a waitable event if and when the closure
160 // is called the waitable event must still exist.
SignalEventClosure(WaitableEvent * completion)161 static base::OnceClosure SignalEventClosure(WaitableEvent* completion) {
162 return base::BindOnce(&WaitableEvent::Signal, base::Unretained(completion));
163 }
164
DiscardBool(base::OnceClosure f,bool b)165 static void DiscardBool(base::OnceClosure f, bool b) {
166 std::move(f).Run();
167 }
168
BoolCallbackAdapter(base::OnceClosure f)169 static base::OnceCallback<void(bool)> BoolCallbackAdapter(base::OnceClosure f) {
170 return base::BindOnce(&DiscardBool, std::move(f));
171 }
172
DiscardInt(base::OnceClosure f,int i)173 static void DiscardInt(base::OnceClosure f, int i) {
174 std::move(f).Run();
175 }
176
IntCallbackAdapter(base::OnceClosure f)177 static base::OnceCallback<void(int)> IntCallbackAdapter(base::OnceClosure f) {
178 return base::BindOnce(&DiscardInt, std::move(f));
179 }
180
181 // Are cookies allowed for file:// URLs by default?
182 const bool kDefaultFileSchemeAllowed = false;
183
184 } // namespace
185
186 // static
GetInstance()187 CookieManager* CookieManager::GetInstance() {
188 static base::NoDestructor<CookieManager> instance;
189 return instance.get();
190 }
191
192 namespace {
GetPathInAppDirectory(std::string path)193 base::FilePath GetPathInAppDirectory(std::string path) {
194 base::FilePath result;
195 if (!base::PathService::Get(base::DIR_ANDROID_APP_DATA, &result)) {
196 NOTREACHED() << "Failed to get app data directory for Android WebView";
197 }
198 result = result.Append(FILE_PATH_LITERAL(path));
199 return result;
200 }
201 } // namespace
202
CookieManager()203 CookieManager::CookieManager()
204 : allow_file_scheme_cookies_(kDefaultFileSchemeAllowed),
205 cookie_store_created_(false),
206 workaround_http_secure_cookies_(
207 !base::android::BuildInfo::GetInstance()->targets_at_least_r()),
208 cookie_store_client_thread_("CookieMonsterClient"),
209 cookie_store_backend_thread_("CookieMonsterBackend"),
210 setting_new_mojo_cookie_manager_(false) {
211 cookie_store_client_thread_.Start();
212 cookie_store_backend_thread_.Start();
213 cookie_store_task_runner_ = cookie_store_client_thread_.task_runner();
214
215 // TODO(amalova): initialize cookie_store_path_ for non-default profile
216 // Do not migrate cookies for non-default profile.
217 cookie_store_path_ = GetPathInAppDirectory("Default/Cookies");
218 MigrateCookieStorePath();
219 }
220
221 CookieManager::~CookieManager() = default;
222
MigrateCookieStorePath()223 void CookieManager::MigrateCookieStorePath() {
224 base::FilePath old_cookie_store_path = GetPathInAppDirectory("Cookies");
225 base::FilePath old_cookie_journal_path =
226 GetPathInAppDirectory("Cookies-journal");
227 base::FilePath new_cookie_journal_path =
228 GetPathInAppDirectory("Default/Cookies-journal");
229
230 if (base::PathExists(old_cookie_store_path)) {
231 base::CreateDirectory(cookie_store_path_.DirName());
232 base::Move(old_cookie_store_path, cookie_store_path_);
233 base::Move(old_cookie_journal_path, new_cookie_journal_path);
234 }
235 }
236
237 // Executes the |task| on |cookie_store_task_runner_| and waits for it to
238 // complete before returning.
239 //
240 // To execute a CookieTask synchronously you must arrange for Signal to be
241 // called on the waitable event at some point. You can call the bool or int
242 // versions of ExecCookieTaskSync, these will supply the caller with a dummy
243 // callback which takes an int/bool, throws it away and calls Signal.
244 // Alternatively you can call the version which supplies a Closure in which
245 // case you must call Run on it when you want the unblock the calling code.
246 //
247 // Ignore a bool callback.
ExecCookieTaskSync(base::OnceCallback<void (base::OnceCallback<void (bool)>)> task)248 void CookieManager::ExecCookieTaskSync(
249 base::OnceCallback<void(base::OnceCallback<void(bool)>)> task) {
250 WaitableEvent completion(base::WaitableEvent::ResetPolicy::AUTOMATIC,
251 base::WaitableEvent::InitialState::NOT_SIGNALED);
252 ExecCookieTask(base::BindOnce(
253 std::move(task), BoolCallbackAdapter(SignalEventClosure(&completion))));
254
255 // Waiting is necessary when implementing synchronous APIs for the WebView
256 // embedder.
257 base::ScopedAllowBaseSyncPrimitivesOutsideBlockingScope wait;
258 completion.Wait();
259 }
260
261 // Ignore an int callback.
ExecCookieTaskSync(base::OnceCallback<void (base::OnceCallback<void (int)>)> task)262 void CookieManager::ExecCookieTaskSync(
263 base::OnceCallback<void(base::OnceCallback<void(int)>)> task) {
264 WaitableEvent completion(base::WaitableEvent::ResetPolicy::AUTOMATIC,
265 base::WaitableEvent::InitialState::NOT_SIGNALED);
266 ExecCookieTask(base::BindOnce(
267 std::move(task), IntCallbackAdapter(SignalEventClosure(&completion))));
268 base::ScopedAllowBaseSyncPrimitivesOutsideBlockingScope wait;
269 completion.Wait();
270 }
271
272 // Call the supplied closure when you want to signal that the blocked code can
273 // continue.
ExecCookieTaskSync(base::OnceCallback<void (base::OnceClosure)> task)274 void CookieManager::ExecCookieTaskSync(
275 base::OnceCallback<void(base::OnceClosure)> task) {
276 WaitableEvent completion(base::WaitableEvent::ResetPolicy::AUTOMATIC,
277 base::WaitableEvent::InitialState::NOT_SIGNALED);
278 ExecCookieTask(
279 base::BindOnce(std::move(task), SignalEventClosure(&completion)));
280 base::ScopedAllowBaseSyncPrimitivesOutsideBlockingScope wait;
281 completion.Wait();
282 }
283
284 // Executes the |task| using |cookie_store_task_runner_|.
ExecCookieTask(base::OnceClosure task)285 void CookieManager::ExecCookieTask(base::OnceClosure task) {
286 base::AutoLock lock(task_queue_lock_);
287 tasks_.push_back(std::move(task));
288 // Unretained is safe, since android_webview::CookieManager is a singleton we
289 // never destroy (we don't need PostTask to do any memory management).
290 cookie_store_task_runner_->PostTask(
291 FROM_HERE, base::BindOnce(&CookieManager::RunPendingCookieTasks,
292 base::Unretained(this)));
293 }
294
RunPendingCookieTasks()295 void CookieManager::RunPendingCookieTasks() {
296 DCHECK(cookie_store_task_runner_->RunsTasksInCurrentSequence());
297 // Don't do any cookie tasks if in the middle of setting a mojo CookieManager,
298 // we'll call this method when that operation is finished.
299 if (setting_new_mojo_cookie_manager_)
300 return;
301
302 // Copy tasks into temp_queue to minimize the amount of time in the critical
303 // section, and to mitigate live-lock issues if these tasks append to the task
304 // queue themselves.
305 base::circular_deque<base::OnceClosure> temp_queue;
306 {
307 base::AutoLock lock(task_queue_lock_);
308 temp_queue.swap(tasks_);
309 }
310 while (!temp_queue.empty()) {
311 std::move(temp_queue.front()).Run();
312 temp_queue.pop_front();
313 }
314 }
315
GetCookieStorePath()316 base::FilePath CookieManager::GetCookieStorePath() {
317 return cookie_store_path_;
318 }
319
GetCookieStore()320 net::CookieStore* CookieManager::GetCookieStore() {
321 DCHECK(cookie_store_task_runner_->RunsTasksInCurrentSequence());
322
323 if (!cookie_store_) {
324 content::CookieStoreConfig cookie_config(
325 cookie_store_path_, true /* restore_old_session_cookies */,
326 true /* persist_session_cookies */);
327 cookie_config.client_task_runner = cookie_store_task_runner_;
328 cookie_config.background_task_runner =
329 cookie_store_backend_thread_.task_runner();
330
331 {
332 base::AutoLock lock(allow_file_scheme_cookies_lock_);
333
334 // There are some unknowns about how to correctly handle file:// cookies,
335 // and our implementation for this is not robust. http://crbug.com/582985
336 //
337 // TODO(mmenke): This call should be removed once we can deprecate and
338 // remove the Android WebView 'CookieManager::SetAllowFileSchemeCookies'
339 // method. Until then, note that this is just not a great idea.
340 cookie_config.cookieable_schemes.insert(
341 cookie_config.cookieable_schemes.begin(),
342 net::CookieMonster::kDefaultCookieableSchemes,
343 net::CookieMonster::kDefaultCookieableSchemes +
344 net::CookieMonster::kDefaultCookieableSchemesCount);
345 if (allow_file_scheme_cookies_)
346 cookie_config.cookieable_schemes.push_back(url::kFileScheme);
347 cookie_store_created_ = true;
348 }
349
350 cookie_store_ = content::CreateCookieStore(cookie_config, nullptr);
351 // Use a CookieAccessDelegate that always returns Legacy mode, for
352 // compatibility reasons.
353 cookie_store_->SetCookieAccessDelegate(
354 std::make_unique<network::CookieAccessDelegateImpl>(
355 network::mojom::CookieAccessDelegateType::ALWAYS_LEGACY,
356 nullptr /* preloaded_first_party_sets */));
357 }
358
359 return cookie_store_.get();
360 }
361
GetMojoCookieManager()362 network::mojom::CookieManager* CookieManager::GetMojoCookieManager() {
363 DCHECK(cookie_store_task_runner_->RunsTasksInCurrentSequence());
364 if (!mojo_cookie_manager_.is_bound())
365 return nullptr;
366 return mojo_cookie_manager_.get();
367 }
368
SetMojoCookieManager(mojo::PendingRemote<network::mojom::CookieManager> cookie_manager_remote)369 void CookieManager::SetMojoCookieManager(
370 mojo::PendingRemote<network::mojom::CookieManager> cookie_manager_remote) {
371 DCHECK_CURRENTLY_ON(BrowserThread::UI);
372 ExecCookieTaskSync(base::BindOnce(&CookieManager::SetMojoCookieManagerAsync,
373 base::Unretained(this),
374 std::move(cookie_manager_remote)));
375 }
376
SetMojoCookieManagerAsync(mojo::PendingRemote<network::mojom::CookieManager> cookie_manager_remote,base::OnceClosure complete)377 void CookieManager::SetMojoCookieManagerAsync(
378 mojo::PendingRemote<network::mojom::CookieManager> cookie_manager_remote,
379 base::OnceClosure complete) {
380 DCHECK(cookie_store_task_runner_->RunsTasksInCurrentSequence());
381 setting_new_mojo_cookie_manager_ = true;
382 // For simplicity, only permit this method to be called once (otherwise, we
383 // must sometimes flush the mojo_cookie_manager_ instead of cookie_store_).
384 DCHECK(!mojo_cookie_manager_.is_bound());
385 if (!cookie_store_created_) {
386 SwapMojoCookieManagerAsync(std::move(cookie_manager_remote),
387 std::move(complete));
388 return;
389 }
390
391 GetCookieStore()->FlushStore(base::BindOnce(
392 &CookieManager::SwapMojoCookieManagerAsync, base::Unretained(this),
393 std::move(cookie_manager_remote), std::move(complete)));
394 }
395
SwapMojoCookieManagerAsync(mojo::PendingRemote<network::mojom::CookieManager> cookie_manager_remote,base::OnceClosure complete)396 void CookieManager::SwapMojoCookieManagerAsync(
397 mojo::PendingRemote<network::mojom::CookieManager> cookie_manager_remote,
398 base::OnceClosure complete) {
399 DCHECK(cookie_store_task_runner_->RunsTasksInCurrentSequence());
400 mojo_cookie_manager_.Bind(std::move(cookie_manager_remote));
401 setting_new_mojo_cookie_manager_ = false;
402 std::move(complete).Run(); // unblock content initialization
403 RunPendingCookieTasks();
404 }
405
SetWorkaroundHttpSecureCookiesForTesting(JNIEnv * env,const JavaParamRef<jobject> & obj,jboolean allow)406 void CookieManager::SetWorkaroundHttpSecureCookiesForTesting(
407 JNIEnv* env,
408 const JavaParamRef<jobject>& obj,
409 jboolean allow) {
410 ExecCookieTaskSync(
411 base::BindOnce(&CookieManager::SetWorkaroundHttpSecureCookiesAsyncHelper,
412 base::Unretained(this), allow));
413 }
414
SetWorkaroundHttpSecureCookiesAsyncHelper(bool allow,base::OnceClosure complete)415 void CookieManager::SetWorkaroundHttpSecureCookiesAsyncHelper(
416 bool allow,
417 base::OnceClosure complete) {
418 DCHECK(cookie_store_task_runner_->RunsTasksInCurrentSequence());
419 workaround_http_secure_cookies_ = allow;
420 std::move(complete).Run();
421 }
422
SetShouldAcceptCookies(JNIEnv * env,const JavaParamRef<jobject> & obj,jboolean accept)423 void CookieManager::SetShouldAcceptCookies(JNIEnv* env,
424 const JavaParamRef<jobject>& obj,
425 jboolean accept) {
426 AwCookieAccessPolicy::GetInstance()->SetShouldAcceptCookies(accept);
427 }
428
GetShouldAcceptCookies(JNIEnv * env,const JavaParamRef<jobject> & obj)429 jboolean CookieManager::GetShouldAcceptCookies(
430 JNIEnv* env,
431 const JavaParamRef<jobject>& obj) {
432 return AwCookieAccessPolicy::GetInstance()->GetShouldAcceptCookies();
433 }
434
SetCookie(JNIEnv * env,const JavaParamRef<jobject> & obj,const JavaParamRef<jstring> & url,const JavaParamRef<jstring> & value,const JavaParamRef<jobject> & java_callback)435 void CookieManager::SetCookie(JNIEnv* env,
436 const JavaParamRef<jobject>& obj,
437 const JavaParamRef<jstring>& url,
438 const JavaParamRef<jstring>& value,
439 const JavaParamRef<jobject>& java_callback) {
440 DCHECK(java_callback) << "Unexpected null Java callback";
441 GURL host(ConvertJavaStringToUTF16(env, url));
442 std::string cookie_value(ConvertJavaStringToUTF8(env, value));
443 base::OnceCallback<void(bool)> callback =
444 base::BindOnce(&base::android::RunBooleanCallbackAndroid,
445 ScopedJavaGlobalRef<jobject>(java_callback));
446
447 ExecCookieTask(base::BindOnce(&CookieManager::SetCookieHelper,
448 base::Unretained(this), host, cookie_value,
449 std::move(callback)));
450 }
451
SetCookieSync(JNIEnv * env,const JavaParamRef<jobject> & obj,const JavaParamRef<jstring> & url,const JavaParamRef<jstring> & value)452 void CookieManager::SetCookieSync(JNIEnv* env,
453 const JavaParamRef<jobject>& obj,
454 const JavaParamRef<jstring>& url,
455 const JavaParamRef<jstring>& value) {
456 GURL host(ConvertJavaStringToUTF16(env, url));
457 std::string cookie_value(ConvertJavaStringToUTF8(env, value));
458
459 ExecCookieTaskSync(base::BindOnce(&CookieManager::SetCookieHelper,
460 base::Unretained(this), host,
461 cookie_value));
462 }
463
SetCookieHelper(const GURL & host,const std::string & value,base::OnceCallback<void (bool)> callback)464 void CookieManager::SetCookieHelper(const GURL& host,
465 const std::string& value,
466 base::OnceCallback<void(bool)> callback) {
467 DCHECK(cookie_store_task_runner_->RunsTasksInCurrentSequence());
468
469 net::CookieSameSiteString samesite = net::CookieSameSiteString::kUnspecified;
470 bool should_allow_cookie = true;
471 const GURL& new_host = MaybeFixUpSchemeForSecureCookieAndGetSameSite(
472 host, value, workaround_http_secure_cookies_, &samesite,
473 &should_allow_cookie);
474
475 UMA_HISTOGRAM_ENUMERATION(
476 "Android.WebView.CookieManager.SameSiteAttributeValue", samesite);
477
478 net::CookieInclusionStatus status;
479 std::unique_ptr<net::CanonicalCookie> cc(
480 net::CanonicalCookie::Create(new_host, value, base::Time::Now(),
481 base::nullopt /* server_time */, &status));
482
483 if (!cc || !should_allow_cookie) {
484 MaybeRunCookieCallback(std::move(callback), false);
485 return;
486 }
487
488 if (cc->SameSite() == net::CookieSameSite::NO_RESTRICTION) {
489 UMA_HISTOGRAM_BOOLEAN("Android.WebView.CookieManager.SameSiteNoneIsSecure",
490 cc->IsSecure());
491 }
492
493 // Note: CookieStore and network::CookieManager both accept a
494 // CookieAccessResult callback. WebView only cares about boolean success,
495 // which is why we use |AdaptCookieAccessResultToBool|. This is temporary
496 // technical debt until we fully launch the Network Service code path.
497 if (GetMojoCookieManager()) {
498 // *cc.get() is safe, because network::CookieManager::SetCanonicalCookie
499 // will make a copy before our smart pointer goes out of scope.
500 GetMojoCookieManager()->SetCanonicalCookie(
501 *cc.get(), new_host, net::CookieOptions::MakeAllInclusive(),
502 net::cookie_util::AdaptCookieAccessResultToBool(std::move(callback)));
503 } else {
504 GetCookieStore()->SetCanonicalCookieAsync(
505 std::move(cc), new_host, net::CookieOptions::MakeAllInclusive(),
506 net::cookie_util::AdaptCookieAccessResultToBool(std::move(callback)));
507 }
508 }
509
GetCookie(JNIEnv * env,const JavaParamRef<jobject> & obj,const JavaParamRef<jstring> & url)510 ScopedJavaLocalRef<jstring> CookieManager::GetCookie(
511 JNIEnv* env,
512 const JavaParamRef<jobject>& obj,
513 const JavaParamRef<jstring>& url) {
514 GURL host(ConvertJavaStringToUTF16(env, url));
515
516 net::CookieList cookie_list;
517 ExecCookieTaskSync(base::BindOnce(&CookieManager::GetCookieListAsyncHelper,
518 base::Unretained(this), host,
519 &cookie_list));
520
521 return base::android::ConvertUTF8ToJavaString(
522 env, net::CanonicalCookie::BuildCookieLine(cookie_list));
523 }
524
GetCookieListAsyncHelper(const GURL & host,net::CookieList * result,base::OnceClosure complete)525 void CookieManager::GetCookieListAsyncHelper(const GURL& host,
526 net::CookieList* result,
527 base::OnceClosure complete) {
528 net::CookieOptions options = net::CookieOptions::MakeAllInclusive();
529
530 if (GetMojoCookieManager()) {
531 GetMojoCookieManager()->GetCookieList(
532 host, options,
533 base::BindOnce(&CookieManager::GetCookieListCompleted,
534 base::Unretained(this), std::move(complete), result));
535 } else {
536 GetCookieStore()->GetCookieListWithOptionsAsync(
537 host, options,
538 base::BindOnce(&CookieManager::GetCookieListCompleted,
539 base::Unretained(this), std::move(complete), result));
540 }
541 }
542
GetCookieListCompleted(base::OnceClosure complete,net::CookieList * result,const net::CookieAccessResultList & value,const net::CookieAccessResultList & excluded_cookies)543 void CookieManager::GetCookieListCompleted(
544 base::OnceClosure complete,
545 net::CookieList* result,
546 const net::CookieAccessResultList& value,
547 const net::CookieAccessResultList& excluded_cookies) {
548 *result = net::cookie_util::StripAccessResults(value);
549 std::move(complete).Run();
550 }
551
RemoveSessionCookies(JNIEnv * env,const JavaParamRef<jobject> & obj,const JavaParamRef<jobject> & java_callback)552 void CookieManager::RemoveSessionCookies(
553 JNIEnv* env,
554 const JavaParamRef<jobject>& obj,
555 const JavaParamRef<jobject>& java_callback) {
556 DCHECK(java_callback) << "Unexpected null Java callback";
557 base::OnceCallback<void(bool)> callback =
558 base::BindOnce(&base::android::RunBooleanCallbackAndroid,
559 ScopedJavaGlobalRef<jobject>(java_callback));
560
561 ExecCookieTask(base::BindOnce(&CookieManager::RemoveSessionCookiesHelper,
562 base::Unretained(this), std::move(callback)));
563 }
564
RemoveSessionCookiesSync(JNIEnv * env,const JavaParamRef<jobject> & obj)565 void CookieManager::RemoveSessionCookiesSync(JNIEnv* env,
566 const JavaParamRef<jobject>& obj) {
567 ExecCookieTaskSync(base::BindOnce(&CookieManager::RemoveSessionCookiesHelper,
568 base::Unretained(this)));
569 }
570
RemoveSessionCookiesHelper(base::OnceCallback<void (bool)> callback)571 void CookieManager::RemoveSessionCookiesHelper(
572 base::OnceCallback<void(bool)> callback) {
573 if (GetMojoCookieManager()) {
574 auto match_session_cookies = network::mojom::CookieDeletionFilter::New();
575 match_session_cookies->session_control =
576 network::mojom::CookieDeletionSessionControl::SESSION_COOKIES;
577 GetMojoCookieManager()->DeleteCookies(
578 std::move(match_session_cookies),
579 base::BindOnce(&CookieManager::RemoveCookiesCompleted,
580 base::Unretained(this), std::move(callback)));
581 } else {
582 GetCookieStore()->DeleteSessionCookiesAsync(
583 base::BindOnce(&CookieManager::RemoveCookiesCompleted,
584 base::Unretained(this), std::move(callback)));
585 }
586 }
587
RemoveCookiesCompleted(base::OnceCallback<void (bool)> callback,uint32_t num_deleted)588 void CookieManager::RemoveCookiesCompleted(
589 base::OnceCallback<void(bool)> callback,
590 uint32_t num_deleted) {
591 std::move(callback).Run(num_deleted > 0u);
592 }
593
RemoveAllCookies(JNIEnv * env,const JavaParamRef<jobject> & obj,const JavaParamRef<jobject> & java_callback)594 void CookieManager::RemoveAllCookies(
595 JNIEnv* env,
596 const JavaParamRef<jobject>& obj,
597 const JavaParamRef<jobject>& java_callback) {
598 DCHECK(java_callback) << "Unexpected null Java callback";
599
600 base::OnceCallback<void(bool)> callback =
601 base::BindOnce(&base::android::RunBooleanCallbackAndroid,
602 ScopedJavaGlobalRef<jobject>(java_callback));
603
604 ExecCookieTask(base::BindOnce(&CookieManager::RemoveAllCookiesHelper,
605 base::Unretained(this), std::move(callback)));
606 }
607
RemoveAllCookiesSync(JNIEnv * env,const JavaParamRef<jobject> & obj)608 void CookieManager::RemoveAllCookiesSync(JNIEnv* env,
609 const JavaParamRef<jobject>& obj) {
610 ExecCookieTaskSync(base::BindOnce(&CookieManager::RemoveAllCookiesHelper,
611 base::Unretained(this)));
612 }
613
RemoveAllCookiesHelper(base::OnceCallback<void (bool)> callback)614 void CookieManager::RemoveAllCookiesHelper(
615 base::OnceCallback<void(bool)> callback) {
616 if (GetMojoCookieManager()) {
617 // An empty filter matches all cookies.
618 auto match_all_cookies = network::mojom::CookieDeletionFilter::New();
619 GetMojoCookieManager()->DeleteCookies(
620 std::move(match_all_cookies),
621 base::BindOnce(&CookieManager::RemoveCookiesCompleted,
622 base::Unretained(this), std::move(callback)));
623 } else {
624 GetCookieStore()->DeleteAllAsync(
625 base::BindOnce(&CookieManager::RemoveCookiesCompleted,
626 base::Unretained(this), std::move(callback)));
627 }
628 }
629
RemoveExpiredCookies(JNIEnv * env,const JavaParamRef<jobject> & obj)630 void CookieManager::RemoveExpiredCookies(JNIEnv* env,
631 const JavaParamRef<jobject>& obj) {
632 // HasCookies will call GetAllCookiesAsync, which in turn will force a GC.
633 HasCookies(env, obj);
634 }
635
FlushCookieStore(JNIEnv * env,const JavaParamRef<jobject> & obj)636 void CookieManager::FlushCookieStore(JNIEnv* env,
637 const JavaParamRef<jobject>& obj) {
638 ExecCookieTaskSync(base::BindOnce(&CookieManager::FlushCookieStoreAsyncHelper,
639 base::Unretained(this)));
640 }
641
FlushCookieStoreAsyncHelper(base::OnceClosure complete)642 void CookieManager::FlushCookieStoreAsyncHelper(base::OnceClosure complete) {
643 if (GetMojoCookieManager()) {
644 GetMojoCookieManager()->FlushCookieStore(std::move(complete));
645 } else {
646 GetCookieStore()->FlushStore(std::move(complete));
647 }
648 }
649
HasCookies(JNIEnv * env,const JavaParamRef<jobject> & obj)650 jboolean CookieManager::HasCookies(JNIEnv* env,
651 const JavaParamRef<jobject>& obj) {
652 bool has_cookies;
653 ExecCookieTaskSync(base::BindOnce(&CookieManager::HasCookiesAsyncHelper,
654 base::Unretained(this), &has_cookies));
655 return has_cookies;
656 }
657
658 // TODO(kristianm): Simplify this, copying the entire list around
659 // should not be needed.
HasCookiesAsyncHelper(bool * result,base::OnceClosure complete)660 void CookieManager::HasCookiesAsyncHelper(bool* result,
661 base::OnceClosure complete) {
662 if (GetMojoCookieManager()) {
663 GetMojoCookieManager()->GetAllCookies(
664 base::BindOnce(&CookieManager::HasCookiesCompleted,
665 base::Unretained(this), std::move(complete), result));
666 } else {
667 GetCookieStore()->GetAllCookiesAsync(
668 base::BindOnce(&CookieManager::HasCookiesCompleted,
669 base::Unretained(this), std::move(complete), result));
670 }
671 }
672
HasCookiesCompleted(base::OnceClosure complete,bool * result,const CookieList & cookies)673 void CookieManager::HasCookiesCompleted(base::OnceClosure complete,
674 bool* result,
675 const CookieList& cookies) {
676 *result = cookies.size() != 0;
677 std::move(complete).Run();
678 }
679
GetAllowFileSchemeCookies()680 bool CookieManager::GetAllowFileSchemeCookies() {
681 base::AutoLock lock(allow_file_scheme_cookies_lock_);
682 return allow_file_scheme_cookies_;
683 }
684
GetAllowFileSchemeCookies(JNIEnv * env,const JavaParamRef<jobject> & obj)685 jboolean CookieManager::GetAllowFileSchemeCookies(
686 JNIEnv* env,
687 const JavaParamRef<jobject>& obj) {
688 return GetAllowFileSchemeCookies();
689 }
690
SetAllowFileSchemeCookies(JNIEnv * env,const JavaParamRef<jobject> & obj,jboolean allow)691 void CookieManager::SetAllowFileSchemeCookies(JNIEnv* env,
692 const JavaParamRef<jobject>& obj,
693 jboolean allow) {
694 ExecCookieTaskSync(
695 base::BindOnce(&CookieManager::SetAllowFileSchemeCookiesAsyncHelper,
696 base::Unretained(this), allow));
697 }
698
SetAllowFileSchemeCookiesAsyncHelper(bool allow,base::OnceClosure complete)699 void CookieManager::SetAllowFileSchemeCookiesAsyncHelper(
700 bool allow,
701 base::OnceClosure complete) {
702 DCHECK(cookie_store_task_runner_->RunsTasksInCurrentSequence());
703 if (GetMojoCookieManager()) {
704 GetMojoCookieManager()->AllowFileSchemeCookies(
705 allow,
706 base::BindOnce(&CookieManager::SetAllowFileSchemeCookiesCompleted,
707 base::Unretained(this), std::move(complete), allow));
708 } else {
709 // If we have neither a Network Service CookieManager nor have created the
710 // CookieStore, we may modify |allow_file_scheme_cookies_|.
711 bool can_change_schemes = !cookie_store_created_;
712 SetAllowFileSchemeCookiesCompleted(std::move(complete), allow,
713 can_change_schemes);
714 }
715 }
716
SetAllowFileSchemeCookiesCompleted(base::OnceClosure complete,bool allow,bool can_change_schemes)717 void CookieManager::SetAllowFileSchemeCookiesCompleted(
718 base::OnceClosure complete,
719 bool allow,
720 bool can_change_schemes) {
721 // Should only update |allow_file_scheme_cookies_| if
722 // SetAllowFileSchemeCookiesAsyncHelper said this is OK.
723 if (can_change_schemes) {
724 base::AutoLock lock(allow_file_scheme_cookies_lock_);
725 allow_file_scheme_cookies_ = allow;
726 }
727 std::move(complete).Run();
728 }
729
JNI_AwCookieManager_GetDefaultCookieManager(JNIEnv * env)730 static jlong JNI_AwCookieManager_GetDefaultCookieManager(JNIEnv* env) {
731 return reinterpret_cast<intptr_t>(CookieManager::GetInstance());
732 }
733
734 } // namespace android_webview
735