I'm new to swift and OS X programming. For my first steps I wanted to create a command line tool which logs me into the webinterface of my mobile carrier, and then shows the amount of my data left. I began to write a wrapper around NSURLSession to make things easier for me.
Problem: My program won't accept cookies.
I tried a lot of things, also setting cookie policies on the session object but nothing changed. How can I make my program accept cookies and how to use them in subsequent requests?
HttpClient.swift:
import Foundation
class HttpClient {
private var url: NSURL!
private var session: NSURLSession
internal init(url: String) {
self.url = NSURL(string: url)
self.session = NSURLSession.sharedSession()
session.configuration.HTTPShouldSetCookies = true
session.configuration.HTTPCookieAcceptPolicy = NSHTTPCookieAcceptPolicy.OnlyFromMainDocumentDomain
session.configuration.HTTPCookieStorage?.cookieAcceptPolicy = NSHTTPCookieAcceptPolicy.OnlyFromMainDocumentDomain
}
internal func sendGet() -> String {
var ready = false
var content: String!
var request = NSMutableURLRequest(URL: self.url)
var task = session.dataTaskWithRequest(request) {
(data, response, error) -> Void in
content = NSString(data: data, encoding: NSASCIIStringEncoding) as! String
ready = true
}
task.resume()
while !ready {
usleep(10)
}
if content != nil {
return content
} else {
return ""
}
}
internal func sendPost(params: String) -> String {
var ready = false
var content: String!
var request = NSMutableURLRequest(URL: self.url)
request.HTTPMethod = "POST"
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.HTTPBody = params.dataUsingEncoding(NSASCIIStringEncoding, allowLossyConversion: false)
request.HTTPShouldHandleCookies = true
var task = session.dataTaskWithRequest(request) {
(data, response, error) -> Void in
content = NSString(data: data, encoding: NSASCIIStringEncoding) as! String
ready = true
}
task.resume()
while !ready {
usleep(10)
}
if content != nil {
return content
} else {
return ""
}
}
internal func setUrl(url: String) {
self.url = NSURL(string: url)
}
}
main.swift
import Foundation
let loginPage = "https://service.winsim.de/"
let dataPage = "https://service.winsim.de/mytariff/invoice/showGprsDataUsage"
var hc = HttpClient(url: loginPage)
println(hc.sendPost("usernameField=username&passwordfield=password"))
hc.setUrl(dataPage)
println(hc.sendGet())
Issue is solved
In fact, cookies are accepted with the above code. I tried logging in to a different site and it worked. Also the login persisted. So why it did not work with my carrier's website?
Stupid me, my carrier has CSRF protection and other hidden form fields which I did not pay attention to. Hence, login did not work. Now I know how to fix it.
For anyone interested, I'll post my updated HttpClient.swift file which is a bit more tidy, I hope.
Please feel free to comment on my code and give me hints for improvement.
import Foundation
public class HttpClient {
private var session: NSURLSession
private var request: NSMutableURLRequest
public init(url: String) {
self.session = NSURLSession.sharedSession()
session.configuration.HTTPShouldSetCookies = true
session.configuration.HTTPCookieAcceptPolicy = NSHTTPCookieAcceptPolicy.OnlyFromMainDocumentDomain
session.configuration.HTTPCookieStorage?.cookieAcceptPolicy = NSHTTPCookieAcceptPolicy.OnlyFromMainDocumentDomain
self.request = NSMutableURLRequest(URL: NSURL(string: url)!)
}
public func send() -> String {
var ready = false
var content: String!
var task = session.dataTaskWithRequest(self.request) {
(data, response, error) -> Void in
content = NSString(data: data, encoding: NSASCIIStringEncoding) as! String
ready = true
}
task.resume()
while !ready {
usleep(10)
}
if content != nil {
return content
} else {
return ""
}
}
public func setUrl(url: String) -> HttpClient {
self.request.URL = NSURL(string: url)
return self
}
public func getMethod() -> String {
return self.request.HTTPMethod
}
public func setMethod(method: String) -> HttpClient {
self.request.HTTPMethod = method
return self
}
public func addFormData(data: Dictionary<String, String>) -> HttpClient {
var params: String = ""
var ctHeader: String? = self.request.valueForHTTPHeaderField("Content-Type")
let ctForm: String = "application/x-www-form-urlencoded"
if(data.count > 0) {
for(name, value) in data {
params += name + "=" + value + "&"
}
params = params.substringToIndex(params.endIndex.predecessor())
self.request.HTTPBody = params.dataUsingEncoding(NSASCIIStringEncoding, allowLossyConversion: false)
if ctHeader != nil {
self.request.setValue(ctForm, forHTTPHeaderField: "Content-Type")
}
}
return self
}
public func removeFormData() -> HttpClient {
self.request.setValue("text/html", forHTTPHeaderField: "Content-Type")
self.request.HTTPBody = "".dataUsingEncoding(NSASCIIStringEncoding, allowLossyConversion: false)
return self
}
}