Index: ios/net/cookies/system_cookie_util.mm |
diff --git a/ios/net/cookies/system_cookie_util.mm b/ios/net/cookies/system_cookie_util.mm |
new file mode 100644 |
index 0000000000000000000000000000000000000000..5414e0f7894e514f143325c711c977b85ef492ab |
--- /dev/null |
+++ b/ios/net/cookies/system_cookie_util.mm |
@@ -0,0 +1,153 @@ |
+// Copyright 2014 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/net/cookies/system_cookie_util.h" |
+ |
+#import <Foundation/Foundation.h> |
+ |
+#include "base/logging.h" |
+#include "base/metrics/histogram.h" |
+#include "base/strings/stringprintf.h" |
+#include "base/strings/sys_string_conversions.h" |
+#include "net/cookies/cookie_constants.h" |
+#include "url/gurl.h" |
+ |
+namespace net { |
+ |
+namespace { |
+ |
+// Used to report cookie loss events in UMA. |
+enum CookieLossType { |
+ LOSS, |
+ NOT_ENOUGH_COOKIES, // Not enough cookies, error checking is disabled. |
+ NO_LOSS, |
+ COOKIE_LOSS_ENUM_COUNT |
+}; |
+ |
+// Undocumented property of NSHTTPCookie. |
+NSString* const kNSHTTPCookieHttpOnly = @"HttpOnly"; |
+ |
+// Key in NSUserDefaults telling wether a low cookie count must be reported as |
+// an error. |
+NSString* const kCheckCookieLossKey = @"CookieUtilIOSCheckCookieLoss"; |
+ |
+// When the cookie count reaches |kCookieThresholdHigh|, and then drops below |
+// |kCookieThresholdLow|, an error is reported. |
+// Cookies count immediately after installation may fluctuate due to session |
+// cookies that can expire quickly. In order to catch true cookie loss, it is |
+// better to wait till a sufficiently large number of cookies have been |
+// accumulated before checking for sudden drop in cookies count. |
+const size_t kCookieThresholdHigh = 100; |
+const size_t kCookieThresholdLow = 30; |
+ |
+// Updates the cookie loss histograms. |
+// |event| determines which histogram is updated, and |loss| is the value to add |
+// to this histogram. |
+void ReportUMACookieLoss(CookieLossType loss, CookieEvent event) { |
+ // Histogram macros require constant histogram names. Use the string constants |
+ // explicitly instead of using a variable. |
+ switch (event) { |
+ case COOKIES_READ: |
+ UMA_HISTOGRAM_ENUMERATION("CookieStoreIOS.LossOnRead", loss, |
+ COOKIE_LOSS_ENUM_COUNT); |
+ break; |
+ case COOKIES_APPLICATION_FOREGROUNDED: |
+ UMA_HISTOGRAM_ENUMERATION("CookieStoreIOS.LossOnForegrounding", loss, |
+ COOKIE_LOSS_ENUM_COUNT); |
+ break; |
+ } |
+} |
+ |
+} // namespace |
+ |
+// Converts NSHTTPCookie to net::CanonicalCookie. |
+net::CanonicalCookie CanonicalCookieFromSystemCookie( |
+ NSHTTPCookie* cookie, |
+ const base::Time& ceation_time) { |
+ return net::CanonicalCookie( |
+ GURL(), base::SysNSStringToUTF8([cookie name]), |
+ base::SysNSStringToUTF8([cookie value]), |
+ base::SysNSStringToUTF8([cookie domain]), |
+ base::SysNSStringToUTF8([cookie path]), ceation_time, |
+ base::Time::FromDoubleT([[cookie expiresDate] timeIntervalSince1970]), |
+ base::Time(), [cookie isSecure], [cookie isHTTPOnly], false, |
+ net::COOKIE_PRIORITY_DEFAULT); |
+} |
+ |
+// Converts net::CanonicalCookie to NSHTTPCookie. |
+NSHTTPCookie* SystemCookieFromCanonicalCookie( |
+ const net::CanonicalCookie& cookie) { |
+ NSString* cookie_domain = base::SysUTF8ToNSString(cookie.Domain()); |
+ NSString* cookie_name = base::SysUTF8ToNSString(cookie.Name()); |
+ NSString* cookie_path = base::SysUTF8ToNSString(cookie.Path()); |
+ NSString* cookie_value = base::SysUTF8ToNSString(cookie.Value()); |
+ if (!cookie_domain || !cookie_name || !cookie_path || !cookie_value) { |
+ DLOG(ERROR) << "Cannot create system cookie: " << cookie.DebugString(); |
+ return nil; |
+ } |
+ NSMutableDictionary* properties = |
+ [NSMutableDictionary dictionaryWithDictionary:@{ |
+ NSHTTPCookieDomain : cookie_domain, |
+ NSHTTPCookieName : cookie_name, |
+ NSHTTPCookiePath : cookie_path, |
+ NSHTTPCookieValue : cookie_value, |
+ }]; |
+ if (cookie.IsPersistent()) { |
+ NSDate* expiry = |
+ [NSDate dateWithTimeIntervalSince1970:cookie.ExpiryDate().ToDoubleT()]; |
+ [properties setObject:expiry forKey:NSHTTPCookieExpires]; |
+ } |
+ if (cookie.IsSecure()) |
+ [properties setObject:@"Y" forKey:NSHTTPCookieSecure]; |
+ if (cookie.IsHttpOnly()) |
+ [properties setObject:@YES forKey:kNSHTTPCookieHttpOnly]; |
+ NSHTTPCookie* system_cookie = [NSHTTPCookie cookieWithProperties:properties]; |
+ DCHECK(system_cookie); |
+ return system_cookie; |
+} |
+ |
+void CheckForCookieLoss(size_t cookie_count, CookieEvent event) { |
+ NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; |
+ BOOL check_cookie_loss = [defaults boolForKey:kCheckCookieLossKey]; |
+ |
+ // Start reporting errors if the cookie count goes above kCookieThresholdHigh. |
+ if (!check_cookie_loss && cookie_count >= kCookieThresholdHigh) { |
+ [defaults setBool:YES forKey:kCheckCookieLossKey]; |
+ [defaults synchronize]; |
+ return; |
+ } |
+ |
+ if (!check_cookie_loss) { |
+ // Error reporting is disabled. |
+ ReportUMACookieLoss(NOT_ENOUGH_COOKIES, event); |
+ return; |
+ } |
+ |
+ if (cookie_count > kCookieThresholdLow) { |
+ // No cookie loss. |
+ ReportUMACookieLoss(NO_LOSS, event); |
+ return; |
+ } |
+ |
+#if 0 |
+ // TODO(ios): [Merge 277884]: crbug.com/386074 ERROR_REPORT is no longer |
+ // supported. |
+ LOG(ERROR_REPORT) << "Possible cookie issue (crbug/370024)\nCookie count: " |
+ << cookie_count; |
+#endif |
+ |
+ ReportUMACookieLoss(LOSS, event); |
+ |
+ // Disable reporting until the cookie count rises above kCookieThresholdHigh |
+ // again. |
+ ResetCookieCountMetrics(); |
+} |
+ |
+void ResetCookieCountMetrics() { |
+ NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; |
+ [defaults setBool:NO forKey:kCheckCookieLossKey]; |
+ [defaults synchronize]; |
+} |
+ |
+} // namespace net |