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