12

Looking over the documentation of NSURLSession and NSURLSessionConfiguration, I was under the impression I should configure it with a dictionary like the following:

    // Create a dictionary to describe the proxy 
    NSDictionary *proxyDict = @{
        (NSString *)kCFProxyHostNameKey   : @"myProxyHost.com",
        (NSString *)kCFProxyPortNumberKey : @"12345",
        (NSString *)kCFProxyTypeKey       : (NSString*)kCFProxyTypeHTTP
    };

    // Create a configuration that uses the dictionary
    NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    [configuration setConnectionProxyDictionary:proxyDict];

However, the requests from NSURLSession created with this configuration connect directly.

Jeff
  • 6,646
  • 5
  • 27
  • 33

6 Answers6

24

It turns out, the dictionary keys you want are the Stream variants, they are the ones that resolve down to "HTTPProxy" and such:

NSString* proxyHost = @"myProxyHost.com";
NSNumber* proxyPort = [NSNumber numberWithInt: 12345];

// Create an NSURLSessionConfiguration that uses the proxy
NSDictionary *proxyDict = @{
    @"HTTPEnable"  : [NSNumber numberWithInt:1],
    (NSString *)kCFStreamPropertyHTTPProxyHost  : proxyHost,
    (NSString *)kCFStreamPropertyHTTPProxyPort  : proxyPort,

    @"HTTPSEnable" : [NSNumber numberWithInt:1],
    (NSString *)kCFStreamPropertyHTTPSProxyHost : proxyHost,
    (NSString *)kCFStreamPropertyHTTPSProxyPort : proxyPort,
};

NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration ephemeralSessionConfiguration];
configuration.connectionProxyDictionary = proxyDict;

// Create a NSURLSession with our proxy aware configuration
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:[NSOperationQueue mainQueue]];

// Form the request
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"https://www.google.com?2"]];

// Dispatch the request on our custom configured session
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:
                              ^(NSData *data, NSURLResponse *response, NSError *error) {
                                  NSLog(@"NSURLSession got the response [%@]", response);
                                  NSLog(@"NSURLSession got the data [%@]", data);
                              }];

NSLog(@"Lets fire up the task!");
[task resume];
Jeff
  • 6,646
  • 5
  • 27
  • 33
  • Thank you! A million times thank you! I would never have figured this out. Sure would be nice if Apple documented this. – bugloaf Mar 27 '15 at 16:14
  • @Jeff - I have tried this.. But the data returning from `^(NSData *data, NSURLResponse *response, NSError *error)` gives the results of myProxyHost.com and not www.google.com Can u pls help me – Balaji Kondalrayal Oct 08 '16 at 08:33
  • is it possible to use user/password? and how to do that if possible? – Alexander Yatsenko Dec 22 '16 at 16:01
  • 1
    @AlexanderYatsenko when I did this research in 2015 the answer was a firm "No", which was quite annoying as l happened to know the credentials the user would soon be prompted for. The issue is that apple handles the proxy challenge it its own layer and doesn't expose any API to you. See that delegate for auth challenge, it is specifically avoids proxy auth. (Maybe this is due to the existence of chained proxies.) – Jeff Dec 27 '16 at 21:18
  • If I have a pac file with automatic proxy configurations, can I set this pac file somewhere? (In this file I have defined some server should be accessed via PROXY other should be accessed DIRECTtly) Is this possible? – nacho4d May 13 '21 at 01:38
9

Since several of Jeff's answer keys were deprecated I use this ones

NSMutableDictionary *proxy=[NSMutableDictionary dictionaryWithDictionary:@{(__bridge NSString *)kCFNetworkProxiesHTTPEnable  : @1,  (__bridge NSString *)kCFNetworkProxiesHTTPSEnable : @1}];
proxy[(__bridge NSString *)kCFNetworkProxiesHTTPProxy] =host;
proxy[(__bridge NSString *)kCFNetworkProxiesHTTPSProxy]=host;
proxy[(__bridge NSString *)kCFNetworkProxiesHTTPPort]  =port;
proxy[(__bridge NSString *)kCFNetworkProxiesHTTPSPort] =port;
proxy[(__bridge NSString *)kCFProxyUsernameKey]=user;
proxy[(__bridge NSString *)kCFProxyPasswordKey]=password;

configuration.connectionProxyDictionary=proxy;
Daniyar
  • 2,975
  • 2
  • 26
  • 39
8

If anyone needs the swift version of this:

Swift 3

let sessionConfiguration = URLSessionConfiguration.default
sessionConfiguration.connectionProxyDictionary = [
    kCFNetworkProxiesHTTPEnable as AnyHashable: true,
    kCFNetworkProxiesHTTPPort as AnyHashable: 999, //myPortInt
    kCFNetworkProxiesHTTPProxy as AnyHashable: "myProxyUrlString"
]
let session = URLSession(configuration: sessionConfiguration)
Travis M.
  • 10,930
  • 1
  • 56
  • 72
4

kCFProxyPortNumberKey value should be Int not String

Oleg Kovtun
  • 362
  • 1
  • 3
3

Swift 3 extension

extension URLSession {

    func withProxy(proxyURL: String, proxyPort: Int) -> URLSession {

        var configuration = self.configuration

        configuration.connectionProxyDictionary = [
            kCFNetworkProxiesHTTPEnable as AnyHashable : true,
            kCFNetworkProxiesHTTPPort as AnyHashable : proxyPort,
            kCFNetworkProxiesHTTPProxy as AnyHashable : proxyURL
        ]

        return URLSession(configuration: configuration, delegate: self.delegate, delegateQueue: self.delegateQueue)
    }
}

Usage:

let session = URLSession().withProxy(proxyURL: "xxxxxx", proxyPort: 8321)
deanWombourne
  • 38,189
  • 13
  • 98
  • 110
Med Abida
  • 1,214
  • 11
  • 31
3

Based on all previous responses, this works for Swift 4, both HTTP and HTTPS:

let proxyHost = "127.0.0.1"
let proxyPort = 8888
let configuration = URLSessionConfiguration.default
configuration.connectionProxyDictionary = [
    kCFNetworkProxiesHTTPEnable: true,
    kCFNetworkProxiesHTTPProxy: proxyHost,
    kCFNetworkProxiesHTTPPort: proxyPort,
    kCFNetworkProxiesHTTPSEnable: true,
    kCFNetworkProxiesHTTPSProxy: proxyHost,
    kCFNetworkProxiesHTTPSPort: proxyPort
]

proxyHost should be a hostname and not contain any URL scheme.

Eneko Alonso
  • 18,884
  • 9
  • 62
  • 84