16

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

David Seek
  • 16,783
  • 19
  • 105
  • 136

2 Answers2

10

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)

manishg
  • 9,520
  • 1
  • 16
  • 19
  • seems to work. will have more tests tomorrow, but this seems to be it. – David Seek Mar 12 '17 at 22:01
  • as far as my current research goes, your config should work here as well, so please feel free to try and if valid, answer here as well: http://stackoverflow.com/questions/42616908/how-to-use-a-proxy-server-with-alamofire-4-and-swift-3 – David Seek Mar 12 '17 at 22:02
  • Yeah the same config should work with alamofire session manager as they are also using URLSessionConfiguration.default . Thanks for the heads up. I will post the answer there. – manishg Mar 12 '17 at 22:48
  • Is it possible to retain the IP address when going to other pages? Currently the first loaded page has the proxy IP but when you click and redirected to other page, it shows your original IP address. – Robin Carlo Catacutan Mar 30 '17 at 05:13
  • @RobinCarloCatacutan did you manage to find an answer to your question? I would be interested in retaining IP address when redirecting as well. – akaralar Mar 21 '18 at 10:00
  • @akaralar Unfortunately no, I didn't. My workaround was to make a page on our web server, then create an iframe where the user will navigate to other pages. – Robin Carlo Catacutan Mar 21 '18 at 12:58
  • HTTPS proxy seems to work fine when providing a dictionary with the following keys: `["HTTPSProxy": , "HTTPSPort": , "HTTPSEnable": kCFBooleanTrue]`. CFStream keys seem to match the constants that aren't available for iOS but available on macOS – pronebird Apr 21 '23 at 09:23
2

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
hasan
  • 23,815
  • 10
  • 63
  • 101