|  | // Copyright 2012 The Chromium Authors | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #import "ios/components/cookie_util/cookie_util.h" | 
|  |  | 
|  | #import <Foundation/Foundation.h> | 
|  | #import <stddef.h> | 
|  | #import <stdint.h> | 
|  | #import <sys/sysctl.h> | 
|  |  | 
|  | #import "base/check.h" | 
|  | #import "base/functional/bind.h" | 
|  | #import "base/functional/callback_helpers.h" | 
|  | #import "base/memory/ref_counted.h" | 
|  | #import "base/task/thread_pool.h" | 
|  | #import "components/prefs/pref_service.h" | 
|  | #import "ios/components/cookie_util/cookie_constants.h" | 
|  | #import "ios/net/cookies/cookie_store_ios.h" | 
|  | #import "ios/net/cookies/system_cookie_store.h" | 
|  | #import "ios/web/common/features.h" | 
|  | #import "ios/web/public/browser_state.h" | 
|  | #import "ios/web/public/thread/web_task_traits.h" | 
|  | #import "ios/web/public/thread/web_thread.h" | 
|  | #import "net/cookies/cookie_monster.h" | 
|  | #import "net/cookies/cookie_store.h" | 
|  | #import "net/extras/sqlite/sqlite_persistent_cookie_store.h" | 
|  | #import "net/log/net_log.h" | 
|  | #import "net/url_request/url_request_context.h" | 
|  | #import "net/url_request/url_request_context_getter.h" | 
|  |  | 
|  | namespace cookie_util { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | // Creates a SQLitePersistentCookieStore running on a background thread. | 
|  | scoped_refptr<net::SQLitePersistentCookieStore> CreatePersistentCookieStore( | 
|  | const base::FilePath& path, | 
|  | bool restore_old_session_cookies) { | 
|  | return scoped_refptr<net::SQLitePersistentCookieStore>( | 
|  | new net::SQLitePersistentCookieStore( | 
|  | path, web::GetIOThreadTaskRunner({}), | 
|  | base::ThreadPool::CreateSequencedTaskRunner( | 
|  | {base::MayBlock(), base::TaskPriority::BEST_EFFORT, | 
|  | base::TaskShutdownBehavior::BLOCK_SHUTDOWN}), | 
|  | restore_old_session_cookies, /*crypto_delegate=*/nullptr, | 
|  | /*enable_exclusive_access=*/false)); | 
|  | } | 
|  |  | 
|  | // Creates a CookieMonster configured by `config`. | 
|  | std::unique_ptr<net::CookieMonster> CreateCookieMonster( | 
|  | const CookieStoreConfig& config, | 
|  | net::NetLog* net_log) { | 
|  | if (config.path.empty()) { | 
|  | // Empty path means in-memory store. | 
|  | return std::make_unique<net::CookieMonster>(nullptr /* store */, net_log); | 
|  | } | 
|  |  | 
|  | const bool restore_old_session_cookies = | 
|  | config.session_cookie_mode == CookieStoreConfig::RESTORED_SESSION_COOKIES; | 
|  | scoped_refptr<net::SQLitePersistentCookieStore> persistent_store = | 
|  | CreatePersistentCookieStore(config.path, restore_old_session_cookies); | 
|  | std::unique_ptr<net::CookieMonster> cookie_monster( | 
|  | new net::CookieMonster(persistent_store.get(), net_log)); | 
|  | if (restore_old_session_cookies) { | 
|  | cookie_monster->SetPersistSessionCookies(true); | 
|  | } | 
|  | return cookie_monster; | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | CookieStoreConfig::CookieStoreConfig(const base::FilePath& path, | 
|  | SessionCookieMode session_cookie_mode, | 
|  | CookieStoreType cookie_store_type) | 
|  | : path(path), | 
|  | session_cookie_mode(session_cookie_mode), | 
|  | cookie_store_type(cookie_store_type) { | 
|  | CHECK(!path.empty() || session_cookie_mode == EPHEMERAL_SESSION_COOKIES); | 
|  | } | 
|  |  | 
|  | CookieStoreConfig::~CookieStoreConfig() {} | 
|  |  | 
|  | std::unique_ptr<net::CookieStore> CreateCookieStore( | 
|  | const CookieStoreConfig& config, | 
|  | std::unique_ptr<net::SystemCookieStore> system_cookie_store, | 
|  | net::NetLog* net_log) { | 
|  | if (config.cookie_store_type == CookieStoreConfig::COOKIE_MONSTER) { | 
|  | return CreateCookieMonster(config, net_log); | 
|  | } | 
|  |  | 
|  | // Using the SystemCookieStore will allow URLFetcher and any other users of | 
|  | // net:CookieStore to in iOS to use cookies directly from WKHTTPCookieStore. | 
|  | return std::make_unique<net::CookieStoreIOS>(std::move(system_cookie_store), | 
|  | net_log); | 
|  | } | 
|  |  | 
|  | bool ShouldClearSessionCookies(PrefService* pref_service) { | 
|  | const base::Time last_cookie_deletion_date = | 
|  | pref_service->GetTime(kLastCookieDeletionDate); | 
|  |  | 
|  | bool clear_cookies = true; | 
|  | if (!last_cookie_deletion_date.is_null()) { | 
|  | struct timeval boottime; | 
|  | int mib[2] = {CTL_KERN, KERN_BOOTTIME}; | 
|  | size_t size = sizeof(boottime); | 
|  |  | 
|  | if (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1) { | 
|  | if (boottime.tv_sec != 0) { | 
|  | const base::Time boot = base::Time::FromTimeVal(boottime); | 
|  |  | 
|  | clear_cookies = boot > last_cookie_deletion_date; | 
|  | } | 
|  | } | 
|  | } | 
|  | if (clear_cookies) { | 
|  | pref_service->SetTime(kLastCookieDeletionDate, base::Time::Now()); | 
|  | } | 
|  | return clear_cookies; | 
|  | } | 
|  |  | 
|  | // Clears the session cookies for `browser_state`. | 
|  | void ClearSessionCookies(web::BrowserState* browser_state) { | 
|  | scoped_refptr<net::URLRequestContextGetter> getter = | 
|  | browser_state->GetRequestContext(); | 
|  | web::GetIOThreadTaskRunner({})->PostTask( | 
|  | FROM_HERE, base::BindOnce(^{ | 
|  | net::CookieStore* cookie_store = | 
|  | getter->GetURLRequestContext()->cookie_store(); | 
|  | if (cookie_store) { | 
|  | cookie_store->DeleteSessionCookiesAsync(base::DoNothing()); | 
|  | } | 
|  | })); | 
|  | } | 
|  |  | 
|  | }  // namespace cookie_util |