Skip to content

Commit

Permalink
Merge fix #96 for threading issue
Browse files Browse the repository at this point in the history
  • Loading branch information
AliSoftware committed May 3, 2015
2 parents 5c67eef + feeef16 commit ec8dee7
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 12 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
_You can download previous versions [here](https://github.com/AliSoftware/OHHTTPStubs/tags) and latest version [here](https://github.com/AliSoftware/OHHTTPStubs/zipball/master) (ZIP files generated by GitHub on the fly)_

## [4.0.1](https://github.com/AliSoftware/OHHTTPStubs/releases/tag/4.0.1)

* Fix threading in `NSURLProtocol` subclass calling `NSURLProtocolClient` callbacks from wrong thread. ([@nsprogrammer](https://github.com/nsprogrammer), [#96](https://github.com/AliSoftware/OHHTTPStubs/pull/96))

## [4.0.0](https://github.com/AliSoftware/OHHTTPStubs/releases/tag/4.0.0) — Improvements for Swift

* Annotated the library with _nullability_ attributes to generate a better API when used in Swift
Expand Down
30 changes: 18 additions & 12 deletions OHHTTPStubs/Sources/OHHTTPStubs.m
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,8 @@ - (OHHTTPStubsDescriptor*)firstStubPassingTestForRequest:(NSURLRequest*)request
@interface OHHTTPStubsProtocol()
@property(assign) BOOL stopped;
@property(strong) OHHTTPStubsDescriptor* stub;
@property(assign) CFRunLoopRef clientRunLoop;
- (void)executeOnClientRunLoopAfterDelay:(NSTimeInterval)delayInSeconds block:(dispatch_block_t)block;
@end

@implementation OHHTTPStubsProtocol
Expand Down Expand Up @@ -298,6 +300,7 @@ - (NSCachedURLResponse *)cachedResponse

- (void)startLoading
{
self.clientRunLoop = CFRunLoopGetCurrent();
NSURLRequest* request = self.request;
id<NSURLProtocolClient> client = self.client;

Expand Down Expand Up @@ -354,16 +357,16 @@ - (void)startLoading
if (((responseStub.statusCode > 300) && (responseStub.statusCode < 400)) && redirectLocationURL)
{
NSURLRequest* redirectRequest = [NSURLRequest requestWithURL:redirectLocationURL];
execute_after(responseStub.requestTime, ^{
[self executeOnClientRunLoopAfterDelay:responseStub.requestTime block:^{
if (!self.stopped)
{
[client URLProtocol:self wasRedirectedToRequest:redirectRequest redirectResponse:urlResponse];
}
});
}];
}
else
{
execute_after(responseStub.requestTime,^{
[self executeOnClientRunLoopAfterDelay:responseStub.requestTime block:^{
if (!self.stopped)
{
[client URLProtocol:self didReceiveResponse:urlResponse cacheStoragePolicy:NSURLCacheStorageNotAllowed];
Expand All @@ -386,16 +389,16 @@ - (void)startLoading
}
}];
}
});
}];
}
} else {
// Send the canned error
execute_after(responseStub.responseTime, ^{
[self executeOnClientRunLoopAfterDelay:responseStub.responseTime block:^{
if (!self.stopped)
{
[client URLProtocol:self didFailWithError:responseStub.error];
}
});
}];
}
}

Expand Down Expand Up @@ -471,10 +474,10 @@ - (void) streamDataForClient:(id<NSURLProtocolClient>)client
if (chunkSizeToRead == 0)
{
// Nothing to read at this pass, but probably later
execute_after(timingInfo.slotTime, ^{
[self executeOnClientRunLoopAfterDelay:timingInfo.slotTime block:^{
[self streamDataForClient:client fromStream:inputStream
timingInfo:timingInfo completion:completion];
});
}];
} else {
uint8_t* buffer = (uint8_t*)malloc(sizeof(uint8_t)*chunkSizeToRead);
NSInteger bytesRead = [inputStream read:buffer maxLength:chunkSizeToRead];
Expand All @@ -483,11 +486,11 @@ - (void) streamDataForClient:(id<NSURLProtocolClient>)client
NSData * data = [NSData dataWithBytes:buffer length:bytesRead];
// Wait for 'slotTime' seconds before sending the chunk.
// If bytesRead < chunkSizePerSlot (because we are near the EOF), adjust slotTime proportionally to the bytes remaining
execute_after(((double)bytesRead / (double)chunkSizeToRead) * timingInfo.slotTime, ^{
[self executeOnClientRunLoopAfterDelay:((double)bytesRead / (double)chunkSizeToRead) * timingInfo.slotTime block:^{
[client URLProtocol:self didLoadData:data];
[self streamDataForClient:client fromStream:inputStream
timingInfo:timingInfo completion:completion];
});
}];
}
else
{
Expand Down Expand Up @@ -515,10 +518,13 @@ - (void) streamDataForClient:(id<NSURLProtocolClient>)client
// Delayed execution utility methods
/////////////////////////////////////////////

static void execute_after(NSTimeInterval delayInSeconds, dispatch_block_t block)
- (void)executeOnClientRunLoopAfterDelay:(NSTimeInterval)delayInSeconds block:(dispatch_block_t)block
{
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), block);
dispatch_after(popTime, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
CFRunLoopPerformBlock(self.clientRunLoop, kCFRunLoopDefaultMode, block);
CFRunLoopWakeUp(self.clientRunLoop);
});
}

@end

0 comments on commit ec8dee7

Please sign in to comment.