From 68fc3715f76e3da9131b035ddd9606dfee6180bd Mon Sep 17 00:00:00 2001 From: droger Date: Thu, 10 Sep 2015 04:05:57 -0700 Subject: [PATCH] [iOS] Upstream cookie utils Review URL: https://codereview.chromium.org/1329403002 Cr-Commit-Position: refs/heads/master@{#348135} --- ios/chrome/browser/net/cookie_util.h | 89 ++++++++++++++++++ ios/chrome/browser/net/cookie_util.mm | 125 +++++++++++++++++++++++++ ios/chrome/browser/net/cookie_util_unittest.mm | 39 ++++++++ ios/chrome/ios_chrome.gyp | 2 + ios/chrome/ios_chrome_tests.gyp | 1 + 5 files changed, 256 insertions(+) create mode 100644 ios/chrome/browser/net/cookie_util.h create mode 100644 ios/chrome/browser/net/cookie_util.mm create mode 100644 ios/chrome/browser/net/cookie_util_unittest.mm diff --git a/ios/chrome/browser/net/cookie_util.h b/ios/chrome/browser/net/cookie_util.h new file mode 100644 index 000000000000..1b85e04f22b3 --- /dev/null +++ b/ios/chrome/browser/net/cookie_util.h @@ -0,0 +1,89 @@ +// Copyright 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_NET_COOKIE_UTIL_H_ +#define IOS_CHROME_BROWSER_NET_COOKIE_UTIL_H_ + +#include "base/files/file_path.h" +#include "base/memory/ref_counted.h" +#include "net/cookies/canonical_cookie.h" + +namespace base { +class SequencedTaskRunner; +} + +namespace ios { +class ChromeBrowserState; +} + +namespace net { +class CookieCryptoDelegate; +class CookieStore; +} + +namespace cookie_util { + +// Configuration for creation of new cookie stores. +struct CookieStoreConfig { + // Specifies how session cookies are persisted in the backing data store. + // + // EPHEMERAL_SESSION_COOKIES specifies session cookies will not be written + // out in a manner that allows for restoration. + // + // RESTORED_SESSION_COOKIES specifies that session cookies are written in a + // manner that allows for them to be restored if the cookie store is opened + // again using RESTORED_SESSION_COOKIES. + enum SessionCookieMode { + EPHEMERAL_SESSION_COOKIES, + RESTORED_SESSION_COOKIES + }; + + // Persistent cookie stores can either be CookieMonster or CookieStoreIOS. + // The CookieMonster is the cross-platform implementation and should be + // preferred in general. + // The CookieStoreIOS must be used when the cookie store is accessed by the + // system through UIWebView. However, note that only one CookieStoreIOS + // instance can be kept synchronized with the global system cookie store at a + // time. + enum CookieStoreType { + COOKIE_MONSTER, // CookieMonster backend. + COOKIE_STORE_IOS // CookieStoreIOS backend. + }; + + // If |path| is empty, then this specifies an in-memory cookie store. + // With in-memory cookie stores, |session_cookie_mode| must be + // EPHEMERAL_SESSION_COOKIES. + // Note: If |crypto_delegate| is non-null, it must outlive any CookieStores + // created using this config. + CookieStoreConfig(const base::FilePath& path, + SessionCookieMode session_cookie_mode, + CookieStoreType cookie_store_type, + net::CookieCryptoDelegate* crypto_delegate); + ~CookieStoreConfig(); + + const base::FilePath path; + const SessionCookieMode session_cookie_mode; + const CookieStoreType cookie_store_type; + + // Used to provide encryption hooks for the cookie store. The + // CookieCryptoDelegate must outlive any cookie store created with this + // config. + net::CookieCryptoDelegate* crypto_delegate; +}; + +// Creates a cookie store wich is internally either a CookieMonster or a +// CookieStoreIOS. +net::CookieStore* CreateCookieStore(const CookieStoreConfig& config); + +// Returns true if the cookies should be cleared. +// Current implementation returns true if the device has rebooted since the +// last time cookies have been cleared. +bool ShouldClearSessionCookies(); + +// Clears the session cookies for |browser_state|. +void ClearSessionCookies(ios::ChromeBrowserState* browser_state); + +} // namespace cookie_util + +#endif // IOS_CHROME_BROWSER_NET_COOKIE_UTIL_H_ diff --git a/ios/chrome/browser/net/cookie_util.mm b/ios/chrome/browser/net/cookie_util.mm new file mode 100644 index 000000000000..5dac5f6d5136 --- /dev/null +++ b/ios/chrome/browser/net/cookie_util.mm @@ -0,0 +1,125 @@ +// Copyright 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ios/chrome/browser/net/cookie_util.h" + +#import +#include + +#include "base/logging.h" +#import "base/mac/bind_objc_block.h" +#include "base/memory/ref_counted.h" +#include "ios/net/cookies/cookie_store_ios.h" +#include "ios/public/provider/chrome/browser/browser_state/chrome_browser_state.h" +#include "ios/web/public/web_thread.h" +#include "net/cookies/cookie_monster.h" +#include "net/cookies/cookie_store.h" +#include "net/extras/sqlite/sqlite_persistent_cookie_store.h" +#include "net/url_request/url_request_context.h" +#include "net/url_request/url_request_context_getter.h" + +namespace cookie_util { + +namespace { + +// Date of the last cookie deletion. +NSString* const kLastCookieDeletionDate = @"LastCookieDeletionDate"; + +// Empty callback. +void DoNothing(int n) {} + +// Creates a SQLitePersistentCookieStore running on a background thread. +scoped_refptr CreatePersistentCookieStore( + const base::FilePath& path, + bool restore_old_session_cookies, + net::CookieCryptoDelegate* crypto_delegate) { + return scoped_refptr( + new net::SQLitePersistentCookieStore( + path, web::WebThread::GetTaskRunnerForThread(web::WebThread::IO), + web::WebThread::GetBlockingPool()->GetSequencedTaskRunner( + web::WebThread::GetBlockingPool()->GetSequenceToken()), + restore_old_session_cookies, crypto_delegate)); +} + +// Creates a CookieMonster configured by |config|. +net::CookieMonster* CreateCookieMonster(const CookieStoreConfig& config) { + if (config.path.empty()) { + // Empty path means in-memory store. + return new net::CookieMonster(nullptr, nullptr); + } + + const bool restore_old_session_cookies = + config.session_cookie_mode == CookieStoreConfig::RESTORED_SESSION_COOKIES; + scoped_refptr persistent_store = + CreatePersistentCookieStore(config.path, restore_old_session_cookies, + config.crypto_delegate); + net::CookieMonster* cookie_monster = + new net::CookieMonster(persistent_store.get(), nullptr); + 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, + net::CookieCryptoDelegate* crypto_delegate) + : path(path), + session_cookie_mode(session_cookie_mode), + cookie_store_type(cookie_store_type), + crypto_delegate(crypto_delegate) { + CHECK(!path.empty() || session_cookie_mode == EPHEMERAL_SESSION_COOKIES); +} + +CookieStoreConfig::~CookieStoreConfig() {} + +net::CookieStore* CreateCookieStore(const CookieStoreConfig& config) { + if (config.cookie_store_type == CookieStoreConfig::COOKIE_MONSTER) + return CreateCookieMonster(config); + + scoped_refptr persistent_store = nullptr; + if (config.session_cookie_mode == + CookieStoreConfig::RESTORED_SESSION_COOKIES) { + DCHECK(!config.path.empty()); + persistent_store = CreatePersistentCookieStore( + config.path, true /* restore_old_session_cookies */, + config.crypto_delegate); + } + return new net::CookieStoreIOS(persistent_store.get()); +} + +bool ShouldClearSessionCookies() { + NSUserDefaults* standardDefaults = [NSUserDefaults standardUserDefaults]; + struct timeval boottime; + int mib[2] = {CTL_KERN, KERN_BOOTTIME}; + size_t size = sizeof(boottime); + time_t lastCookieDeletionDate = + [standardDefaults integerForKey:kLastCookieDeletionDate]; + time_t now; + time(&now); + bool clear_cookies = true; + if (lastCookieDeletionDate != 0 && + sysctl(mib, 2, &boottime, &size, NULL, 0) != -1 && boottime.tv_sec != 0) { + clear_cookies = boottime.tv_sec > lastCookieDeletionDate; + } + if (clear_cookies) + [standardDefaults setInteger:now forKey:kLastCookieDeletionDate]; + return clear_cookies; +} + +// Clears the session cookies for |profile|. +void ClearSessionCookies(ios::ChromeBrowserState* browser_state) { + scoped_refptr getter = + browser_state->GetRequestContext(); + web::WebThread::PostTask( + web::WebThread::IO, FROM_HERE, base::BindBlock(^{ + getter->GetURLRequestContext() + ->cookie_store() + ->DeleteSessionCookiesAsync(base::Bind(&DoNothing)); + })); +} + +} // namespace cookie_util diff --git a/ios/chrome/browser/net/cookie_util_unittest.mm b/ios/chrome/browser/net/cookie_util_unittest.mm new file mode 100644 index 000000000000..c2611d7c70c7 --- /dev/null +++ b/ios/chrome/browser/net/cookie_util_unittest.mm @@ -0,0 +1,39 @@ +// Copyright 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ios/chrome/browser/net/cookie_util.h" + +#import + +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +// Date of the last cookie deletion. +NSString* const kLastCookieDeletionDate = @"LastCookieDeletionDate"; + +} // namespace + +TEST(CookieUtil, ShouldClearSessionCookies) { + time_t start_test_time; + time(&start_test_time); + NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; + // Delete cookies if the key is not present. + [defaults removeObjectForKey:kLastCookieDeletionDate]; + EXPECT_TRUE(cookie_util::ShouldClearSessionCookies()); + // The deletion time should be created. + time_t deletion_time = [defaults integerForKey:kLastCookieDeletionDate]; + time_t now; + time(&now); + EXPECT_LE(start_test_time, deletion_time); + EXPECT_LE(deletion_time, now); + // Cookies are not deleted again. + EXPECT_FALSE(cookie_util::ShouldClearSessionCookies()); + + // Set the deletion time before the machine was started. + // Sometime in year 1980. + [defaults setInteger:328697227 forKey:kLastCookieDeletionDate]; + EXPECT_TRUE(cookie_util::ShouldClearSessionCookies()); + EXPECT_LE(now, [defaults integerForKey:kLastCookieDeletionDate]); +} diff --git a/ios/chrome/ios_chrome.gyp b/ios/chrome/ios_chrome.gyp index 7eb7f8aed194..3d0a046943e7 100644 --- a/ios/chrome/ios_chrome.gyp +++ b/ios/chrome/ios_chrome.gyp @@ -284,6 +284,8 @@ 'browser/net/chrome_cookie_store_ios_client.mm', 'browser/net/connection_type_observer_bridge.h', 'browser/net/connection_type_observer_bridge.mm', + 'browser/net/cookie_util.h', + 'browser/net/cookie_util.mm', 'browser/net/http_server_properties_manager_factory.cc', 'browser/net/http_server_properties_manager_factory.h', 'browser/net/image_fetcher.h', diff --git a/ios/chrome/ios_chrome_tests.gyp b/ios/chrome/ios_chrome_tests.gyp index 2847f312a555..c7409236fb86 100644 --- a/ios/chrome/ios_chrome_tests.gyp +++ b/ios/chrome/ios_chrome_tests.gyp @@ -43,6 +43,7 @@ 'browser/installation_notifier_unittest.mm', 'browser/metrics/previous_session_info_unittest.mm', 'browser/metrics/ios_stability_metrics_provider_unittest.mm', + 'browser/net/cookie_util_unittest.mm', 'browser/net/image_fetcher_unittest.mm', 'browser/net/metrics_network_client_unittest.mm', 'browser/net/retryable_url_fetcher_unittest.mm', -- 2.11.4.GIT