Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use URLSession with Proxy in Swift 3

Tags:

ios

swift

For an API Request I'm trying to setup an URLSession using a Proxy. For test purposes I'm using a public Proxy and an API responding the IP.

func makeRequestViaUrlSessionProxy(_ url: String, completion: @escaping (_ result: String?) -> ()) {

    let request = URLRequest(url: URL(string: url)!)

    let config = URLSessionConfiguration.default
    config.requestCachePolicy = URLRequest.CachePolicy.reloadIgnoringLocalCacheData
    config.connectionProxyDictionary = [AnyHashable: Any]()
    config.connectionProxyDictionary?[kCFNetworkProxiesHTTPEnable as String] = 1
    config.connectionProxyDictionary?[kCFNetworkProxiesHTTPProxy as String] = "142.54.173.19"
    config.connectionProxyDictionary?[kCFNetworkProxiesHTTPPort as String] = 8888

    let session = URLSession.init(configuration: config, delegate: nil, delegateQueue: OperationQueue.current)

    let task = session.dataTask(with: request) {
        (data: Data?, response: URLResponse?, error: Error?) in
        if error != nil {
            NSLog("Client-side error in request to \(url): \(error)")
            completion(nil)
            return
        }

        if data == nil {
            NSLog("Data from request to \(url) is nil")
            completion(nil)
            return
        }

        let httpResponse = response as? HTTPURLResponse
        if httpResponse?.statusCode != 200 {
            NSLog("Server-side error in request to \(url): \(httpResponse)")
            completion(nil)
            return
        }

        let encodingName = response?.textEncodingName != nil ? response?.textEncodingName : "utf-8"
        let encoding = CFStringConvertEncodingToNSStringEncoding(CFStringConvertIANACharSetNameToEncoding(encodingName as CFString!))
        let stringData = String(data: data!, encoding: String.Encoding(rawValue: UInt(encoding)))
        session.invalidateAndCancel()
        completion(stringData)
    }
    task.resume()
}

Called by:

override func viewDidLoad() {
    super.viewDidLoad()
    makeRequestViaUrlSessionProxy("https://api.ipify.org?format=json") { string in
        print(string)
    }
}

It seems like the config is completely ignored because even with made up Proxy IP, the responded IP is always the actual devices IP

Any help is highly appreciated.

Edit: as suggested by User hasan83, taking "the HTTPS keys" seems not an option.

enter image description here enter image description here

like image 382
David Seek Avatar asked Mar 06 '17 04:03

David Seek


Video Answer


2 Answers

I think the working (supposed to be deprecated) keys are:

kCFStreamPropertyHTTPSProxyHost
kCFStreamPropertyHTTPSProxyPort

Could you try this code?

func makeRequestViaUrlSessionProxy(_ url: String, completion: @escaping (_ result: String?) -> ()) {

    let request = URLRequest(url: URL(string: url)!)

    let config = URLSessionConfiguration.default
    config.requestCachePolicy = URLRequest.CachePolicy.reloadIgnoringLocalCacheData
    config.connectionProxyDictionary = [AnyHashable: Any]()
    config.connectionProxyDictionary?[kCFNetworkProxiesHTTPEnable as String] = 1
    config.connectionProxyDictionary?[kCFNetworkProxiesHTTPProxy as String] = "142.54.173.19"
    config.connectionProxyDictionary?[kCFNetworkProxiesHTTPPort as String] = 8888
    config.connectionProxyDictionary?[kCFStreamPropertyHTTPSProxyHost as String] = "142.54.173.19"
    config.connectionProxyDictionary?[kCFStreamPropertyHTTPSProxyPort as String] = 8888

    let session = URLSession.init(configuration: config, delegate: nil, delegateQueue: OperationQueue.current)

    let task = session.dataTask(with: request) {
        (data: Data?, response: URLResponse?, error: Error?) in
        if error != nil {
            NSLog("Client-side error in request to \(url): \(error)")
            completion(nil)
            return
        }

        if data == nil {
            NSLog("Data from request to \(url) is nil")
            completion(nil)
            return
        }

        let httpResponse = response as? HTTPURLResponse
        if httpResponse?.statusCode != 200 {
            NSLog("Server-side error in request to \(url): \(httpResponse)")
            completion(nil)
            return
        }

        let encodingName = response?.textEncodingName != nil ? response?.textEncodingName : "utf-8"
        let encoding = CFStringConvertEncodingToNSStringEncoding(CFStringConvertIANACharSetNameToEncoding(encodingName as CFString!))
        let stringData = String(data: data!, encoding: String.Encoding(rawValue: UInt(encoding)))
        session.invalidateAndCancel()
        completion(stringData)
    }
    task.resume()
}

Also please make sure your proxy server is configured to handle https requests.

Note: It might give deprecated warning for those keys but keys are still working (see https://forums.developer.apple.com/thread/19356#131446)

like image 105
manishg Avatar answered Sep 26 '22 18:09

manishg


I am not sure if that make sense. But, there is two defferent set of keys here:

  1. HTTP
  2. HTTPS

Proxy Keys:

// http proxy keys
kCFNetworkProxiesHTTPEnable
kCFNetworkProxiesHTTPProxy
kCFNetworkProxiesHTTPPort

// https proxy keys
kCFNetworkProxiesHTTPSEnable
kCFNetworkProxiesHTTPSProxy
kCFNetworkProxiesHTTPSPort
like image 35
hasan Avatar answered Sep 25 '22 18:09

hasan