1 // Copyright 2019 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 #ifndef ANDROID_WEBVIEW_BROWSER_COOKIE_MANAGER_H_
6 #define ANDROID_WEBVIEW_BROWSER_COOKIE_MANAGER_H_
7 
8 #include <memory>
9 #include <vector>
10 
11 #include "base/android/scoped_java_ref.h"
12 #include "base/containers/circular_deque.h"
13 #include "base/no_destructor.h"
14 #include "base/thread_annotations.h"
15 #include "base/threading/thread.h"
16 #include "mojo/public/cpp/bindings/pending_remote.h"
17 #include "mojo/public/cpp/bindings/remote.h"
18 #include "services/network/public/mojom/cookie_manager.mojom-forward.h"
19 #include "services/network/public/mojom/cookie_manager.mojom.h"
20 
21 class GURL;
22 
23 namespace base {
24 class SingleThreadTaskRunner;
25 }
26 
27 namespace net {
28 class CookieStore;
29 class CanonicalCookie;
30 }
31 
32 namespace android_webview {
33 
34 // CookieManager creates and owns Webview's CookieStore, in addition to handling
35 // calls into the CookieStore from Java.
36 //
37 // Since Java calls can be made on the IO Thread, and must synchronously return
38 // a result, and the CookieStore API allows it to asynchronously return results,
39 // the CookieStore must be run on its own thread, to prevent deadlock.
40 //
41 // Initialization:
42 //
43 // There are two possible scenarios: 1) The CookieManager is used before the
44 // Network Service is initialized. 2) The CookieManager is not used until after
45 // the Network Service is initialized (during content initialization).
46 //
47 // Case 2) is straightforward: Once the NetworkContext and the
48 // network::mojom::CookieManager are created, the AwContentBrowserClient calls
49 // PassMojoCookieManagerToAwCookieManager, which ends up calling
50 // CookieManager::SwapMojoCookieManagerAsync, setting the |mojo_cookie_manager_|
51 // member of CookieManager (the AW one; it's an unfortunately overloaded term).
52 //
53 // In case 1), the CookieManager creates a provisional CookieStore
54 // |cookie_store_|, which it uses for all operations (because the
55 // network::mojom::CookieManager doesn't exist yet): For every cookie task
56 // it receives, the CookieManager first checks for the presence of a
57 // |mojo_cookie_manager_|, and if it doesn't exist, the CookieManager checks for
58 // the presence of a provisionally-created CookieStore, creating one if it
59 // doesn't exist (in GetCookieStore). Then whichever one it found will handle
60 // the cookie task.
61 //
62 // When it comes time to create the NetworkContext, which comes with a
63 // network::mojom::CookieManager, the provisionally-created CookieStore needs to
64 // transfer its contents (with the results of the pre-content-initialization
65 // cookie tasks) to the newly created network::mojom::CookieManager. It does
66 // this by flushing its contents to disk and then calling the same method,
67 // CookieManager::SwapMojoCookieManagerAsync, which binds the newly created
68 // network::mojom::CookieManager to |mojo_cookie_manager_|. Thereafter, any
69 // cookie tasks will be handled by |mojo_cookie_manager_| because it now exists.
70 //
71 // This works because the newly created network::mojom::CookieManager reads from
72 // the same on-disk backing store that the provisionally-created CookieStore
73 // just flushed its contents to.
74 //
75 // Why is this not a race condition? This was addressed in crbug.com/933461.
76 // If the CookieManager receives cookie tasks while the flush is in progress,
77 // those tasks are added to a task queue, which is not executed until after the
78 // new |mojo_cookie_manager_| has finished being set. The new
79 // |mojo_cookie_manager_| only loads from disk upon receiving a task (*not* upon
80 // creation, importantly; see CookieMonster::FetchAllCookiesIfNecessary, which
81 // is only called if cookie tasks are received), so it will not try to load from
82 // disk until the flush is complete.
83 class CookieManager {
84  public:
85   static CookieManager* GetInstance();
86 
87   // Passes a |cookie_manager_remote|, which this will use for CookieManager
88   // APIs going forward. Only called in the Network Service path, with the
89   // intention this is called once during content initialization (when we create
90   // the only NetworkContext). Note: no other cookie tasks will be processed
91   // while this operation is running.
92   void SetMojoCookieManager(
93       mojo::PendingRemote<network::mojom::CookieManager> cookie_manager_remote);
94 
95   // Configure whether or not this CookieManager should workaround cookies
96   // specified for insecure URLs with the 'Secure' directive. See
97   // |workaround_http_secure_cookies_| for the default behavior. This should not
98   // be needed in production, as the default is the desirable behavior.
99   void SetWorkaroundHttpSecureCookiesForTesting(
100       JNIEnv* env,
101       const base::android::JavaParamRef<jobject>& obj,
102       jboolean allow);
103   void SetShouldAcceptCookies(JNIEnv* env,
104                               const base::android::JavaParamRef<jobject>& obj,
105                               jboolean accept);
106   jboolean GetShouldAcceptCookies(
107       JNIEnv* env,
108       const base::android::JavaParamRef<jobject>& obj);
109   void SetCookie(JNIEnv* env,
110                  const base::android::JavaParamRef<jobject>& obj,
111                  const base::android::JavaParamRef<jstring>& url,
112                  const base::android::JavaParamRef<jstring>& value,
113                  const base::android::JavaParamRef<jobject>& java_callback);
114   void SetCookieSync(JNIEnv* env,
115                      const base::android::JavaParamRef<jobject>& obj,
116                      const base::android::JavaParamRef<jstring>& url,
117                      const base::android::JavaParamRef<jstring>& value);
118 
119   base::android::ScopedJavaLocalRef<jstring> GetCookie(
120       JNIEnv* env,
121       const base::android::JavaParamRef<jobject>& obj,
122       const base::android::JavaParamRef<jstring>& url);
123 
124   void RemoveAllCookies(
125       JNIEnv* env,
126       const base::android::JavaParamRef<jobject>& obj,
127       const base::android::JavaParamRef<jobject>& java_callback);
128   void RemoveSessionCookies(
129       JNIEnv* env,
130       const base::android::JavaParamRef<jobject>& obj,
131       const base::android::JavaParamRef<jobject>& java_callback);
132   void RemoveAllCookiesSync(JNIEnv* env,
133                             const base::android::JavaParamRef<jobject>& obj);
134   void RemoveSessionCookiesSync(
135       JNIEnv* env,
136       const base::android::JavaParamRef<jobject>& obj);
137   void RemoveExpiredCookies(JNIEnv* env,
138                             const base::android::JavaParamRef<jobject>& obj);
139   void FlushCookieStore(JNIEnv* env,
140                         const base::android::JavaParamRef<jobject>& obj);
141   jboolean HasCookies(JNIEnv* env,
142                       const base::android::JavaParamRef<jobject>& obj);
143   bool GetAllowFileSchemeCookies();
144   jboolean GetAllowFileSchemeCookies(
145       JNIEnv* env,
146       const base::android::JavaParamRef<jobject>& obj);
147 
148   // Configures whether CookieManager and WebView instances will honor requests
149   // to set cookies for file:// scheme URLs. This method must be called (and
150   // must finish execution) before calling any other WebView APIs which modify
151   // the cookie store (otherwise, this is not guaranteed to succeed).
152   //
153   // This blocks the calling thread until its work is done to achieve this
154   // guarantee (otherwise other mojo::Remote<network::mojom::CookieManager>
155   // instances might be able to modify the underlying net::CookieStore before
156   // this call finishes.
157   void SetAllowFileSchemeCookies(
158       JNIEnv* env,
159       const base::android::JavaParamRef<jobject>& obj,
160       jboolean allow);
161 
162   base::FilePath GetCookieStorePath();
163 
164  private:
165   friend class base::NoDestructor<CookieManager>;
166 
167   CookieManager();
168   ~CookieManager();
169 
170   // Returns the CookieStore, creating it if necessary. This must only be called
171   // on the CookieStore TaskRunner.
172   net::CookieStore* GetCookieStore();
173 
174   // Gets the Network Service CookieManager if it's been passed via
175   // |SetMojoCookieManager|. Otherwise (if Network Service is disabled or
176   // content layer has not yet initialized the NetworkContext), this returns
177   // nullptr (and |GetCookieStore| should be used installed). This must only be
178   // called on the CookieStore TaskRunner.
179   network::mojom::CookieManager* GetMojoCookieManager();
180 
181   void ExecCookieTaskSync(
182       base::OnceCallback<void(base::OnceCallback<void(bool)>)> task);
183   void ExecCookieTaskSync(
184       base::OnceCallback<void(base::OnceCallback<void(int)>)> task);
185   void ExecCookieTaskSync(base::OnceCallback<void(base::OnceClosure)> task);
186   void ExecCookieTask(base::OnceClosure task);
187   // Runs all queued-up cookie tasks in |tasks_|.
188   void RunPendingCookieTasks();
189 
190   void SetCookieHelper(const GURL& host,
191                        const std::string& value,
192                        base::OnceCallback<void(bool)> callback);
193 
194   void SetWorkaroundHttpSecureCookiesAsyncHelper(bool allow,
195                                                  base::OnceClosure complete);
196 
197   void GotCookies(const std::vector<net::CanonicalCookie>& cookies);
198   void GetCookieListAsyncHelper(const GURL& host,
199                                 net::CookieList* result,
200                                 base::OnceClosure complete);
201   void GetCookieListCompleted(
202       base::OnceClosure complete,
203       net::CookieList* result,
204       const net::CookieAccessResultList& value,
205       const net::CookieAccessResultList& excluded_cookies);
206 
207   void RemoveSessionCookiesHelper(base::OnceCallback<void(bool)> callback);
208   void RemoveAllCookiesHelper(base::OnceCallback<void(bool)> callback);
209   void RemoveCookiesCompleted(base::OnceCallback<void(bool)> callback,
210                               uint32_t num_deleted);
211 
212   void FlushCookieStoreAsyncHelper(base::OnceClosure complete);
213 
214   void SetMojoCookieManagerAsync(
215       mojo::PendingRemote<network::mojom::CookieManager> cookie_manager_remote,
216       base::OnceClosure complete);
217   void SwapMojoCookieManagerAsync(
218       mojo::PendingRemote<network::mojom::CookieManager> cookie_manager_remote,
219       base::OnceClosure complete);
220 
221   void HasCookiesAsyncHelper(bool* result, base::OnceClosure complete);
222   void HasCookiesCompleted(base::OnceClosure complete,
223                            bool* result,
224                            const net::CookieList& cookies);
225 
226   void SetAllowFileSchemeCookiesAsyncHelper(bool allow,
227                                             base::OnceClosure complete);
228   // |can_change_schemes| indicates whether or not this call was successful,
229   // indicating whether we may update |allow_file_scheme_cookies_|.
230   void SetAllowFileSchemeCookiesCompleted(base::OnceClosure complete,
231                                           bool allow,
232                                           bool can_change_schemes);
233   void MigrateCookieStorePath();
234 
235   base::FilePath cookie_store_path_;
236 
237   // This protects the following bool, as it's used on multiple threads.
238   base::Lock allow_file_scheme_cookies_lock_;
239   // True if cookies should be allowed for file URLs. Can only be changed prior
240   // to creating the CookieStore.
241   bool allow_file_scheme_cookies_ GUARDED_BY(allow_file_scheme_cookies_lock_);
242   // True once the cookie store has been created. Just used to track when
243   // |allow_file_scheme_cookies_| can no longer be modified. Only accessed on
244   // |cookie_store_task_runner_|.
245   bool cookie_store_created_;
246 
247   // Whether or not to workaround 'Secure' cookies set on insecure URLs. See
248   // MaybeFixUpSchemeForSecureCookieAndGetSameSite. Only accessed on
249   // |cookie_store_task_runner_|. Defaults to false starting for apps targeting
250   // >= R.
251   bool workaround_http_secure_cookies_;
252 
253   base::Thread cookie_store_client_thread_;
254   base::Thread cookie_store_backend_thread_;
255 
256   scoped_refptr<base::SingleThreadTaskRunner> cookie_store_task_runner_;
257   std::unique_ptr<net::CookieStore> cookie_store_;
258 
259   // Tracks if we're in the middle of a call to SetMojoCookieManager(). See the
260   // note in SetMojoCookieManager(). Must only be accessed on
261   // |cookie_store_task_runner_|.
262   bool setting_new_mojo_cookie_manager_;
263 
264   // |tasks_| is a queue we manage, to allow us to delay tasks until after
265   // SetMojoCookieManager()'s work is done. This is modified on different
266   // threads, so accesses must be guarded by |task_queue_lock_|.
267   base::Lock task_queue_lock_;
268   base::circular_deque<base::OnceClosure> tasks_ GUARDED_BY(task_queue_lock_);
269 
270   // The CookieManager shared with the NetworkContext.
271   mojo::Remote<network::mojom::CookieManager> mojo_cookie_manager_;
272 
273   DISALLOW_COPY_AND_ASSIGN(CookieManager);
274 };
275 
276 }  // namespace android_webview
277 
278 #endif  // ANDROID_WEBVIEW_BROWSER_COOKIE_MANAGER_H_
279