Question

I subclassed a NSURLConnection in order to call web services using ssl. I thought about doing it synchronous and not only asynchronous connection as it's now.

My code:

#import "SecureSSLConnection.h"

static NSMutableArray *sharedConnectionList = nil;

@implementation SecureSSLConnection
@synthesize request, completionBlock, internalConnection;

- (id)initWithRequest:(NSMutableURLRequest *)req
{
    self = [super init];
    if (self) {
        self.request = req;
    }
    return self;
}

- (void)start
{
    container = [NSMutableData new];
    internalConnection = [[NSURLConnection alloc] initWithRequest:self.request delegate:self startImmediately:YES];

    if (!sharedConnectionList) {
        sharedConnectionList = [NSMutableArray new];
    }
    [sharedConnectionList addObject:self];    
}

#pragma mark - NSURLConnectionDelegate

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    [container appendData:data];
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    if (self.completionBlock) {
        self.completionBlock(container, nil);
    }

    [sharedConnectionList removeObject:self];
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
    if (self.completionBlock) {
        self.completionBlock(nil, error);
    }

    [sharedConnectionList removeObject:self];
}

#pragma mark - SSL Connection Addition

- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace
{
    return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust];
}

- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
    NSLog(@"challenge.protectionSpace.host: %@", challenge.protectionSpace.host);

    if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
        // We only trust our own domain
        if ([challenge.protectionSpace.host isEqualToString:WebSiteURL]) {
            NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
            [challenge.sender useCredential:credential forAuthenticationChallenge:challenge];
        }
    }

    [challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
}

I started thinking about implementing:

+ (NSData *)sendSynchronousRequest:(NSURLRequest *)request returningResponse:(NSURLResponse **)response error:(NSError **)error

In order to keep it the same as original delegate.

One way is using NSNotificationCenter but my goal is much easier method for it.

Any ideas how should I doing it?

Was it helpful?

Solution

I would not suggest making this synchronous. You invariably want to keep your network requests asynchronous.

The simple solution is to employ your completion block property. Simply put other tasks that are dependent upon your initial SSL request inside the completion block of the first request. That way, they won't start until the first completes.

The more elegant solution is to take this a step further, and wrap your SSL request in a concurrent NSOperation subclass. That way, you can employ not only the above completion block pattern, but you can use the addDependency of subsequent operations and maxConcurrentOperationCount of the NSOperationQueue to really refine the dynamics between various operations. This is non-trivial, but you can see AFNetworking for an example of a relatively well thought-out implementation of this pattern.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top