I need to fetch a redirecting URL but prevent redirection in Swift. From other posts and Apple docs I understand I must implement the delegate method URLS
I also found the solution helpful, but I am using Swift 4.2 in my current project.
So, here is an adapted shorter version of the solution above, that also works with Swift 4.2 and Xcode 10.
import Foundation
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
class MySession: NSObject, URLSessionTaskDelegate {
func urlSession(_ session: URLSession, task: URLSessionTask, willPerformHTTPRedirection response: HTTPURLResponse, newRequest request: URLRequest, completionHandler: @escaping (URLRequest?) -> Void) {
completionHandler(nil)
}
}
func getDataFromServerWithSuccess(myURL: String, noRedirect: Bool) {
let myDelegate: MySession? = noRedirect ? MySession() : nil
let session = URLSession(configuration: URLSessionConfiguration.default, delegate: myDelegate, delegateQueue: nil)
let loadDataTask = session.dataTask(with: URL(string:myURL)!) { (data, response, error) in
// OMITTING ERROR CHECKING FOR BREVITY
if let data = data {
if let dataString = String(bytes: data, encoding: .utf8) {
print(dataString)
if dataString.contains("Bitly") == true {
print("success: redirection was prevented")
} else {
print("failure: redirection went through")
}
}
}
}
loadDataTask.resume()
}
getDataFromServerWithSuccess(myURL: "http://bitly.com/filmenczer", noRedirect: true)
You have two things standing in your way with your current implementation.
You never set the delegate property on the NSURLSession
instance that you're using to make the request. Without the delegate property set, your delegate methods won't ever be called. Instead of getting NSURLSession.sharedSession()
, look at the NSURLSession(configuration:delegate:delegateQueue:)
initializer. The first and last parameters can be NSURLSessionConfiguration.defaultSessionConfiguration()
and nil
, respectively, see below for more about the delegate.
Note that when you use the variant of
session.dataTaskWithURL
that has a completion handler, delegate methods that handle response and data delivery will be ignored, but authentication and redirection handlers are still used.
You'll have to refactor somewhat to use MySession
as a delegate, since you're using class methods to make the request. You need an instance to use as the session's delegate.
I took a short and incomplete route to having the delegate pick up on the redirect with this alternate code—you'll need to refactor as in #3 to make sure you can still call your callback:
class func getDataFromServerWithSuccess(myURL: String, success: (response: String!) -> Void) {
let delegate = MySession()
var session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration(), delegate: delegate, delegateQueue: nil)
let task = session.dataTaskWithURL(NSURL(string: myURL)!) {
// ...
}
task.resume()
}
Hope that helps!
Minor adjustments to the solutions proposed above. This works with Swift 2 in XCode 7.
import UIKit
import Foundation
import XCPlayground
XCPSetExecutionShouldContinueIndefinitely(true)
class MySession: NSObject, NSURLSessionDelegate {
// to prevent redirection
func URLSession(session: NSURLSession, task: NSURLSessionTask, willPerformHTTPRedirection response: NSHTTPURLResponse, newRequest request: NSURLRequest, completionHandler: (NSURLRequest!) -> Void) {
completionHandler(nil)
}
// fetch data from URL with NSURLSession
class func getDataFromServerWithSuccess(myURL: String, noRedirect: Bool, success: (response: String!) -> Void) {
var myDelegate: MySession? = nil
if noRedirect {
myDelegate = MySession()
}
let session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration(), delegate: myDelegate, delegateQueue: nil)
let loadDataTask = session.dataTaskWithURL(NSURL(string: myURL)!) { (data: NSData?, response: NSURLResponse?, error: NSError?) -> Void in
// OMITTING ERROR CHECKING FOR BREVITY
success(response: NSString(data: data!, encoding: NSASCIIStringEncoding) as! String)
}
loadDataTask.resume()
}
// extract data from redirect
class func getRedirectionInfo(url: String) {
getDataFromServerWithSuccess(url, noRedirect: true) {(data) -> Void in
if let html = data {
if html.rangeOfString("<html>\n<head><title>Bitly</title>", options: .RegularExpressionSearch) != nil {
print("success: redirection was prevented")
} else {
print("failure: redirection went through")
}
}
}
}
}
MySession.getRedirectionInfo("http://bit.ly/filmenczer")