| // 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 <stddef.h> |
| |
| #include "base/logging.h" |
| #include "base/metrics/histogram_macros.h" |
| #include "base/strings/sys_string_conversions.h" |
| #include "net/cookies/cookie_constants.h" |
| #include "url/gurl.h" |
| #include "url/third_party/mozilla/url_parse.h" |
| |
| #if !defined(__has_feature) || !__has_feature(objc_arc) |
| #error "This file requires ARC support." |
| #endif |
| |
| namespace net { |
| |
| namespace { |
| |
| // Undocumented property of NSHTTPCookie. |
| NSString* const kNSHTTPCookieHttpOnly = @"HttpOnly"; |
| |
| // Possible value for SameSite policy. WebKit doesn't use the value "none" or |
| // any other value, it uses the empty value to represent none, and any value |
| // that is not "strict" or "lax" will be considered as none. |
| NSString* const kNSHTTPCookieSameSiteNone = @"none"; |
| |
| } // namespace |
| |
| // Converts NSHTTPCookie to net::CanonicalCookie. |
| std::unique_ptr<net::CanonicalCookie> CanonicalCookieFromSystemCookie( |
| NSHTTPCookie* cookie, |
| const base::Time& ceation_time) { |
| net::CookieSameSite same_site = net::CookieSameSite::NO_RESTRICTION; |
| if (@available(iOS 13, *)) { |
| same_site = net::CookieSameSite::UNSPECIFIED; |
| if ([cookie.sameSitePolicy isEqual:NSHTTPCookieSameSiteLax]) |
| same_site = net::CookieSameSite::LAX_MODE; |
| |
| if ([cookie.sameSitePolicy isEqual:NSHTTPCookieSameSiteStrict]) |
| same_site = net::CookieSameSite::STRICT_MODE; |
| |
| if ([[cookie.sameSitePolicy lowercaseString] |
| isEqual:kNSHTTPCookieSameSiteNone]) |
| same_site = net::CookieSameSite::NO_RESTRICTION; |
| } |
| |
| return net::CanonicalCookie::FromStorage( |
| 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], same_site, |
| // When iOS begins to support 'Priority' and 'SameParty' attributes, pass |
| // them through here. |
| net::COOKIE_PRIORITY_DEFAULT, false /* SameParty */, |
| absl::nullopt /* partition_key */, net::CookieSourceScheme::kUnset, |
| url::PORT_UNSPECIFIED); |
| } |
| |
| void ReportGetCookiesForURLResult(SystemCookieStoreType store_type, |
| bool has_cookies) { |
| GetCookiesForURLCallResult call_result = |
| GetCookiesForURLCallResult::kCookiesFoundOnWKHTTPSystemCookieStore; |
| switch (store_type) { |
| case SystemCookieStoreType::kWKHTTPSystemCookieStore: |
| call_result = |
| has_cookies |
| ? GetCookiesForURLCallResult:: |
| kCookiesFoundOnWKHTTPSystemCookieStore |
| : GetCookiesForURLCallResult::kNoCookiesOnWKHTTPSystemCookieStore; |
| break; |
| case SystemCookieStoreType::kNSHTTPSystemCookieStore: |
| call_result = |
| has_cookies |
| ? GetCookiesForURLCallResult:: |
| kCookiesFoundOnNSHTTPSystemCookieStore |
| : GetCookiesForURLCallResult::kNoCookiesOnNSHTTPSystemCookieStore; |
| |
| break; |
| case SystemCookieStoreType::kCookieMonster: |
| call_result = |
| has_cookies ? GetCookiesForURLCallResult::kCookiesFoundOnCookieMonster |
| : GetCookiesForURLCallResult::kNoCookiesOnCookieMonster; |
| break; |
| } |
| UMA_HISTOGRAM_ENUMERATION("IOS.Cookies.GetCookiesForURLCallResult", |
| call_result); |
| } |
| |
| void ReportGetCookiesForURLCall(SystemCookieStoreType store_type) { |
| UMA_HISTOGRAM_ENUMERATION("IOS.Cookies.GetCookiesForURLCallStoreType", |
| store_type); |
| } |
| |
| // 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 (@available(iOS 13, *)) { |
| // In iOS 13 sameSite property in NSHTTPCookie is used to specify the |
| // samesite policy. |
| NSString* same_site = @""; |
| switch (cookie.SameSite()) { |
| case net::CookieSameSite::LAX_MODE: |
| same_site = NSHTTPCookieSameSiteLax; |
| break; |
| case net::CookieSameSite::STRICT_MODE: |
| same_site = NSHTTPCookieSameSiteStrict; |
| break; |
| case net::CookieSameSite::NO_RESTRICTION: |
| same_site = kNSHTTPCookieSameSiteNone; |
| break; |
| case net::CookieSameSite::UNSPECIFIED: |
| // All other values of same site policy will be treated as no value . |
| break; |
| } |
| properties[NSHTTPCookieSameSitePolicy] = same_site; |
| } |
| |
| 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; |
| } |
| |
| NSArray<NSHTTPCookie*>* SystemCookiesFromCanonicalCookieList( |
| const net::CookieList& cookie_list) { |
| NSMutableArray<NSHTTPCookie*>* cookies = [[NSMutableArray alloc] init]; |
| for (const net::CanonicalCookie& cookie : cookie_list) { |
| [cookies addObject:net::SystemCookieFromCanonicalCookie(cookie)]; |
| } |
| return [cookies copy]; |
| } |
| |
| } // namespace net |