Chromium Code Reviews| 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 @interface DeferredCancellation : NSObject {} | |
| 872 | |
| 873 - (instancetype)initWithCore:(scoped_refptr<net::HttpProtocolHandlerCore>)core; | |
| 874 - (void)cancel; | |
| 875 | |
| 876 @end | |
| 877 | |
| 878 @implementation DeferredCancellation { | |
| 879 scoped_refptr<net::HttpProtocolHandlerCore> _core; | |
| 880 } | |
| 881 | |
| 882 - (instancetype)initWithCore:(scoped_refptr<net::HttpProtocolHandlerCore>)core { | |
| 883 if ((self = [super init])) { | |
| 884 _core.swap(core); | |
|
droger
2015/06/11 08:56:19
Nit: We're not swapping anything here,
_core = cor
Elly Fong-Jones
2015/06/11 13:49:33
Done.
| |
| 885 } | |
| 886 return self; | |
| 887 } | |
| 888 | |
| 889 - (void)cancel { | |
| 890 g_protocol_handler_delegate->GetDefaultURLRequestContext() | |
| 891 ->GetNetworkTaskRunner() | |
| 892 ->PostTask(FROM_HERE, | |
| 893 base::Bind(&net::HttpProtocolHandlerCore::Cancel, _core)); | |
| 894 } | |
| 895 | |
| 896 @end | |
| 897 | |
| 898 #pragma mark - | |
| 869 #pragma mark HttpProtocolHandler | 899 #pragma mark HttpProtocolHandler |
| 870 | 900 |
| 901 @interface CRNHTTPProtocolHandler (Private) {} | |
| 902 | |
| 903 - (id<CRNHTTPProtocolHandlerProxy>)getProtocolHandlerProxy; | |
| 904 - (void)cancelRequest; | |
| 905 | |
| 906 @end | |
| 907 | |
| 871 // The HttpProtocolHandler is called by the iOS system to handle the | 908 // The HttpProtocolHandler is called by the iOS system to handle the |
| 872 // NSURLRequest. | 909 // NSURLRequest. |
| 873 @implementation CRNHTTPProtocolHandler { | 910 @implementation CRNHTTPProtocolHandler { |
| 874 scoped_refptr<net::HttpProtocolHandlerCore> _core; | 911 scoped_refptr<net::HttpProtocolHandlerCore> _core; |
| 875 base::scoped_nsprotocol<id<CRNHTTPProtocolHandlerProxy>> _protocolProxy; | 912 base::scoped_nsprotocol<id<CRNHTTPProtocolHandlerProxy>> _protocolProxy; |
| 913 NSThread* _clientThread; | |
| 914 NSString* _clientRunLoopMode; | |
| 876 BOOL _supportedURL; | 915 BOOL _supportedURL; |
| 877 } | 916 } |
| 878 | 917 |
| 879 #pragma mark NSURLProtocol methods | 918 #pragma mark NSURLProtocol methods |
| 880 | 919 |
| 881 + (BOOL)canInitWithRequest:(NSURLRequest*)request { | 920 + (BOOL)canInitWithRequest:(NSURLRequest*)request { |
| 882 DVLOG(5) << "canInitWithRequest " << net::FormatUrlRequestForLogging(request); | 921 DVLOG(5) << "canInitWithRequest " << net::FormatUrlRequestForLogging(request); |
| 883 return g_protocol_handler_delegate->CanHandleRequest(request); | 922 return g_protocol_handler_delegate->CanHandleRequest(request); |
| 884 } | 923 } |
| 885 | 924 |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 923 if (url) | 962 if (url) |
| 924 [dictionary setObject:url forKey:NSURLErrorKey]; | 963 [dictionary setObject:url forKey:NSURLErrorKey]; |
| 925 | 964 |
| 926 NSError* error = [NSError errorWithDomain:NSURLErrorDomain | 965 NSError* error = [NSError errorWithDomain:NSURLErrorDomain |
| 927 code:NSURLErrorUnsupportedURL | 966 code:NSURLErrorUnsupportedURL |
| 928 userInfo:dictionary]; | 967 userInfo:dictionary]; |
| 929 [[self client] URLProtocol:self didFailWithError:error]; | 968 [[self client] URLProtocol:self didFailWithError:error]; |
| 930 return; | 969 return; |
| 931 } | 970 } |
| 932 | 971 |
| 933 _protocolProxy.reset([[CRNHTTPProtocolHandlerProxyWithClientThread alloc] | 972 _clientThread = [NSThread currentThread]; |
| 934 initWithProtocol:self | 973 |
| 935 clientThread:[NSThread currentThread] | |
| 936 runLoopMode:[[NSRunLoop currentRunLoop] currentMode]]); | |
| 937 g_protocol_handler_delegate->GetDefaultURLRequestContext() | 974 g_protocol_handler_delegate->GetDefaultURLRequestContext() |
| 938 ->GetNetworkTaskRunner() | 975 ->GetNetworkTaskRunner() |
| 939 ->PostTask(FROM_HERE, base::Bind(&net::HttpProtocolHandlerCore::Start, | 976 ->PostTask(FROM_HERE, base::Bind(&net::HttpProtocolHandlerCore::Start, |
| 940 _core, _protocolProxy)); | 977 _core, [self getProtocolHandlerProxy])); |
| 941 } | 978 } |
| 942 | 979 |
| 943 - (void)stopLoading { | 980 - (id<CRNHTTPProtocolHandlerProxy>)getProtocolHandlerProxy { |
|
droger
2015/06/11 08:56:19
DCHECK that the current thread is _clientThread he
Elly Fong-Jones
2015/06/11 13:49:33
Done.
| |
| 981 if (!_protocolProxy.get()) { | |
| 982 _protocolProxy.reset([[CRNHTTPProtocolHandlerProxyWithClientThread alloc] | |
| 983 initWithProtocol:self | |
| 984 clientThread:[NSThread currentThread] | |
|
droger
2015/06/11 08:56:19
Why not using _clientThread here?
Elly Fong-Jones
2015/06/11 13:49:33
Done.
| |
| 985 runLoopMode:[[NSRunLoop currentRunLoop] currentMode]]); | |
| 986 } | |
| 987 return _protocolProxy.get(); | |
| 988 } | |
| 989 | |
| 990 // This method has unusual concurrency properties. It can be called on any | |
| 991 // thread, but it must be called from |-dealloc|, which guarantees that no other | |
| 992 // method of this object is running concurrently (since |-dealloc| is only | |
| 993 // called when the last reference to the object drops). | |
| 994 // | |
| 995 // This method takes a reference to _core to ensure that _core lives long enough | |
| 996 // to have the request cleanly cancelled. | |
| 997 - (void)scheduleCancelRequest { | |
|
droger
2015/06/11 08:56:19
Optional:
Why is this method on CRNHTTPProtocolHa
Elly Fong-Jones
2015/06/11 13:49:33
Done. I have added accessors for _clientThread and
| |
| 998 DeferredCancellation* cancellation = | |
| 999 [[DeferredCancellation alloc] initWithCore:_core]; | |
| 1000 NSArray* modes = @[ [[NSRunLoop currentRunLoop] currentMode] ]; | |
| 1001 [cancellation performSelector:@selector(cancel) | |
| 1002 onThread:_clientThread | |
| 1003 withObject:nil | |
| 1004 waitUntilDone:NO | |
| 1005 modes:modes]; | |
| 1006 } | |
| 1007 | |
| 1008 - (void)cancelRequest { | |
| 944 g_protocol_handler_delegate->GetDefaultURLRequestContext() | 1009 g_protocol_handler_delegate->GetDefaultURLRequestContext() |
| 945 ->GetNetworkTaskRunner() | 1010 ->GetNetworkTaskRunner() |
| 946 ->PostTask(FROM_HERE, | 1011 ->PostTask(FROM_HERE, |
| 947 base::Bind(&net::HttpProtocolHandlerCore::Cancel, _core)); | 1012 base::Bind(&net::HttpProtocolHandlerCore::Cancel, _core)); |
| 948 [_protocolProxy invalidate]; | 1013 [_protocolProxy invalidate]; |
| 1014 } | |
| 1015 | |
| 1016 - (void)stopLoading { | |
| 1017 [self cancelRequest]; | |
| 949 _protocolProxy.reset(); | 1018 _protocolProxy.reset(); |
| 950 } | 1019 } |
| 951 | 1020 |
| 952 @end | 1021 @end |
| 1022 | |
| 1023 #pragma mark - | |
| 1024 #pragma mark PauseableHttpProtocolHandler | |
| 1025 | |
| 1026 // The HttpProtocolHandler is called by the iOS system to handle the | |
| 1027 // NSURLRequest. This HttpProtocolHandler conforms to the observed semantics of | |
| 1028 // NSURLProtocol when used with NSURLSession on iOS 8 - i.e., |-startLoading| | |
| 1029 // means "start or resume request" and |-stopLoading| means "pause request". | |
| 1030 // Since there is no way to actually pause a request in the network stack, this | |
| 1031 // is implemented using a subclass of CRNHTTPProtocolHandlerProxy that knows how | |
| 1032 // to defer callbacks. | |
| 1033 // | |
| 1034 // Note that this class conforms to somewhat complex threading rules: | |
| 1035 // 1) |initWithRequest:cachedResponse:client:| and |dealloc| can be called on | |
| 1036 // any thread. | |
| 1037 // 2) |startLoading| and |stopLoading| are always called on the client thread. | |
| 1038 // 3) |stopLoading| is called before |dealloc| is called. | |
| 1039 // | |
| 1040 // The main wrinkle is that |dealloc|, which may be called on any thread, needs | |
| 1041 // to clean up a running network request. To do this, |dealloc| needs to run | |
| 1042 // |cancelRequest|, which needs to be run on the client thread. Since it is | |
| 1043 // guaranteed that |startLoading| is called before |dealloc| is called, the | |
| 1044 // |startLoading| method stores a pointer to the client thread, then |dealloc| | |
| 1045 // asks that client thread to perform the |cancelRequest| selector via | |
| 1046 // |scheduleCancelRequest|. | |
| 1047 // | |
| 1048 // Some of the above logic is implemented in the parent class | |
| 1049 // (CRNHTTPProtocolHandler) because it is convenient. | |
| 1050 @implementation CRNPauseableHTTPProtocolHandler { | |
| 1051 BOOL _started; | |
| 1052 dispatch_queue_t _queue; | |
| 1053 } | |
| 1054 | |
| 1055 #pragma mark NSURLProtocol methods | |
| 1056 | |
| 1057 - (instancetype)initWithRequest:(NSURLRequest*)request | |
|
droger
2015/06/11 08:56:19
Is this constructor useful? Is it only here for th
Elly Fong-Jones
2015/06/11 13:49:33
It is not. The parent class duplicates the DCHECK
| |
| 1058 cachedResponse:(NSCachedURLResponse*)cachedResponse | |
| 1059 client:(id<NSURLProtocolClient>)client { | |
| 1060 DCHECK(!cachedResponse); | |
| 1061 self = [super initWithRequest:request | |
| 1062 cachedResponse:cachedResponse | |
| 1063 client:client]; | |
| 1064 return self; | |
| 1065 } | |
| 1066 | |
| 1067 - (void)dealloc { | |
| 1068 [self scheduleCancelRequest]; | |
| 1069 [super dealloc]; | |
| 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 @end | |
| OLD | NEW |