| 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 "base/command_line.h" | 7 #include "base/command_line.h" |
| 8 #include "base/logging.h" | 8 #include "base/logging.h" |
| 9 #include "base/mac/bind_objc_block.h" | 9 #include "base/mac/bind_objc_block.h" |
| 10 #include "base/mac/scoped_nsobject.h" | 10 #include "base/mac/scoped_nsobject.h" |
| (...skipping 848 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 859 _core = core; | 859 _core = core; |
| 860 return self; | 860 return self; |
| 861 } | 861 } |
| 862 | 862 |
| 863 - (void)stream:(NSStream*)theStream handleEvent:(NSStreamEvent)streamEvent { | 863 - (void)stream:(NSStream*)theStream handleEvent:(NSStreamEvent)streamEvent { |
| 864 _core->HandleStreamEvent(theStream, streamEvent); | 864 _core->HandleStreamEvent(theStream, streamEvent); |
| 865 } | 865 } |
| 866 @end | 866 @end |
| 867 | 867 |
| 868 #pragma mark - | 868 #pragma mark - |
| 869 #pragma mark DeferredCancellation |
| 870 |
| 871 // An object of class |DeferredCancellation| represents a deferred cancellation |
| 872 // of a request. In principle this is a block posted to a thread's runloop, but |
| 873 // since there is no performBlock:onThread:, this class wraps the desired |
| 874 // behavior in an object. |
| 875 @interface DeferredCancellation : NSObject |
| 876 |
| 877 - (instancetype)initWithCore:(scoped_refptr<net::HttpProtocolHandlerCore>)core; |
| 878 - (void)cancel; |
| 879 |
| 880 @end |
| 881 |
| 882 @implementation DeferredCancellation { |
| 883 scoped_refptr<net::HttpProtocolHandlerCore> _core; |
| 884 } |
| 885 |
| 886 - (instancetype)initWithCore:(scoped_refptr<net::HttpProtocolHandlerCore>)core { |
| 887 if ((self = [super init])) { |
| 888 _core = core; |
| 889 } |
| 890 return self; |
| 891 } |
| 892 |
| 893 - (void)cancel { |
| 894 g_protocol_handler_delegate->GetDefaultURLRequestContext() |
| 895 ->GetNetworkTaskRunner() |
| 896 ->PostTask(FROM_HERE, |
| 897 base::Bind(&net::HttpProtocolHandlerCore::Cancel, _core)); |
| 898 } |
| 899 |
| 900 @end |
| 901 |
| 902 #pragma mark - |
| 869 #pragma mark HttpProtocolHandler | 903 #pragma mark HttpProtocolHandler |
| 870 | 904 |
| 905 @interface CRNHTTPProtocolHandler (Private) |
| 906 |
| 907 - (id<CRNHTTPProtocolHandlerProxy>)getProtocolHandlerProxy; |
| 908 - (scoped_refptr<net::HttpProtocolHandlerCore>)getCore; |
| 909 - (NSThread*)getClientThread; |
| 910 - (void)cancelRequest; |
| 911 |
| 912 @end |
| 913 |
| 871 // The HttpProtocolHandler is called by the iOS system to handle the | 914 // The HttpProtocolHandler is called by the iOS system to handle the |
| 872 // NSURLRequest. | 915 // NSURLRequest. |
| 873 @implementation CRNHTTPProtocolHandler { | 916 @implementation CRNHTTPProtocolHandler { |
| 874 scoped_refptr<net::HttpProtocolHandlerCore> _core; | 917 scoped_refptr<net::HttpProtocolHandlerCore> _core; |
| 875 base::scoped_nsprotocol<id<CRNHTTPProtocolHandlerProxy>> _protocolProxy; | 918 base::scoped_nsprotocol<id<CRNHTTPProtocolHandlerProxy>> _protocolProxy; |
| 919 NSThread* _clientThread; |
| 920 NSString* _clientRunLoopMode; |
| 876 BOOL _supportedURL; | 921 BOOL _supportedURL; |
| 877 } | 922 } |
| 878 | 923 |
| 879 #pragma mark NSURLProtocol methods | 924 #pragma mark NSURLProtocol methods |
| 880 | 925 |
| 881 + (BOOL)canInitWithRequest:(NSURLRequest*)request { | 926 + (BOOL)canInitWithRequest:(NSURLRequest*)request { |
| 882 DVLOG(5) << "canInitWithRequest " << net::FormatUrlRequestForLogging(request); | 927 DVLOG(5) << "canInitWithRequest " << net::FormatUrlRequestForLogging(request); |
| 883 return g_protocol_handler_delegate->CanHandleRequest(request); | 928 return g_protocol_handler_delegate->CanHandleRequest(request); |
| 884 } | 929 } |
| 885 | 930 |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 923 if (url) | 968 if (url) |
| 924 [dictionary setObject:url forKey:NSURLErrorKey]; | 969 [dictionary setObject:url forKey:NSURLErrorKey]; |
| 925 | 970 |
| 926 NSError* error = [NSError errorWithDomain:NSURLErrorDomain | 971 NSError* error = [NSError errorWithDomain:NSURLErrorDomain |
| 927 code:NSURLErrorUnsupportedURL | 972 code:NSURLErrorUnsupportedURL |
| 928 userInfo:dictionary]; | 973 userInfo:dictionary]; |
| 929 [[self client] URLProtocol:self didFailWithError:error]; | 974 [[self client] URLProtocol:self didFailWithError:error]; |
| 930 return; | 975 return; |
| 931 } | 976 } |
| 932 | 977 |
| 933 _protocolProxy.reset([[CRNHTTPProtocolHandlerProxyWithClientThread alloc] | 978 _clientThread = [NSThread currentThread]; |
| 934 initWithProtocol:self | 979 |
| 935 clientThread:[NSThread currentThread] | |
| 936 runLoopMode:[[NSRunLoop currentRunLoop] currentMode]]); | |
| 937 g_protocol_handler_delegate->GetDefaultURLRequestContext() | 980 g_protocol_handler_delegate->GetDefaultURLRequestContext() |
| 938 ->GetNetworkTaskRunner() | 981 ->GetNetworkTaskRunner() |
| 939 ->PostTask(FROM_HERE, base::Bind(&net::HttpProtocolHandlerCore::Start, | 982 ->PostTask(FROM_HERE, base::Bind(&net::HttpProtocolHandlerCore::Start, |
| 940 _core, _protocolProxy)); | 983 _core, [self getProtocolHandlerProxy])); |
| 941 } | 984 } |
| 942 | 985 |
| 943 - (void)stopLoading { | 986 - (id<CRNHTTPProtocolHandlerProxy>)getProtocolHandlerProxy { |
| 987 DCHECK_EQ([NSThread currentThread], _clientThread); |
| 988 if (!_protocolProxy.get()) { |
| 989 _protocolProxy.reset([[CRNHTTPProtocolHandlerProxyWithClientThread alloc] |
| 990 initWithProtocol:self |
| 991 clientThread:_clientThread |
| 992 runLoopMode:[[NSRunLoop currentRunLoop] currentMode]]); |
| 993 } |
| 994 return _protocolProxy.get(); |
| 995 } |
| 996 |
| 997 - (scoped_refptr<net::HttpProtocolHandlerCore>)getCore { |
| 998 return _core; |
| 999 } |
| 1000 |
| 1001 - (NSThread*)getClientThread { |
| 1002 return _clientThread; |
| 1003 } |
| 1004 |
| 1005 - (void)cancelRequest { |
| 944 g_protocol_handler_delegate->GetDefaultURLRequestContext() | 1006 g_protocol_handler_delegate->GetDefaultURLRequestContext() |
| 945 ->GetNetworkTaskRunner() | 1007 ->GetNetworkTaskRunner() |
| 946 ->PostTask(FROM_HERE, | 1008 ->PostTask(FROM_HERE, |
| 947 base::Bind(&net::HttpProtocolHandlerCore::Cancel, _core)); | 1009 base::Bind(&net::HttpProtocolHandlerCore::Cancel, _core)); |
| 948 [_protocolProxy invalidate]; | 1010 [_protocolProxy invalidate]; |
| 1011 } |
| 1012 |
| 1013 - (void)stopLoading { |
| 1014 [self cancelRequest]; |
| 949 _protocolProxy.reset(); | 1015 _protocolProxy.reset(); |
| 950 } | 1016 } |
| 951 | 1017 |
| 952 @end | 1018 @end |
| 1019 |
| 1020 #pragma mark - |
| 1021 #pragma mark PauseableHttpProtocolHandler |
| 1022 |
| 1023 // The HttpProtocolHandler is called by the iOS system to handle the |
| 1024 // NSURLRequest. This HttpProtocolHandler conforms to the observed semantics of |
| 1025 // NSURLProtocol when used with NSURLSession on iOS 8 - i.e., |-startLoading| |
| 1026 // means "start or resume request" and |-stopLoading| means "pause request". |
| 1027 // Since there is no way to actually pause a request in the network stack, this |
| 1028 // is implemented using a subclass of CRNHTTPProtocolHandlerProxy that knows how |
| 1029 // to defer callbacks. |
| 1030 // |
| 1031 // Note that this class conforms to somewhat complex threading rules: |
| 1032 // 1) |initWithRequest:cachedResponse:client:| and |dealloc| can be called on |
| 1033 // any thread. |
| 1034 // 2) |startLoading| and |stopLoading| are always called on the client thread. |
| 1035 // 3) |stopLoading| is called before |dealloc| is called. |
| 1036 // |
| 1037 // The main wrinkle is that |dealloc|, which may be called on any thread, needs |
| 1038 // to clean up a running network request. To do this, |dealloc| needs to run |
| 1039 // |cancelRequest|, which needs to be run on the client thread. Since it is |
| 1040 // guaranteed that |startLoading| is called before |dealloc| is called, the |
| 1041 // |startLoading| method stores a pointer to the client thread, then |dealloc| |
| 1042 // asks that client thread to perform the |cancelRequest| selector via |
| 1043 // |scheduleCancelRequest|. |
| 1044 // |
| 1045 // Some of the above logic is implemented in the parent class |
| 1046 // (CRNHTTPProtocolHandler) because it is convenient. |
| 1047 @implementation CRNPauseableHTTPProtocolHandler { |
| 1048 BOOL _started; |
| 1049 dispatch_queue_t _queue; |
| 1050 } |
| 1051 |
| 1052 #pragma mark NSURLProtocol methods |
| 1053 |
| 1054 - (void)dealloc { |
| 1055 [self scheduleCancelRequest]; |
| 1056 [super dealloc]; |
| 1057 } |
| 1058 |
| 1059 #pragma mark NSURLProtocol overrides. |
| 1060 |
| 1061 - (void)startLoading { |
| 1062 if (_started) { |
| 1063 [[self getProtocolHandlerProxy] resume]; |
| 1064 return; |
| 1065 } |
| 1066 |
| 1067 _started = YES; |
| 1068 [super startLoading]; |
| 1069 } |
| 1070 |
| 1071 - (void)stopLoading { |
| 1072 [[self getProtocolHandlerProxy] pause]; |
| 1073 } |
| 1074 |
| 1075 // This method has unusual concurrency properties. It can be called on any |
| 1076 // thread, but it must be called from |-dealloc|, which guarantees that no other |
| 1077 // method of this object is running concurrently (since |-dealloc| is only |
| 1078 // called when the last reference to the object drops). |
| 1079 // |
| 1080 // This method takes a reference to _core to ensure that _core lives long enough |
| 1081 // to have the request cleanly cancelled. |
| 1082 - (void)scheduleCancelRequest { |
| 1083 DeferredCancellation* cancellation = |
| 1084 [[DeferredCancellation alloc] initWithCore:[self getCore]]; |
| 1085 NSArray* modes = @[ [[NSRunLoop currentRunLoop] currentMode] ]; |
| 1086 [cancellation performSelector:@selector(cancel) |
| 1087 onThread:[self getClientThread] |
| 1088 withObject:nil |
| 1089 waitUntilDone:NO |
| 1090 modes:modes]; |
| 1091 } |
| 1092 |
| 1093 @end |
| OLD | NEW |