Below is the snippet for making request.
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("application/json", forHTTPHeaderField: "Accept")
let configurationId = String(format: "NetworkManager%d", UInt16(arc4random_uniform(UInt32(UINT16_MAX))))
let configuration = URLSessionConfiguration.background(withIdentifier: configurationId)
let session = Foundation.URLSession(configuration: configuration, delegate: self, delegateQueue: OperationQueue.current)
let task = session.downloadTask(with: request)
task.resume()
While making this request, the authentication challenge methods as described below are not getting called.
#nonobjc func urlSession(_ session: Foundation.URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: (Foundation.URLSession.AuthChallengeDisposition, URLCredential?) -> Swift.Void)
#nonobjc func urlSession(_ session: Foundation.URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: (Foundation.URLSession.AuthChallengeDisposition, URLCredential?) -> Swift.Void)
Try using the following header slightly different from the ones you listed in your question.
open func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
//handle challenge here.
}
Related
This code is working fine on Swift version 3, I'm not able to make it work on Swift 4
func rest() {
let path = "https://localhost:8443/someservice"
let request = NSMutableURLRequest(URL: NSURL(string: path)!)
let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: configuration, delegate: self, delegateQueue:NSOperationQueue.mainQueue())
let task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
let json:JSON = JSON(data: data!)
if let c = json["content"].string {
print(c)
}
})
task.resume()
}
func URLSession(session: NSURLSession, task: NSURLSessionTask, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void) {
completionHandler(NSURLSessionAuthChallengeDisposition.UseCredential, NSURLCredential(forTrust: challenge.protectionSpace.serverTrust!))
}
You may need latest syntax
func urlSession(_ session: URLSession,
task: URLSessionTask,
didReceive challenge: URLAuthenticationChallenge,
completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void)
Your Delegate method is right for below swift 4.0 version but it's wrong for swift 4.0 and higher.
Here is working code, You need to use like this.
class ViewController: UIViewController,URLSessionDelegate {
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
completionHandler(URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust: challenge.protectionSpace.serverTrust!))
}
}
I'm trying to load data from the following url:: https://www.sample-videos.com/video/mp4/720/big_buck_bunny_720p_1mb.mp4
Function
func download() {
let configuration = URLSessionConfiguration.default
self.session = URLSession(configuration: configuration, delegate: self, delegateQueue: nil)
self.downloadTask = self.session.dataTask(with: self.url)
self.downloadTask.resume()
}
Delegates
// NOT GETTING CALLED
func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
completionHandler(URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust: challenge.protectionSpace.serverTrust!))
}
// NOT GETTING CALLED
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
completionHandler(URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust: challenge.protectionSpace.serverTrust!))
}
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
self.completion(self, data)
}
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
print(error)
// THIS IS GETTING CALLED WITH ERROR: Could not connect to the server. FULL ERROR BELOW.
}
func urlSession(_ session: URLSession, didBecomeInvalidWithError error: Error?) {
print(error)
}
Full Error
(Error Domain=NSURLErrorDomain Code=-1004 \"Could not connect to the
server.\" UserInfo={NSUnderlyingError=0x1c0658cc0 {Error
Domain=kCFErrorDomainCFNetwork Code=-1004 \"(null)\"
UserInfo={_kCFStreamErrorCodeKey=61, _kCFStreamErrorDomainKey=1}},
NSErrorFailingURLStringKey=https://www.sample-videos.com/video/mp4/720/big_buck_bunny_720p_1mb.mp4,
NSErrorFailingURLKey=https://www.sample-videos.com/video/mp4/720/big_buck_bunny_720p_1mb.mp4,
_kCFStreamErrorDomainKey=1, _kCFStreamErrorCodeKey=61, NSLocalizedDescription=Could not connect to the server.})
Below is the ATS configuration
Any help would be really appreciated!
Note The above URL works in Chrome but fails to load in Safari
I am trying to upload a file to the server and after the completion of upload, I'm supposed to get a JSON response.
I can see the data when I use the completion block
uploaderSession.dataTask(with: request, completionHandler: { (data, response, error) in
print("\(NSString(data: data!, encoding: 4))")
}).resume()
I need the same data but using the custom delegates
let session = URLSession(configuration: configuration, delegate: self, delegateQueue: nil)
session.dataTask(with: request).resume()
I implemented
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data)
but didReceiveData is not called.
Please suggest what can be done to get the JSON data at the end of completion of file upload
Thanks in advance
ok so got the answer just posting cause it can help somebody
we have to call
completionHandler(URLSession.ResponseDisposition.allow)
in
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse, completionHandler: #escaping (URLSession.ResponseDisposition) -> Void)
I want to download a file from a certain url .
what I need is the data delegate ( the delegate which gives me the downloaded data) .
I implemented the :
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
delegate but it doesn't get called .
my code is :
func download(url: URL)
{
let sessionConfig = URLSessionConfiguration.default
let session = URLSession(configuration: sessionConfig, delegate: self, delegateQueue: nil)
let task = session.downloadTask(with: url)
task.resume()
}
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
print("apending ")
self.dataaa.append(data)
}
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse, completionHandler: #escaping (URLSession.ResponseDisposition) -> Void) {
print("here")
}
the two delegate functions don't get called !
You're using the delegate methods for a data task, but you're creating a download task. Those two task types work differently and use completely different delegate methods.
I am doing a URLSession, but the URL requires credentials.
I have this whole method here that is trying to do a URLSession with URLCredentials:
func loginUser(_ username: String, password: String, completion: #escaping (_ result: Bool) -> Void)
{
//Create request URL as String
let requestString = String(format:"%#", webservice) as String
//Covert URL request string to URL
guard let url = URL(string: requestString) else {
print("Error: cannot create URL")
return
}
//Convert URL to URLRequest
let urlRequest = URLRequest(url: url)
print(urlRequest)
//Add the username and password to URLCredential
credential = URLCredential(user:username, password:password, persistence: .forSession)
//Setup the URLSessionConfiguration
let config = URLSessionConfiguration.default
//Setup the URLSession
let session = URLSession(configuration: config, delegate: self, delegateQueue: nil)
//Prepare the task to get data.
let task = session.dataTask(with: urlRequest, completionHandler: { (data, response, error) in
DispatchQueue.main.async(execute: {
if(error == nil)
{
completion(true)
}
else
{
completion(false)
}
})
})
//Run the task to get data.
task.resume()
}
and here are my URLSessionDelegate Methods:
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
if challenge.previousFailureCount > 0
{
completionHandler(Foundation.URLSession.AuthChallengeDisposition.cancelAuthenticationChallenge, nil)
}
else
{
completionHandler(Foundation.URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust:challenge.protectionSpace.serverTrust!))
}
}
/**
Requests credentials from the delegate in response to an authentication request from the remote server.
*/
func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
completionHandler(Foundation.URLSession.AuthChallengeDisposition.useCredential,credential)
}
I notice when I debug this in this delegate method:
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
if challenge.previousFailureCount > 0
{
completionHandler(Foundation.URLSession.AuthChallengeDisposition.cancelAuthenticationChallenge, nil)
}
else
{
completionHandler(Foundation.URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust:challenge.protectionSpace.serverTrust!))
}
}
That this method gets called twice and when it hits this line for the second time:
completionHandler(Foundation.URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust:challenge.protectionSpace.serverTrust!))
I get this error:
fatal error: unexpectedly found nil while unwrapping an Optional value
and then my app crashes! How do I fix this error?
the crash is due to challenge.protectionSpace.serverTrust being nil when you attempt to force unwrap it.
you should unwrap serverTrust and handle it being nil. my guess is that when serverTrust is nil challenge.error has a value.
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
if challenge.previousFailureCount > 0 {
completionHandler(Foundation.URLSession.AuthChallengeDisposition.cancelAuthenticationChallenge, nil)
} else if let serverTrust = challenge.protectionSpace.serverTrust {
completionHandler(Foundation.URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust: serverTrust))
} else {
print("unknown state. error: \(challenge.error)")
// do something w/ completionHandler here
}
}
Here is syntax as per swift 3.
Just verify firstly in which part of the delegate method it entered
open func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Swift.Void){
var disposition: URLSession.AuthChallengeDisposition = URLSession.AuthChallengeDisposition.performDefaultHandling
var credential:URLCredential?
if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
credential = URLCredential(trust: challenge.protectionSpace.serverTrust!)
if (credential != nil) {
disposition = URLSession.AuthChallengeDisposition.useCredential
}
else{
disposition = URLSession.AuthChallengeDisposition.performDefaultHandling
}
}
else{
disposition = URLSession.AuthChallengeDisposition.cancelAuthenticationChallenge
}
if (completionHandler != nil) {
completionHandler(disposition, credential);
}
}
Here is a slightly refactored from the above answers, a delegate class checks the number of failures, uses default unless the challenge is of type server trust it then calls the completion with trust credential:
class AuthSessionDelegate: NSObject, URLSessionDelegate {
func urlSession(_ session: URLSession,
didReceive challenge: URLAuthenticationChallenge,
completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
let authMethod = challenge.protectionSpace.authenticationMethod
guard challenge.previousFailureCount < 1, authMethod == NSURLAuthenticationMethodServerTrust,
let trust = challenge.protectionSpace.serverTrust else {
completionHandler(.performDefaultHandling, nil)
return
}
completionHandler(.useCredential, URLCredential(trust: trust))
}
}