Configuring proxy for NSURLSession in iOS 9

It looks like several of the dictionary key constants I was using in my NSURLSessionConfiguration's connectionProxyDictionary were marked as deprecated in iOS 9:


@available(iOS, introduced=2.0, deprecated=9.0, message="Use NSURLSession API for http requests")
public let kCFStreamPropertyHTTPProxyHost: CFString

@available(iOS, introduced=2.0, deprecated=9.0, message="Use NSURLSession API for http requests")
public let kCFStreamPropertyHTTPProxyPort: CFString

@available(iOS, introduced=2.0, deprecated=9.0, message="Use NSURLSession API for http requests")
public let kCFStreamPropertyHTTPSProxyHost: CFString

@available(iOS, introduced=2.0, deprecated=9.0, message="Use NSURLSession API for http requests")
public let kCFStreamPropertyHTTPSProxyPort: CFString


I've done some searching but I can't find any documentation that talks about alternatives.

What is the appropriate way to configure a proxy in iOS 9?

Post not yet marked as solved Up vote post of chrish Down vote post of chrish
8.3k views

Replies

Right, that’s part of the general deprecation of CFHTTPStream.

You should use the non-deprecated constants in

<CFNetwork/CFProxySupport.h>
, specifically
kCFNetworkProxiesHTTPEnable
,
kCFNetworkProxiesHTTPProxy
and
kCFNetworkProxiesHTTPPort
. AFAIK you won’t need the matching ‘HTTPS’ constants—which are OS X only—because iOS infers one from the other.

Share and Enjoy

Quinn "The Eskimo!"
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Quinn, these two don't function in the same way though do they? I use a NSURLSession in a NSURLProtocol for catching some traffic and channeling it through a HTTP proxy for a business network. When using the old kCFStreamPropertyHTTPProxyHost etc (CFStream....) in the debug logs I only see traffic going to the proxy server. When using kCFNetworkProxiesHTTPProxy (kCFNetwork.....) I see some traffic leaking through and hitting the originaly targetted server. The only change is changing the HTTP dictionaries, as below:


from:

        let proxyDict = [
            "HTTPEnable":NSNumber(integer: 1),
            String(kCFStreamPropertyHTTPProxyHost):proxyHost,
            String(kCFStreamPropertyHTTPProxyPort):proxyPort,
           
            "HTTPSEnable":NSNumber(integer: 1),
            String(kCFStreamPropertyHTTPSProxyHost):proxyHost,
            String(kCFStreamPropertyHTTPSProxyPort):proxyPort
        ]


to:

        let proxyDict = [
            "kCFNetworkProxiesHTTPEnable":NSNumber(integer: 1),
            String(kCFNetworkProxiesHTTPProxy):proxyHost,
            String(kCFNetworkProxiesHTTPPort):proxyPort
        ]


Any ideas?

Why are you using

"kCFNetworkProxiesHTTPEnable"
rather than
String(kCFNetworkProxiesHTTPEnable)
? The value of
kCFNetworkProxiesHTTPEnable
is
"HTTPEnable"
, so that makes a significant difference.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Thanks for pointing that out Quinn. However, I'm still having issues: with the old dictionary above (the one that explicitly states to work over HTTP AND HTTPS - depricated in iOS 9) my NSURLProtocol catches HTTPS requests. However, with the new dictionary that only includes keys for HTTP proxy, HTTPS connections seem not to be proxified and seem to slip through. When I use the network diagnostics tool, I see conncetions only to my proxy server IP when going to HTTP addresses, but as soon as it's an HTTPS address it goes directly to the site. Any ideas? As far as I can see, no HTTPS keys exist.

Do you see anything of interested in the CFNetwork diagnostic log.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Hey Quinn,


We have a major project to reroute all of our applications traffic through a corporate proxy. Your inputs in this forum have been helpful, but were still having trouble getting the appside proxy to work for HTTP requests. HTTPS requests are returning data, but HTTP requests are timing out.


We've tested the proxy locally through Charles and it seems to be working for both. We also checked the cfnetwork log, but the data seems a little short, so were still not sure what maybe wrong or if theres anything else we should be looking at as well. Please let us know what more information we could provide and we will follow up 😝


Here's the code snippet from our test project:


    NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration ephemeralSessionConfiguration];
    NSDictionary *proxyDict = @{
                                (NSString *)kCFNetworkProxiesHTTPEnable  : [NSNumber numberWithInt:1],
                                (NSString *)kCFNetworkProxiesHTTPProxy  : newProxyHost,
                                (NSString *)kCFNetworkProxiesHTTPPort  : proxyPort,
                                };

    configuration.connectionProxyDictionary = proxyDict;

    NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.directv.com"];

    NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:
                                  ^(NSData *data, NSURLResponse *response, NSError *error) {
                                   
                                      if (error) {
                                      NSLog(@"Failed === Response:%@ %@\n", response, error);
                                      }
                                      NSString* newStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
                                      NSLog(@"%@",newStr);
                                  }];
    [task resume];

