Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(130)

Side by Side Diff: ios/net/crn_http_protocol_handler_proxy_with_client_thread.mm

Issue 1142383006: CrNet: add pauseable NSURLProtocol and switch to using it (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fixes Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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_proxy_with_client_thread.h" 5 #import "ios/net/crn_http_protocol_handler_proxy_with_client_thread.h"
6 6
7 #include "base/logging.h" 7 #include "base/logging.h"
8 #import "base/mac/scoped_nsobject.h" 8 #import "base/mac/scoped_nsobject.h"
9 #include "base/time/time.h" 9 #include "base/time/time.h"
10 #import "ios/net/protocol_handler_util.h" 10 #import "ios/net/protocol_handler_util.h"
(...skipping 18 matching lines...) Expand all
29 __weak NSThread* _clientThread; 29 __weak NSThread* _clientThread;
30 // The run loop modes to use when posting tasks to |clientThread_|. 30 // The run loop modes to use when posting tasks to |clientThread_|.
31 base::scoped_nsobject<NSArray> _runLoopModes; 31 base::scoped_nsobject<NSArray> _runLoopModes;
32 // The request URL. 32 // The request URL.
33 base::scoped_nsobject<NSString> _url; 33 base::scoped_nsobject<NSString> _url;
34 // The creation time of the request. 34 // The creation time of the request.
35 base::Time _creationTime; 35 base::Time _creationTime;
36 // |requestComplete_| is used in debug to check that the client is not called 36 // |requestComplete_| is used in debug to check that the client is not called
37 // after completion. 37 // after completion.
38 BOOL _requestComplete; 38 BOOL _requestComplete;
39 BOOL _paused;
40
41 base::scoped_nsobject<NSMutableArray> _queuedInvocations;
39 } 42 }
40 43
41 // Performs the selector on |clientThread_| using |runLoopModes_|. 44 // Performs the selector on |clientThread_| using |runLoopModes_|.
42 - (void)performSelectorOnClientThread:(SEL)aSelector withObject:(id)arg; 45 - (void)runInvocationQueueOnClientThread;
43 // These functions are just wrappers around the corresponding 46 - (void)postToClientThread:(SEL)aSelector, ...
47 NS_REQUIRES_NIL_TERMINATION;
48 - (void)invokeOnClientThread:(NSInvocation*)invocation;
49 // hese functions are just wrappers around the corresponding
44 // NSURLProtocolClient methods, used for task posting. 50 // NSURLProtocolClient methods, used for task posting.
45 - (void)didFailWithErrorOnClientThread:(NSError*)error; 51 - (void)didFailWithErrorOnClientThread:(NSError*)error;
46 - (void)didLoadDataOnClientThread:(NSData*)data; 52 - (void)didLoadDataOnClientThread:(NSData*)data;
47 - (void)didReceiveResponseOnClientThread:(NSURLResponse*)response; 53 - (void)didReceiveResponseOnClientThread:(NSURLResponse*)response;
48 - (void)wasRedirectedToRequestOnClientThread:(NSArray*)params; 54 - (void)wasRedirectedToRequestOnClientThread:(NSURLRequest*)request
55 redirectResponse:(NSURLResponse*)response;
49 - (void)didFinishLoadingOnClientThread; 56 - (void)didFinishLoadingOnClientThread;
50 @end 57 @end
51 58
52 @implementation CRNHTTPProtocolHandlerProxyWithClientThread 59 @implementation CRNHTTPProtocolHandlerProxyWithClientThread
53 60
54 - (instancetype)initWithProtocol:(NSURLProtocol*)protocol 61 - (instancetype)initWithProtocol:(NSURLProtocol*)protocol
55 clientThread:(NSThread*)clientThread 62 clientThread:(NSThread*)clientThread
56 runLoopMode:(NSString*)mode { 63 runLoopMode:(NSString*)mode {
57 DCHECK(protocol); 64 DCHECK(protocol);
58 DCHECK(clientThread); 65 DCHECK(clientThread);
59 if ((self = [super init])) { 66 if ((self = [super init])) {
60 _protocol = protocol; 67 _protocol = protocol;
61 _url.reset([[[[protocol request] URL] absoluteString] copy]); 68 _url.reset([[[[protocol request] URL] absoluteString] copy]);
62 _creationTime = base::Time::Now(); 69 _creationTime = base::Time::Now();
63 _clientThread = clientThread; 70 _clientThread = clientThread;
64 // Use the common run loop mode in addition to the client thread mode, in 71 // Use the common run loop mode in addition to the client thread mode, in
65 // hope that our tasks are executed even if the client thread changes mode 72 // hope that our tasks are executed even if the client thread changes mode
66 // later on. 73 // later on.
67 if ([mode isEqualToString:NSRunLoopCommonModes]) 74 if ([mode isEqualToString:NSRunLoopCommonModes])
68 _runLoopModes.reset([@[ NSRunLoopCommonModes ] retain]); 75 _runLoopModes.reset([@[ NSRunLoopCommonModes ] retain]);
69 else 76 else
70 _runLoopModes.reset([@[ mode, NSRunLoopCommonModes ] retain]); 77 _runLoopModes.reset([@[ mode, NSRunLoopCommonModes ] retain]);
78 _queuedInvocations.reset([[NSMutableArray alloc] init]);
71 } 79 }
72 return self; 80 return self;
73 } 81 }
74 82
75 - (void)invalidate { 83 - (void)invalidate {
76 DCHECK([NSThread currentThread] == _clientThread); 84 DCHECK([NSThread currentThread] == _clientThread);
77 _protocol = nil; 85 _protocol = nil;
78 _requestComplete = YES; 86 _requestComplete = YES;
87 // TODO(ellyjones): This DCHECK fails sometimes. What this implies is that a
88 // callback is coming from the chrome network stack, being enqueued, and then
89 // this proxy is being invalidated before that callback has ever been
90 // delivered. Disturbingly, in practice these seem to be didLoadData and
91 // similar...
92 DCHECK(_queuedInvocations.get().count == 0);
droger 2015/06/11 08:56:19 I think it's expected that the queue may not be em
Elly Fong-Jones 2015/06/11 13:49:33 Done.
79 } 93 }
80 94
81 - (void)performSelectorOnClientThread:(SEL)aSelector withObject:(id)arg { 95 - (void)runInvocationQueueOnClientThread {
82 [self performSelector:aSelector 96 DCHECK([NSThread currentThread] == _clientThread);
97 DCHECK(!_requestComplete || !_protocol);
98 while (!_paused && _queuedInvocations.get().count > 0) {
droger 2015/06/11 08:56:20 I don't understand this. Do you expect _paused or
Elly Fong-Jones 2015/06/11 13:49:33 Yes, that is the crux of it. A callback can lead t
99 NSInvocation* inv = [_queuedInvocations objectAtIndex:0];
100 // Since |_queuedInvocations| owns the only reference to each queued
101 // invocation, this function has to retain another reference before removing
102 // the queued invocation from the array.
103 [inv retain];
104 [_queuedInvocations removeObjectAtIndex:0];
105 [inv invoke];
106 [inv release];
107 }
108 }
109
110 - (void)postToClientThread:(SEL)aSelector, ... {
111 // Build an NSInvocation representing an invocation of |aSelector| on |self|
112 // with the supplied varargs passed as arguments to the invocation.
113 NSMethodSignature* sig = [self methodSignatureForSelector:aSelector];
114 DCHECK(sig != nil);
115 NSInvocation* inv = [NSInvocation invocationWithMethodSignature:sig];
116 [inv setTarget:self];
117 [inv setSelector:aSelector];
118 [inv retainArguments];
119
120 size_t arg_index = 2;
121 va_list args;
122 va_start(args, aSelector);
123 NSObject* arg = va_arg(args, NSObject*);
124 while (arg != nil) {
125 [inv setArgument:&arg atIndex:arg_index];
126 arg = va_arg(args, NSObject*);
127 arg_index++;
128 }
129 va_end(args);
130
131 DCHECK(arg_index == sig.numberOfArguments);
132 [inv retain];
droger 2015/06/11 08:56:20 Can we remove this retain and the corresponding re
Elly Fong-Jones 2015/06/11 13:49:33 Done.
133 [self performSelector:@selector(invokeOnClientThread:)
83 onThread:_clientThread 134 onThread:_clientThread
84 withObject:arg 135 withObject:inv
85 waitUntilDone:NO 136 waitUntilDone:NO
86 modes:_runLoopModes]; 137 modes:_runLoopModes];
87 } 138 }
88 139
140 - (void)invokeOnClientThread:(NSInvocation*)invocation {
141 DCHECK([NSThread currentThread] == _clientThread);
142 DCHECK(!_requestComplete || !_protocol);
143 if (!_paused) {
144 [invocation invoke];
145 } else {
146 [_queuedInvocations addObject:invocation];
147 }
148 [invocation release];
149 }
150
89 #pragma mark Proxy methods called from any thread. 151 #pragma mark Proxy methods called from any thread.
90 152
91 - (void)didFailWithNSErrorCode:(NSInteger)nsErrorCode 153 - (void)didFailWithNSErrorCode:(NSInteger)nsErrorCode
92 netErrorCode:(int)netErrorCode { 154 netErrorCode:(int)netErrorCode {
93 DCHECK(_clientThread); 155 DCHECK(_clientThread);
94 if (!_protocol) 156 if (!_protocol)
droger 2015/06/11 08:56:19 Optional: I realize that this check is not trivia
95 return; 157 return;
96 NSError* error = 158 NSError* error =
97 net::GetIOSError(nsErrorCode, netErrorCode, _url, _creationTime); 159 net::GetIOSError(nsErrorCode, netErrorCode, _url, _creationTime);
98 [self performSelectorOnClientThread:@selector(didFailWithErrorOnClientThread:) 160 [self postToClientThread:@selector(didFailWithErrorOnClientThread:),
99 withObject:error]; 161 error, nil];
100 } 162 }
101 163
102 - (void)didLoadData:(NSData*)data { 164 - (void)didLoadData:(NSData*)data {
103 DCHECK(_clientThread); 165 DCHECK(_clientThread);
104 if (!_protocol) 166 if (!_protocol)
105 return; 167 return;
106 [self performSelectorOnClientThread:@selector(didLoadDataOnClientThread:) 168 [self postToClientThread:@selector(didLoadDataOnClientThread:),
107 withObject:data]; 169 data, nil];
108 } 170 }
109 171
110 - (void)didReceiveResponse:(NSURLResponse*)response { 172 - (void)didReceiveResponse:(NSURLResponse*)response {
111 DCHECK(_clientThread); 173 DCHECK(_clientThread);
112 if (!_protocol) 174 if (!_protocol)
113 return; 175 return;
114 [self 176 [self postToClientThread:@selector(didReceiveResponseOnClientThread:),
115 performSelectorOnClientThread:@selector(didReceiveResponseOnClientThread:) 177 response, nil];
116 withObject:response];
117 } 178 }
118 179
119 - (void)wasRedirectedToRequest:(NSURLRequest*)request 180 - (void)wasRedirectedToRequest:(NSURLRequest*)request
120 nativeRequest:(net::URLRequest*)nativeRequest 181 nativeRequest:(net::URLRequest*)nativeRequest
121 redirectResponse:(NSURLResponse*)redirectResponse { 182 redirectResponse:(NSURLResponse*)redirectResponse {
122 DCHECK(_clientThread); 183 DCHECK(_clientThread);
123 if (!_protocol) 184 if (!_protocol)
124 return; 185 return;
125 [self performSelectorOnClientThread:@selector( 186 [self postToClientThread:@selector(wasRedirectedToRequestOnClientThread:),
126 wasRedirectedToRequestOnClientThread:) 187 request, redirectResponse, nil];
127 withObject:@[ request, redirectResponse ]];
128 } 188 }
129 189
130 - (void)didFinishLoading { 190 - (void)didFinishLoading {
131 DCHECK(_clientThread); 191 DCHECK(_clientThread);
132 if (!_protocol) 192 if (!_protocol)
133 return; 193 return;
134 [self performSelectorOnClientThread:@selector(didFinishLoadingOnClientThread) 194 [self postToClientThread:@selector(didFinishLoadingOnClientThread),
135 withObject:nil]; 195 nil];
136 } 196 }
137 197
138 // Feature support methods that don't forward to the NSURLProtocolClient. 198 // Feature support methods that don't forward to the NSURLProtocolClient.
139 - (void)didCreateNativeRequest:(net::URLRequest*)nativeRequest { 199 - (void)didCreateNativeRequest:(net::URLRequest*)nativeRequest {
140 // no-op. 200 // no-op.
141 } 201 }
142 202
143 - (void)didRecieveAuthChallenge:(net::AuthChallengeInfo*)authInfo 203 - (void)didRecieveAuthChallenge:(net::AuthChallengeInfo*)authInfo
144 nativeRequest:(const net::URLRequest&)nativeRequest 204 nativeRequest:(const net::URLRequest&)nativeRequest
145 callback:(const network_client::AuthCallback&)callback { 205 callback:(const network_client::AuthCallback&)callback {
146 // If we get this far, authentication has failed. 206 // If we get this far, authentication has failed.
147 base::string16 empty; 207 base::string16 empty;
148 callback.Run(false, empty, empty); 208 callback.Run(false, empty, empty);
149 } 209 }
150 210
151 - (void)cancelAuthRequest { 211 - (void)cancelAuthRequest {
152 // no-op. 212 // no-op.
153 } 213 }
154 214
155 - (void)setUnderlyingClient:(id<CRNNetworkClientProtocol>)underlyingClient { 215 - (void)setUnderlyingClient:(id<CRNNetworkClientProtocol>)underlyingClient {
156 // This is the lowest level. 216 // This is the lowest level.
157 DCHECK(!underlyingClient); 217 DCHECK(!underlyingClient);
158 } 218 }
159 219
160 #pragma mark Proxy methods called from the client thread. 220 #pragma mark Proxy methods called from the client thread.
161 221
162 - (void)didFailWithErrorOnClientThread:(NSError*)error { 222 - (void)didFailWithErrorOnClientThread:(NSError*)error {
163 DCHECK([NSThread currentThread] == _clientThread);
164 DCHECK(!_requestComplete || !_protocol);
165 _requestComplete = YES; 223 _requestComplete = YES;
166 [[_protocol client] URLProtocol:_protocol didFailWithError:error]; 224 [[_protocol client] URLProtocol:_protocol didFailWithError:error];
167 } 225 }
168 226
169 - (void)didLoadDataOnClientThread:(NSData*)data { 227 - (void)didLoadDataOnClientThread:(NSData*)data {
170 DCHECK([NSThread currentThread] == _clientThread);
171 DCHECK(!_requestComplete || !_protocol);
172 [[_protocol client] URLProtocol:_protocol didLoadData:data]; 228 [[_protocol client] URLProtocol:_protocol didLoadData:data];
173 } 229 }
174 230
175 - (void)didReceiveResponseOnClientThread:(NSURLResponse*)response { 231 - (void)didReceiveResponseOnClientThread:(NSURLResponse*)response {
176 DCHECK([NSThread currentThread] == _clientThread);
177 DCHECK(!_requestComplete || !_protocol);
178 [[_protocol client] URLProtocol:_protocol 232 [[_protocol client] URLProtocol:_protocol
179 didReceiveResponse:response 233 didReceiveResponse:response
180 cacheStoragePolicy:NSURLCacheStorageNotAllowed]; 234 cacheStoragePolicy:NSURLCacheStorageNotAllowed];
181 } 235 }
182 236
183 - (void)wasRedirectedToRequestOnClientThread:(NSArray*)params { 237 - (void)wasRedirectedToRequestOnClientThread:(NSURLRequest*)request
184 DCHECK([NSThread currentThread] == _clientThread); 238 redirectResponse:(NSURLResponse*)redirectResponse {
185 DCHECK_EQ(2u, [params count]);
186 DCHECK([params[0] isKindOfClass:[NSURLRequest class]]);
187 DCHECK([params[1] isKindOfClass:[NSURLResponse class]]);
188 DCHECK(!_requestComplete || !_protocol);
189 [[_protocol client] URLProtocol:_protocol 239 [[_protocol client] URLProtocol:_protocol
190 wasRedirectedToRequest:params[0] 240 wasRedirectedToRequest:request
191 redirectResponse:params[1]]; 241 redirectResponse:redirectResponse];
192 } 242 }
193 243
194 - (void)didFinishLoadingOnClientThread { 244 - (void)didFinishLoadingOnClientThread {
195 DCHECK([NSThread currentThread] == _clientThread);
196 DCHECK(!_requestComplete || !_protocol);
197 _requestComplete = YES; 245 _requestComplete = YES;
198 [[_protocol client] URLProtocolDidFinishLoading:_protocol]; 246 [[_protocol client] URLProtocolDidFinishLoading:_protocol];
199 } 247 }
200 248
249 - (void)pause {
250 DCHECK([NSThread currentThread] == _clientThread);
251 // It's legal (in fact, required) for |pause| to be called after the request
252 // has already finished, so the usual invalidation DCHECK is missing here.
253 _paused = YES;
254 }
255
256 - (void)resume {
257 DCHECK([NSThread currentThread] == _clientThread);
258 DCHECK(!_requestComplete || !_protocol);
259 _paused = NO;
260 [self runInvocationQueueOnClientThread];
261 }
262
201 @end 263 @end
OLDNEW
« ios/net/crn_http_protocol_handler_proxy.h ('K') | « ios/net/crn_http_protocol_handler_proxy.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698