Question

I am trying to make a subclass to NSURLProtocol. However, I am noticing that I seem to lose caching functionality when I register my subclass, even though it shouldn't do anything. For example, if I do [NSURLConnection sendSynchronousRequest...] multiple times to the same URL without registering the subclass, it only performs one actual http request. With this subclass registered, it performs a network request every time.

Here is my code:

@interface CustomURLProtocol : NSURLProtocol
@property (nonatomic, strong) NSURLConnection *connection;
@end

@implementation CustomURLProtocol

+ (BOOL)canInitWithRequest:(NSURLRequest *)request {
    return [[[request URL] scheme] isEqualToString:@"http"] &&
           [NSURLProtocol propertyForKey:@"tagged" inRequest:request] == nil;
}

+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request {
    return request;
}

- (void)startLoading {
    NSMutableURLRequest *newRequest = [self.request mutableCopy];
    [NSURLProtocol setProperty:@YES forKey:@"tagged" inRequest:newRequest];
    self.connection = [NSURLConnection connectionWithRequest:newRequest delegate:self];
}

- (void)stopLoading {
    [self.connection cancel];
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    [[self client] URLProtocol:self didLoadData:data];
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    [[self client] URLProtocol:self didFailWithError:error];
    self.connection = nil;
}

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
    [[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:[[self request] cachePolicy]];
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection  {
    [[self client] URLProtocolDidFinishLoading:self];
    self.connection = nil;
}
@end

No correct solution

OTHER TIPS

The issue here was not what I expected. The real problem was that redirects were not being handled correctly, since the following code was not there:

- (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)response {
  [[self client] URLProtocol:self wasRedirectedToRequest:request redirectResponse:response];
  return request;
}

Without this code, redirects were not being cached so requests so sequential requests to a redirected URL like wikipedia.com resulted in redirects every single time.

I think the line you added is just to skip your custom NSURLProtocol. After adding this method, are those connectionDelegate methods still being called ?

Update: Finally figured this out. This is the reason. I made it work after adding this part into startLoading.

NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:self.request];
    if (cachedResponse) {  
        [self connection:nil didReceiveResponse:[cachedResponse response]];
        [self connection:nil didReceiveData:[cachedResponse data]];
        [self connectionDidFinishLoading:nil];
    } else {
        _connection = [NSURLConnection connectionWithRequest:newRequest delegate:self];
    }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top