If the problem is with HTTP requests, you can simply look at the packets on the wire to see where they went. There’s advice on setting that up in QA1176 Getting a Packet Trace.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

I'm currently facing the same issue. With only the keys kCFNetworkProxiesHTTPEnable, kCFNetworkProxiesHTTPPort and kCFNetworkProxiesHTTPProxy in the dictionary, all HTTPS requests are not going through the proxy. Only if I add the keys kCFStreamPropertyHTTPSProxyPort and kCFStreamPropertyHTTPSProxyHost as well, HTTPS requests are routed through the proxy.


Is there any solution for this, other than using the deprectaed keys for now?


And is there a way to tell the NSURLSession about exceptions, domains which should be not routed through the proxy? Like for example the following IP ranges: 10.0.0.0/8, 172.16.0.0/12 and 192.168.0.0/16

Is there any solution for this, other than using the deprectaed keys for now?

Please file a bug with the details and continue using the deprecated keys for now.

By way of context:

  • All of these constants have the same value. For example,

    kCFNetworkProxiesHTTPProxy
    is equal to
    kCFStreamPropertyHTTPProxyHost
    is equal to
    kSCPropNetProxiesHTTPProxy
    is equal to “HTTPProxy”. All except the first explicitly document that equivalence.
  • These constants are tested with

    -isEquals:
    , not pointer equality, so they all work equally well. A literal string would just as well (although I don’t recommend that).
  • The upshot of this is that all of these problems are related to packaging (how the constants are exposed on the various platforms) rather than core functionality.

And is there a way to tell the NSURLSession about exceptions, domains which should be not routed through the proxy?

This are constants for this on OS X (

kCFNetworkProxiesExceptionsList
and
kSCPropNetProxiesExceptionsList
) but none of them are public on iOS. Again, you should file a bug about this.

If you do file any bugs here, please make sure to post the bug numbers, just for the record.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

I've sent an enhancement request #25876726

Thanks for the Tip Eskimo. I was having the same issue for HTTPS not going through the proxy.

So, assuming all the constatns have the same value, I used the following and now, I am able to see both http and https requests via proxy.

is this safe to use?


NSDictionary *proxyDict = @{

@"HTTPEnable":[NSNumber numberWithInt:1],

@"HTTPProxy":proxyHost,

@"HTTPPort":proxyPort,

@"HTTPSEnable":[NSNumber numberWithInt:1],

@"HTTPSProxy":proxyHost,

@"HTTPSPort":proxyPort

};

Quinn - Can we get a response please? 😟


Since, the following API is deprectaed in iOS9 -


CFN_EXPORT const CFStringRef kCFStreamPropertyHTTPSProxyHost CF_DEPRECATED(10_2, 10_11, 2_0, 9_0, "Use NSURLSession API for http requests");
/ matches kSCPropNetProxiesHTTPSProxy */
CFN_EXPORT const CFStringRef kCFStreamPropertyHTTPSProxyPort CF_DEPRECATED(10_2, 10_11, 2_0, 9_0, "Use NSURLSession API for http requests");
/ matches kSCPropNetProxiesHTTPSPort */


Would it be fair to use this configuration for both HTTP and HTTPS outbound calls for a proxy?


    NSDictionary *proxyDict = @{
                                @"HTTPEnable":[NSNumber numberWithInt:1],
                                @"HTTPProxy":proxyHost,
                                @"HTTPPort":proxyPort,
                                @"HTTPSEnable":[NSNumber numberWithInt:1],
                                @"HTTPSProxy":proxyHost,
                                @"HTTPSPort":proxyPort
                                };


rather than:


    NSDictionary *proxyDict = @{
                                (NSString *)kCFNetworkProxiesHTTPEnable:[NSNumber numberWithInt:1],
                                (NSString *)kCFNetworkProxiesHTTPProxy:proxyHost,
                                (NSString *)kCFNetworkProxiesHTTPPort:proxyPort
                                };

Does iOS Simulator on macOS Monterey use the proxies set in System Preferences ?

Does iOS Simulator on macOS Monterey use the proxies set in System Preferences ?

That’s an interesting question. On the one hand, the simulator does not have its own networking stack, relying on macOS’s one, so there’s nowhere to configure proxies in the sim itself. OTOH, proxy support is done in user space and thus the sim would have to pick up those settings from the host macOS. Interesting.

In short, I don’t know for sure. Try it out and let us know what you see. And if doesn’t work, that’s definitely bugworthy.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"