| Index: ios/net/crn_http_protocol_handler.mm
|
| diff --git a/ios/net/crn_http_protocol_handler.mm b/ios/net/crn_http_protocol_handler.mm
|
| index d2855b4e2aebe73594100d0c81cdb470557ab22d..bb9ac3b279565d8253a5c71e5f389356d34f57f7 100644
|
| --- a/ios/net/crn_http_protocol_handler.mm
|
| +++ b/ios/net/crn_http_protocol_handler.mm
|
| @@ -1030,3 +1030,77 @@
|
| }
|
|
|
| @end
|
| +
|
| +#pragma mark -
|
| +#pragma mark PauseableHttpProtocolHandler
|
| +
|
| +// The HttpProtocolHandler is called by the iOS system to handle the
|
| +// NSURLRequest. This HttpProtocolHandler conforms to the observed semantics of
|
| +// NSURLProtocol when used with NSURLSession on iOS 8 - i.e., |-startLoading|
|
| +// means "start or resume request" and |-stopLoading| means "pause request".
|
| +// Since there is no way to actually pause a request in the network stack, this
|
| +// is implemented using a subclass of CRNHTTPProtocolHandlerProxy that knows how
|
| +// to defer callbacks.
|
| +//
|
| +// Note that this class conforms to somewhat complex threading rules:
|
| +// 1) |initWithRequest:cachedResponse:client:| and |dealloc| can be called on
|
| +// any thread.
|
| +// 2) |startLoading| and |stopLoading| are always called on the client thread.
|
| +// 3) |stopLoading| is called before |dealloc| is called.
|
| +//
|
| +// The main wrinkle is that |dealloc|, which may be called on any thread, needs
|
| +// to clean up a running network request. To do this, |dealloc| needs to run
|
| +// |cancelRequest|, which needs to be run on the client thread. Since it is
|
| +// guaranteed that |startLoading| is called before |dealloc| is called, the
|
| +// |startLoading| method stores a pointer to the client thread, then |dealloc|
|
| +// asks that client thread to perform the |cancelRequest| selector via
|
| +// |scheduleCancelRequest|.
|
| +//
|
| +// Some of the above logic is implemented in the parent class
|
| +// (CRNHTTPProtocolHandler) because it is convenient.
|
| +@implementation CRNPauseableHTTPProtocolHandler {
|
| + BOOL _started;
|
| + dispatch_queue_t _queue;
|
| +}
|
| +
|
| +#pragma mark NSURLProtocol methods
|
| +
|
| +- (void)dealloc {
|
| + [self scheduleCancelRequest];
|
| +}
|
| +
|
| +#pragma mark NSURLProtocol overrides.
|
| +
|
| +- (void)startLoading {
|
| + if (_started) {
|
| + [[self getProtocolHandlerProxy] resume];
|
| + return;
|
| + }
|
| +
|
| + _started = YES;
|
| + [super startLoading];
|
| +}
|
| +
|
| +- (void)stopLoading {
|
| + [[self getProtocolHandlerProxy] pause];
|
| +}
|
| +
|
| +// This method has unusual concurrency properties. It can be called on any
|
| +// thread, but it must be called from |-dealloc|, which guarantees that no other
|
| +// method of this object is running concurrently (since |-dealloc| is only
|
| +// called when the last reference to the object drops).
|
| +//
|
| +// This method takes a reference to _core to ensure that _core lives long enough
|
| +// to have the request cleanly cancelled.
|
| +- (void)scheduleCancelRequest {
|
| + DeferredCancellation* cancellation =
|
| + [[DeferredCancellation alloc] initWithCore:[self getCore]];
|
| + NSArray* modes = @[ [[NSRunLoop currentRunLoop] currentMode] ];
|
| + [cancellation performSelector:@selector(cancel)
|
| + onThread:[self getClientThread]
|
| + withObject:nil
|
| + waitUntilDone:NO
|
| + modes:modes];
|
| +}
|
| +
|
| +@end
|
|
|