4

I have a custom URLProtocol where I want to redirect all traffic via a proxy server.

My current working code looks like that:

+(BOOL)canInitWithRequest:(NSURLRequest*)request
{
    if ([NSURLProtocol propertyForKey:protocolKey inRequest:request])
        return NO;
    NSString *scheme = request.URL.scheme.lowercaseString;
    return [scheme isEqualToString:@"http"] || [scheme isEqualToString:@"https"];
}
-(void)startLoading
{
    NSMutableURLRequest *request = self.request.mutableCopy;
    [NSURLProtocol setProperty:@YES forKey:protocolKey inRequest:request];
    NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
    config.requestCachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
    config.connectionProxyDictionary = @
    {
        (id)kCFNetworkProxiesHTTPEnable:@YES,
        (id)kCFNetworkProxiesHTTPProxy:@"1.2.3.4",
        (id)kCFNetworkProxiesHTTPPort:@8080
    };
    m_session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:[NSOperationQueue currentQueue]];
    [[m_session dataTaskWithRequest:request] resume];
}

This works great so far. The problem is that there are some url's which use redirection - and I want the redirection to be performed by the proxy server as well, rather than by the device. I've tried to add the following code, but it didn't help:

-(void)URLSession:(NSURLSession*)session task:(NSURLSessionTask*)task willPerformHTTPRedirection:(NSHTTPURLResponse*)response newRequest:(NSURLRequest*)newRequest completionHandler:(void (^)(NSURLRequest*))completionHandler
{
    NSMutableURLRequest *request = newRequest.mutableCopy;
    [NSURLProtocol removePropertyForKey:protocolKey inRequest:request];
    [self.client URLProtocol:self wasRedirectedToRequest:request redirectResponse:response];
    [task cancel];
    [self.client URLProtocol:self didFailWithError:[NSError errorWithDomain:NSCocoaErrorDomain code:NSUserCancelledError userInfo:nil]];
}

The problem is that the new request is not being sent to the proxy server but instead being redirected by the device itself.

Thanks.

Gilad Novik
  • 4,546
  • 4
  • 41
  • 58
  • What is m_session in `-(void)startLoading`? Any chance you could post your full URLProtocol file please? – Sam Heather Feb 25 '16 at 18:54
  • 1
    @SamHeather m_session is just where I save the NSURLSession instance. There is a great tutorial (which uses NSURLConnection instead) which I've used as a starting point: http://www.raywenderlich.com/59982/nsurlprotocol-tutorial – Gilad Novik Feb 25 '16 at 21:25
  • Do you happen to have any idea how to apply the connectionProxy to NSURLConnection or NSMutableURLRequest? Finding the docs a touch lacking in this... – Sam Heather Feb 25 '16 at 21:56
  • 1
    I think that was the reason I eventually switched to NSURLSession. You can do it also with NSURLConnection - but it's much more complicated. Use the link I posted as the skeleton and use NSURLSession instead of NSURLConnection with my proxy example. My current code is proprietary for a client and I'm not allowed to post it. If I'll have time, I might post a basic example of it. – Gilad Novik Feb 25 '16 at 22:24
  • agreed, NSURLSession seems easier. I've posted my code and asked the question, hopefully we can find an answer and maybe it saves you posting an example :) http://stackoverflow.com/questions/35639740/using-nsurlsession-inside-nsurlprotocol – Sam Heather Feb 25 '16 at 22:33

1 Answers1

2

It turned out the problem was with the redirection for an HTTPS server, while there is no HTTPS proxy defined. To use HTTPS proxy, the code should looks like:

config.connectionProxyDictionary = @
{
    @"HTTPEnable":@YES,
    (id)kCFStreamPropertyHTTPProxyHost:@"1.2.3.4",
    (id)kCFStreamPropertyHTTPProxyPort:@8080,
    @"HTTPSEnable":@YES,
    (id)kCFStreamPropertyHTTPSProxyHost:@"1.2.3.4",
    (id)kCFStreamPropertyHTTPSProxyPort:@8080
};

Source: How to programmatically add a proxy to an NSURLSession

Community
  • 1
  • 1
Gilad Novik
  • 4,546
  • 4
  • 41
  • 58