OLD | NEW |
1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #import "ios/net/crn_http_protocol_handler.h" | 5 #import "ios/net/crn_http_protocol_handler.h" |
6 | 6 |
7 #include <stdint.h> | 7 #include <stdint.h> |
8 | 8 |
9 #include <memory> | 9 #include <memory> |
10 #include <utility> | 10 #include <utility> |
(...skipping 947 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
958 base::Bind(&net::HttpProtocolHandlerCore::Cancel, _core)); | 958 base::Bind(&net::HttpProtocolHandlerCore::Cancel, _core)); |
959 [_protocolProxy invalidate]; | 959 [_protocolProxy invalidate]; |
960 } | 960 } |
961 | 961 |
962 - (void)stopLoading { | 962 - (void)stopLoading { |
963 [self cancelRequest]; | 963 [self cancelRequest]; |
964 _protocolProxy.reset(); | 964 _protocolProxy.reset(); |
965 } | 965 } |
966 | 966 |
967 @end | 967 @end |
968 | |
969 #pragma mark - | |
970 #pragma mark PauseableHttpProtocolHandler | |
971 | |
972 // The HttpProtocolHandler is called by the iOS system to handle the | |
973 // NSURLRequest. This HttpProtocolHandler conforms to the observed semantics of | |
974 // NSURLProtocol when used with NSURLSession on iOS 8 - i.e., |-startLoading| | |
975 // means "start or resume request" and |-stopLoading| means "pause request". | |
976 // Since there is no way to actually pause a request in the network stack, this | |
977 // is implemented using a subclass of CRNHTTPProtocolHandlerProxy that knows how | |
978 // to defer callbacks. | |
979 // | |
980 // Note that this class conforms to somewhat complex threading rules: | |
981 // 1) |initWithRequest:cachedResponse:client:| and |dealloc| can be called on | |
982 // any thread. | |
983 // 2) |startLoading| and |stopLoading| are always called on the client thread. | |
984 // 3) |stopLoading| is called before |dealloc| is called. | |
985 // | |
986 // The main wrinkle is that |dealloc|, which may be called on any thread, needs | |
987 // to clean up a running network request. To do this, |dealloc| needs to run | |
988 // |cancelRequest|, which needs to be run on the client thread. Since it is | |
989 // guaranteed that |startLoading| is called before |dealloc| is called, the | |
990 // |startLoading| method stores a pointer to the client thread, then |dealloc| | |
991 // asks that client thread to perform the |cancelRequest| selector via | |
992 // |scheduleCancelRequest|. | |
993 // | |
994 // Some of the above logic is implemented in the parent class | |
995 // (CRNHTTPProtocolHandler) because it is convenient. | |
996 @implementation CRNPauseableHTTPProtocolHandler { | |
997 BOOL _started; | |
998 dispatch_queue_t _queue; | |
999 } | |
1000 | |
1001 #pragma mark NSURLProtocol methods | |
1002 | |
1003 - (void)dealloc { | |
1004 [self scheduleCancelRequest]; | |
1005 } | |
1006 | |
1007 #pragma mark NSURLProtocol overrides. | |
1008 | |
1009 - (void)startLoading { | |
1010 if (_started) { | |
1011 [[self getProtocolHandlerProxy] resume]; | |
1012 return; | |
1013 } | |
1014 | |
1015 _started = YES; | |
1016 [super startLoading]; | |
1017 } | |
1018 | |
1019 - (void)stopLoading { | |
1020 [[self getProtocolHandlerProxy] pause]; | |
1021 } | |
1022 | |
1023 // This method has unusual concurrency properties. It can be called on any | |
1024 // thread, but it must be called from |-dealloc|, which guarantees that no other | |
1025 // method of this object is running concurrently (since |-dealloc| is only | |
1026 // called when the last reference to the object drops). | |
1027 // | |
1028 // This method takes a reference to _core to ensure that _core lives long enough | |
1029 // to have the request cleanly cancelled. | |
1030 - (void)scheduleCancelRequest { | |
1031 DeferredCancellation* cancellation = | |
1032 [[DeferredCancellation alloc] initWithCore:[self getCore]]; | |
1033 NSArray* modes = @[ [[NSRunLoop currentRunLoop] currentMode] ]; | |
1034 [cancellation performSelector:@selector(cancel) | |
1035 onThread:[self getClientThread] | |
1036 withObject:nil | |
1037 waitUntilDone:NO | |
1038 modes:modes]; | |
1039 } | |
1040 | |
1041 @end | |
OLD | NEW |