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