| 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 1012 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1023 base::Bind(&net::HttpProtocolHandlerCore::Cancel, _core)); | 1023 base::Bind(&net::HttpProtocolHandlerCore::Cancel, _core)); |
| 1024 [_protocolProxy invalidate]; | 1024 [_protocolProxy invalidate]; |
| 1025 } | 1025 } |
| 1026 | 1026 |
| 1027 - (void)stopLoading { | 1027 - (void)stopLoading { |
| 1028 [self cancelRequest]; | 1028 [self cancelRequest]; |
| 1029 _protocolProxy.reset(); | 1029 _protocolProxy.reset(); |
| 1030 } | 1030 } |
| 1031 | 1031 |
| 1032 @end | 1032 @end |
| 1033 |
| 1034 #pragma mark - |
| 1035 #pragma mark PauseableHttpProtocolHandler |
| 1036 |
| 1037 // The HttpProtocolHandler is called by the iOS system to handle the |
| 1038 // NSURLRequest. This HttpProtocolHandler conforms to the observed semantics of |
| 1039 // NSURLProtocol when used with NSURLSession on iOS 8 - i.e., |-startLoading| |
| 1040 // means "start or resume request" and |-stopLoading| means "pause request". |
| 1041 // Since there is no way to actually pause a request in the network stack, this |
| 1042 // is implemented using a subclass of CRNHTTPProtocolHandlerProxy that knows how |
| 1043 // to defer callbacks. |
| 1044 // |
| 1045 // Note that this class conforms to somewhat complex threading rules: |
| 1046 // 1) |initWithRequest:cachedResponse:client:| and |dealloc| can be called on |
| 1047 // any thread. |
| 1048 // 2) |startLoading| and |stopLoading| are always called on the client thread. |
| 1049 // 3) |stopLoading| is called before |dealloc| is called. |
| 1050 // |
| 1051 // The main wrinkle is that |dealloc|, which may be called on any thread, needs |
| 1052 // to clean up a running network request. To do this, |dealloc| needs to run |
| 1053 // |cancelRequest|, which needs to be run on the client thread. Since it is |
| 1054 // guaranteed that |startLoading| is called before |dealloc| is called, the |
| 1055 // |startLoading| method stores a pointer to the client thread, then |dealloc| |
| 1056 // asks that client thread to perform the |cancelRequest| selector via |
| 1057 // |scheduleCancelRequest|. |
| 1058 // |
| 1059 // Some of the above logic is implemented in the parent class |
| 1060 // (CRNHTTPProtocolHandler) because it is convenient. |
| 1061 @implementation CRNPauseableHTTPProtocolHandler { |
| 1062 BOOL _started; |
| 1063 dispatch_queue_t _queue; |
| 1064 } |
| 1065 |
| 1066 #pragma mark NSURLProtocol methods |
| 1067 |
| 1068 - (void)dealloc { |
| 1069 [self scheduleCancelRequest]; |
| 1070 } |
| 1071 |
| 1072 #pragma mark NSURLProtocol overrides. |
| 1073 |
| 1074 - (void)startLoading { |
| 1075 if (_started) { |
| 1076 [[self getProtocolHandlerProxy] resume]; |
| 1077 return; |
| 1078 } |
| 1079 |
| 1080 _started = YES; |
| 1081 [super startLoading]; |
| 1082 } |
| 1083 |
| 1084 - (void)stopLoading { |
| 1085 [[self getProtocolHandlerProxy] pause]; |
| 1086 } |
| 1087 |
| 1088 // This method has unusual concurrency properties. It can be called on any |
| 1089 // thread, but it must be called from |-dealloc|, which guarantees that no other |
| 1090 // method of this object is running concurrently (since |-dealloc| is only |
| 1091 // called when the last reference to the object drops). |
| 1092 // |
| 1093 // This method takes a reference to _core to ensure that _core lives long enough |
| 1094 // to have the request cleanly cancelled. |
| 1095 - (void)scheduleCancelRequest { |
| 1096 DeferredCancellation* cancellation = |
| 1097 [[DeferredCancellation alloc] initWithCore:[self getCore]]; |
| 1098 NSArray* modes = @[ [[NSRunLoop currentRunLoop] currentMode] ]; |
| 1099 [cancellation performSelector:@selector(cancel) |
| 1100 onThread:[self getClientThread] |
| 1101 withObject:nil |
| 1102 waitUntilDone:NO |
| 1103 modes:modes]; |
| 1104 } |
| 1105 |
| 1106 @end |
| OLD | NEW |