// Copyright 2019 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/web/download/download_session_cookie_storage.h"
#import "base/notreached.h"
#import "ios/net/cookies/system_cookie_util.h"
#import "net/base/apple/url_conversions.h"
#import "net/cookies/canonical_cookie.h"
#import "net/cookies/cookie_constants.h"
@implementation DownloadSessionCookieStorage {
__strong NSMutableArray<NSHTTPCookie*>* _cookies;
NSHTTPCookieAcceptPolicy _cookieAcceptPolicy;
}
- (instancetype)init {
return [self initWithCookies:nil
cookieAcceptPolicy:NSHTTPCookieAcceptPolicyAlways];
}
- (instancetype)initWithCookies:(NSArray<NSHTTPCookie*>*)cookies
cookieAcceptPolicy:(NSHTTPCookieAcceptPolicy)cookieAcceptPolicy {
if ((self = [super init])) {
_cookieAcceptPolicy = cookieAcceptPolicy;
if (cookies && _cookieAcceptPolicy != NSHTTPCookieAcceptPolicyNever) {
_cookies = [cookies mutableCopy];
} else {
_cookies = [[NSMutableArray alloc] init];
}
}
return self;
}
// This method assumes that it will be called with valid cookies, with no
// repeated cookies and no expired cookies.
- (void)setCookie:(NSHTTPCookie*)cookie {
if (self.cookieAcceptPolicy == NSHTTPCookieAcceptPolicyNever) {
return;
}
[_cookies addObject:cookie];
}
- (void)deleteCookie:(NSHTTPCookie*)cookie {
NOTREACHED_IN_MIGRATION();
}
- (NSArray<NSHTTPCookie*>*)cookiesForURL:(NSURL*)URL {
NSMutableArray<NSHTTPCookie*>* result = [NSMutableArray array];
GURL gURL = net::GURLWithNSURL(URL);
// TODO(crbug.com/40104865): Compute the cookie access semantic, and update
// `options` with it.
net::CookieOptions options = net::CookieOptions::MakeAllInclusive();
net::CookieAccessSemantics cookieAccessSemantics =
net::CookieAccessSemantics::LEGACY;
// No extra trustworthy URLs.
bool delegate_treats_url_as_trustworthy = false;
// Using `UNKNOWN` semantics to allow the experiment to switch between non
// legacy (where cookies that don't have a specific same-site access policy
// and not secure will not be included), and legacy mode.
cookieAccessSemantics = net::CookieAccessSemantics::UNKNOWN;
net::CookieAccessParams params = {cookieAccessSemantics,
delegate_treats_url_as_trustworthy};
for (NSHTTPCookie* cookie in self.cookies) {
std::unique_ptr<net::CanonicalCookie> canonical_cookie =
net::CanonicalCookieFromSystemCookie(cookie, base::Time());
if (canonical_cookie->IncludeForRequestURL(gURL, options, params)
.status.IsInclude())
[result addObject:cookie];
}
return [result copy];
}
- (void)setCookies:(NSArray<NSHTTPCookie*>*)cookies
forURL:(NSURL*)URL
mainDocumentURL:(NSURL*)mainDocumentURL {
if (self.cookieAcceptPolicy == NSHTTPCookieAcceptPolicyNever) {
return;
}
if (self.cookieAcceptPolicy ==
NSHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain) {
if (!mainDocumentURL.host ||
![[@"." stringByAppendingString:URL.host]
hasSuffix:[@"." stringByAppendingString:mainDocumentURL.host]]) {
return;
}
}
[_cookies addObjectsFromArray:cookies];
}
- (void)storeCookies:(NSArray<NSHTTPCookie*>*)cookies
forTask:(NSURLSessionTask*)task {
[self setCookies:cookies
forURL:task.currentRequest.URL
mainDocumentURL:task.currentRequest.mainDocumentURL];
}
- (void)getCookiesForTask:(NSURLSessionTask*)task
completionHandler:(void (^)(NSArray<NSHTTPCookie*>* _Nullable cookies))
completionHandler {
if (completionHandler)
completionHandler([self cookiesForURL:task.currentRequest.URL]);
}
#pragma mark - NSHTTPCookieStorage Properties
- (NSArray<NSHTTPCookie*>*)cookies {
return [_cookies copy];
}
- (NSHTTPCookieAcceptPolicy)cookieAcceptPolicy {
return _cookieAcceptPolicy;
}
- (void)setCookieAcceptPolicy:(NSHTTPCookieAcceptPolicy)cookieAcceptPolicy {
_cookieAcceptPolicy = cookieAcceptPolicy;
}
@end