Linked Questions

Popular Questions

Preventing URLSession redirect in Swift

Asked by At

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 URLSession(session:, task:, willPerformHTTPRedirection response:, request:, completionHandler:) and return nil via the completion closure. But I can't find examples in swift, nor figure out the right way to do it. The code below reproduces my issue in playground: the delegate does not seem to get executed.

import Foundation
import XCPlayground

XCPSetExecutionShouldContinueIndefinitely(continueIndefinitely: true)

class MySession: NSObject, NSURLSessionDelegate, NSURLSessionTaskDelegate {

    // trying to follow instructions at https://developer.apple.com/library/ios/documentation/Foundation/Reference/NSURLSessionTaskDelegate_protocol/index.html#//apple_ref/occ/intfm/NSURLSessionTaskDelegate/URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler:
    // to prevent redirection -- DOES NOT SEEM TO GET CALLED
    func URLSession(session: NSURLSession, task: NSURLSessionTask, willPerformHTTPRedirection response: NSHTTPURLResponse, newRequest request: NSURLRequest, completionHandler: (NSURLRequest!) -> Void) {
        println("in URLSession delegate") // NEVER PRINTS
        completionHandler(nil) // NO EFFECT
    }

    // fetch data from URL with NSURLSession
    class func getDataFromServerWithSuccess(myURL: String, success: (response: String!) -> Void) {
        var session = NSURLSession.sharedSession()
        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) {(data) -> Void in
            if let html = data {
                if html.rangeOfString("<html><head><title>Object moved</title>", options: .RegularExpressionSearch) != nil {
                    println("success: redirection was prevented") // SHOULD PRINT THIS
                } else {
                    println("failure: redirection went through") // INSTEAD PRINTS THIS
                }
            }
        }
    }
}

MySession.getRedirectionInfo("http://bit.ly/filmenczer") // ex. redirecting link

Please be gentle, I am a newbie. Thank you in advance for any assistance!

UPDATE: With many thanks to @nate I got it to work. The key insight is that in order for the delegate to be called, one must pass the delegate class to the NSURLSession() initializer, rather than using NSURLSession.sharedSession(). Passing nil as the delegate yields the customary behavior (with redirection). Here is working version of the code:

import Foundation
import XCPlayground

XCPSetExecutionShouldContinueIndefinitely(continueIndefinitely: true)

class MySession: NSObject, NSURLSessionDelegate, NSURLSessionTaskDelegate {

    // 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 {
                    println("success: redirection was prevented")
                } else {
                    println("failure: redirection went through")
                }
            }
        }
    }
}

MySession.getRedirectionInfo("http://bit.ly/filmenczer")

Related Questions