Search code examples
iosswifthttpproxyswift-playground

How to connect to a HTTP server using a proxy configuration with Swift 5 (why connectionProxyDictionary is being ignored)?


I need to connect to a webserver behind an HTTP proxy. I've tried using URLSessionConfiguration with connectionProxyDictionary, but it seems my proxy configurations are ignored because you can change the proxy host value to anything and the result is the same.

I have tried to use Charles Proxy to debug the situation in lieu of the proxy I need to connect to and found out that the request never reaches it, so I believe there is something wrong on my client-side code.

import Foundation

class URLSessionProxy: NSObject, URLSessionDelegate {

    func doRequest() {

        let configuration = URLSessionConfiguration.default
        configuration.connectionProxyDictionary = [
            kCFNetworkProxiesHTTPEnable: true,
            kCFNetworkProxiesHTTPProxy: "localhost",
            kCFNetworkProxiesHTTPPort: "8888",
        ]

        var request = URLRequest(url: URL(string: "https://ip.seeip.org/jsonip")!)
        request.addValue("application/json", forHTTPHeaderField: "Accept")

       URLSession(configuration: configuration, delegate: self, delegateQueue: OperationQueue.main)
        .dataTask(with: request, completionHandler: { (data, response, error) in
            if error == nil {
                print("url request = ", request.url?.absoluteString)
                print("headers request = ", request.allHTTPHeaderFields.debugDescription)
                print("response = ", response)
                print("data body = ", String(data: data!, encoding: String.Encoding.utf8.self))

            } else {
                print("error = ", error)
                print(error?.localizedDescription)
            }
        }).resume()
    }
}

URLSessionProxy().doRequest()

In the example given, I expect the connection to ip.seeip.org to happen indirectly, using the proxy I have set up on localhost:8888.​

gist: https://gist.github.com/brunabaudel/90a6873d2c3df6caeb89f8b7afc9adce


Solution

  • The kCFNetworkProxiesHTTP keys only control the proxy that's used for http URLs. https URLs use a proxy defined with the kCFNetworkProxiesHTTPS keys.

    Unfortunately the HTTPS keys aren't available on iOS (really not sure why), but the implementation is there, so you can just pass strings with the correct keys, which are "HTTPSEnable", "HTTPSProxy", and "HTTPSPort".