Reputation: 128
I'm using SwiftHTTP in an iOS application to perform basic authentication in a web server. If the authentication succeeds, everything works as expected. However, if the authentication fails (with code 401), it takes about 35 to 45 seconds for the failure handler to be called. The code is as follows:
var request = HTTPTask()
auth = HTTPAuth(username: user, password: password)
auth!.persistence = .ForSession
request.auth = auth
request.requestSerializer.timeoutInterval = 5
request.GET("http://\(ipaddr)", parameters: nil,
success: {(response : HTTPResponse) in
NSLog("login success")
},
failure: {(error: NSError, response: HTTPResponse?) in
NSLog("login failure")
}
)
Note that the timeout value is set to 5 seconds. Checking the SwiftHTTP code, the actual request implementation boils down to:
var request = NSMutableURLRequest(URL: url, cachePolicy: cachePolicy, timeoutInterval: timeoutInterval)
I added a few debug lines in SwiftHTTP to check if timeoutInterval
is being correctly set, and it is. I tried variations in cache policies and other configurable parameters with no changes in the result. I also opened a telnet connection to the HTTP server and sent the same request by hand, and the 401 result was returned immediately, as expected.
Any ideas why this is happening?
Upvotes: 0
Views: 668
Reputation: 128
When a library doesn't work in a bizarre, unexpected or nonsensical way, chances are that there's a bug in the library. If you used an unstable release or a git repository snapshot, be sure to check for fixes in the upstream tree, even if you think the library is working correctly.
So this was fixed by updating the library. HTTPAuth
doesn't exist anymore in the current (at the time of this writing) library. It was replaced by an user-provided closure, as shown in the library documentation:
var request = HTTPTask()
//the auth closures will continually be called until a successful auth or rejection
var attempted = false
request.auth = {(challenge: NSURLAuthenticationChallenge) in
if !attempted {
attempted = true
return NSURLCredential(user: "user", password: "passwd", persistence: .ForSession)
}
return nil //auth failed, nil causes the request to be properly cancelled.
}
Upvotes: 0
Reputation: 438287
It looks like HTTPTask
handles challenges like so:
public func URLSession(session: NSURLSession, task: NSURLSessionTask, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential!) -> Void) {
if let a = auth {
let cred = a(challenge)
if let c = cred {
completionHandler(.UseCredential, c)
return
}
completionHandler(.RejectProtectionSpace, nil)
return
}
completionHandler(.PerformDefaultHandling, nil)
}
I'd suggest you only use the credential if the previousFailureCount
was zero, e.g.
public func URLSession(session: NSURLSession, task: NSURLSessionTask, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential!) -> Void) {
if let credential = auth?(challenge) {
if challenge.previousFailureCount == 0 {
completionHandler(.UseCredential, credential)
} else {
completionHandler(.RejectProtectionSpace, nil)
}
} else {
completionHandler(.PerformDefaultHandling, nil)
}
}
Upvotes: 2