Skip navigation.
 
mlNSURLProtocol thread safety
FROM : Jakob Olesen
DATE : Fri Jul 21 00:23:15 2006

Is NSURLProtocol thread safe?

I am subclassing NSURLProtocol to implement a custom URL scheme. I 
need to handle all requests in a particular thread that I created at 
startup. NSURLConnection uses a separate thread for the NSURLProtocol 
instances, so in my -startLoading implementation I forward the 
request to my data processing thread.

Abbreviated code:

-(void)startLoading
{
    isLoading = YES;
    [dataThread queueProtocolRequest:self];  // puts self in a queue 
for data thread to pick up
}

The data thread then delivers data using this method (called in the 
data thread). (I am skipping details with sending the NSURLResponse 
here)

- (void)sendData:(NSData*)data;
{
    if (isLoading)
        [[self client] URLProtocol:self didLoadData:data];
}

Finally, after calling -URLProtocolDidFinishLoading, I get:

-(void)stopLoading
{
    isLoading = NO;
}

So far, so good, this actually works. At least until I start 
cancelling requests. Then I get crashes. I figured out, what 
happened. NSURLConnection is calling -stopLoading just after my data 
thread has entered URLProtocol:didLoadData:. -stopLoading returns 
immediately, and NSURLConnection starts cleaning up. Meanwhile my 
data thread is still running in URLProtocol:didLoadData:. Crash.

So, I added synchronization with an NSRecursiveLock: (Again, I have 
omitted callbacks for setting the response and finishing, they are 
similar)

- (void) sendData:(NSData*)data;
{
    [lock lock];
    if (isLoading)
        [[self client] URLProtocol:self didLoadData:data];
    [lock unlock];
}

-(void)stopLoading
{
    [lock lock];
    isLoading = NO;
    [lock unlock];
}

This way -stopLoading cannot return until the data thread has left 
URLProtocol:didLoadData:, and [self client] will not be called again 
after that in any thread. (Because I check isLoading before each 
call). I can no longer provoke the crash. Everybody is happy.

Except, I still have a bad feeling about this. I am calling the 
NSURLProtocolClient from a different thread. Synchronized, yes, but 
still a different thread. The documentation doesn't mention threading 
at all, except this:
- (void)URLProtocol:(NSURLProtocol *)protocol 
didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)
challenge

[...] The protocol client guarantees that it will answer the request 
on the same thread that called this method. [...]

This comment suggests that the NSURLProtocolClient is thread aware, 
but who knows?



I can only find two code examples of an NSURLProtocol subclass: The 
PictureBrowser example and WebKit's WebDataProtocol (used for 
loadHTMLString:baseURL:) Both are trivial, they do all their work in -
startLoading.



So, am I safe, or do I need to deliver data in the original thread?

Related mailsAuthorDate
No related mails found.