If you realize the usage of cookie, the server has to send the header Set-Cookie
in response to the client request. Just inspect the header in response and you will see Set-Cookie
header field with cookie in it.
https://en.wikipedia.org/wiki/HTTP_cookie#Setting_a_cookie
If you use URLSession with default or background URLSessionConfiguration
, you dont have to make any change to save cookie. If you look at documentation for default URLSessionConfiguration
, which describes it like this,
The default session configuration uses a persistent disk-based cache
(except when the result is downloaded to a file) and stores
credentials in the user’s keychain. It also stores cookies (by
default) in the same shared cookie store as the NSURLConnection and
NSURLDownload classes.
Also, you can read further about this in URLSessionConfiguration
documentation for property httpCookieStorage
here.
Here is a small snippet of code that I will use further to test the cookie storage.
let sessionConfiguration = URLSessionConfiguration.ephemeral
sessionConfiguration.httpCookieAcceptPolicy = .never
let customSession = URLSession(configuration: sessionConfiguration)
enum Result {
case success(HTTPURLResponse, Data)
case failure(Error)
}
func readCookie(forURL url: URL) -> [HTTPCookie] {
let cookieStorage = HTTPCookieStorage.shared
let cookies = cookieStorage.cookies(for: url) ?? []
return cookies
}
func deleteCookies(forURL url: URL) {
let cookieStorage = HTTPCookieStorage.shared
for cookie in readCookie(forURL: url) {
cookieStorage.deleteCookie(cookie)
}
}
func storeCookies(_ cookies: [HTTPCookie], forURL url: URL) {
let cookieStorage = HTTPCookieStorage.shared
cookieStorage.setCookies(cookies,
for: url,
mainDocumentURL: nil)
}
func executeURLRequest(url: URL, inSession session: URLSession = .shared, completion: @escaping (Result) -> Void) {
let task = session.dataTask(with: url) { data, response, error in
if let response = response as? HTTPURLResponse,
let data = data {
completion(.success(response, data))
return
}
if let error = error {
completion(.failure(error))
return
}
let error = NSError(domain: "com.cookiesetting.test", code: 101, userInfo: [NSLocalizedDescriptionKey: "Unknown error occurred"])
completion(.failure(error))
}
task.resume()
}
With the snippet above, we firstly test that default session saves the cookie.
var cookies = readCookie(forURL: googleURL)
print("Cookies before request: ", cookies)
executeURLRequest(url: googleURL) { result in
if case .success (let data) = result {
cookies = readCookie(forURL: googleURL)
print("Cookies after request: ", cookies)
deleteCookies(forURL: googleURL)
cookies = readCookie(forURL: googleURL)
print("Cookies after deletion: ", cookies)
}
}
And, here is what we get,
Cookies before request: []
Cookies after request: [<NSHTTPCookie
version:0
name:1P_JAR
value:2018-09-26-15
expiresDate:'2018-10-26 15:39:46 +0000'
created:'2018-09-26 15:39:46 +0000'
sessionOnly:FALSE
domain:.google.com
partition:none
sameSite:none
path:/
isSecure:FALSE
path:"/" isSecure:FALSE>, <NSHTTPCookie
version:0
name:NID
value:139=E3g4bKNRGcYoeFuaECpfsx_Efp64xONmVwcJS7f7PuZe8LayS5ZkGuz3f7z6eq7zoBm2z-opTvzX8YPzn8v1ebjH6iyt5-6yDYm9RE6XhXwHCZWs98_j7nb11u2EPnHI
expiresDate:'2019-03-28 15:39:46 +0000'
created:'2018-09-26 15:39:46 +0000'
sessionOnly:FALSE
domain:.google.com
partition:none
sameSite:none
path:/
isSecure:FALSE
isHTTPOnly: YES
path:"/" isSecure:FALSE isHTTPOnly: YES>]
Cookies after deletion: []
URLSessionConfiguration
also has a property httpCookieAcceptPolicy
, which quotes the following:
This property determines the cookie accept policy for all tasks within
sessions based on this configuration.
The default value is
HTTPCookie.AcceptPolicy.onlyFromMainDocumentDomain. You can change it
to any of the constants defined in the HTTPCookie.AcceptPolicy
enumerated type.
If you want more direct control over what cookies are accepted, set
this value to HTTPCookie.AcceptPolicy.never and then use the
allHeaderFields and cookies(withResponseHeaderFields:for:) methods to
extract cookies from the URL response object yourself.
So, if you wish to manipulate the cookie by yourself, you could set the httpCookieAcceptPolicy
to never
.
Following code shows, cookie not stored when using httpCookieAcceptPolicy to never,
var cookies = readCookie(forURL: googleURL)
print("Cookies before request: ", cookies)
executeURLRequest(url: googleURL, inSession: customSession) { result in
if case .success (let data) = result {
cookies = readCookie(forURL: googleURL)
print("Cookies after request: ", cookies)
}
}
Which logs the following;
Cookies before request: []
Cookies after request: []
You can see that using .never for httpCookieStoragePolicy, system wont store cookie to shared cookie storage.
You can also store the cookie yourself, which would look like this,
Storing the cookie by ourselves
deleteCookies(forURL: googleURL)
var cookies = readCookie(forURL: googleURL)
print("Cookies before request: ", cookies)
executeURLRequest(url: googleURL, inSession: customSession) { result in
if case let .success (response, data) = result {
guard let cookiesResponseHeader = response.allHeaderFields["Set-Cookie"] else {
return
}
cookies = readCookie(forURL: googleURL)
print("Cookies after request: ", cookies)
let responseCookies = HTTPCookie.cookies(withResponseHeaderFields: response.allHeaderFields as! [String: String], for: googleURL)
storeCookies(responseCookies, forURL: googleURL)
cookies = readCookie(forURL: googleURL)
print("Cookies after storing: ", cookies)
}
}
And, here is what the code above prints to console,
Cookies before request: []
Cookies after request: []
Cookies after storing: [<NSHTTPCookie
version:0
name:1P_JAR
value:2018-09-26-18
expiresDate:'2018-10-26 18:35:23 +0000'
created:'2018-09-26 18:35:23 +0000'
sessionOnly:FALSE
domain:.google.com
partition:none
sameSite:none
path:/
isSecure:FALSE
path:"/" isSecure:FALSE>, <NSHTTPCookie
version:0
name:NID
value:139=D7GTUazWfeaB5Bcu1wN5I_Il2k6xALNiRZDX_DN9totQbnrP31gE0GzlsjCHDISUv8ulPq9G8Yu1p-GsZcVRw2fnrBROih-vtAVBic5UXFKUkG_ZbFQYKFprr4MPHDGS
expiresDate:'2019-03-28 18:35:23 +0000'
created:'2018-09-26 18:35:23 +0000'
sessionOnly:FALSE
domain:.google.com
partition:none
sameSite:none
path:/
isSecure:FALSE
isHTTPOnly: YES
path:"/" isSecure:FALSE isHTTPOnly: YES>]
The code above uses .never
HTTPCookieAcceptPolicy to URLSessionConfiguration but we create cookie from response and store it to the cookie store by ourselves.