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

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: main.m -> main.mm & format 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
« no previous file with comments | « ios/net/crn_http_protocol_handler_proxy.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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, ... NS_REQUIRES_NIL_TERMINATION;
47 - (void)invokeOnClientThread:(NSInvocation*)invocation;
48 // hese functions are just wrappers around the corresponding
44 // NSURLProtocolClient methods, used for task posting. 49 // NSURLProtocolClient methods, used for task posting.
45 - (void)didFailWithErrorOnClientThread:(NSError*)error; 50 - (void)didFailWithErrorOnClientThread:(NSError*)error;
46 - (void)didLoadDataOnClientThread:(NSData*)data; 51 - (void)didLoadDataOnClientThread:(NSData*)data;
47 - (void)didReceiveResponseOnClientThread:(NSURLResponse*)response; 52 - (void)didReceiveResponseOnClientThread:(NSURLResponse*)response;
48 - (void)wasRedirectedToRequestOnClientThread:(NSArray*)params; 53 - (void)wasRedirectedToRequestOnClientThread:(NSURLRequest*)request
54 redirectResponse:(NSURLResponse*)response;
49 - (void)didFinishLoadingOnClientThread; 55 - (void)didFinishLoadingOnClientThread;
50 @end 56 @end
51 57
52 @implementation CRNHTTPProtocolHandlerProxyWithClientThread 58 @implementation CRNHTTPProtocolHandlerProxyWithClientThread
53 59
54 - (instancetype)initWithProtocol:(NSURLProtocol*)protocol 60 - (instancetype)initWithProtocol:(NSURLProtocol*)protocol
55 clientThread:(NSThread*)clientThread 61 clientThread:(NSThread*)clientThread
56 runLoopMode:(NSString*)mode { 62 runLoopMode:(NSString*)mode {
57 DCHECK(protocol); 63 DCHECK(protocol);
58 DCHECK(clientThread); 64 DCHECK(clientThread);
59 if ((self = [super init])) { 65 if ((self = [super init])) {
60 _protocol = protocol; 66 _protocol = protocol;
61 _url.reset([[[[protocol request] URL] absoluteString] copy]); 67 _url.reset([[[[protocol request] URL] absoluteString] copy]);
62 _creationTime = base::Time::Now(); 68 _creationTime = base::Time::Now();
63 _clientThread = clientThread; 69 _clientThread = clientThread;
64 // Use the common run loop mode in addition to the client thread mode, in 70 // 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 71 // hope that our tasks are executed even if the client thread changes mode
66 // later on. 72 // later on.
67 if ([mode isEqualToString:NSRunLoopCommonModes]) 73 if ([mode isEqualToString:NSRunLoopCommonModes])
68 _runLoopModes.reset([@[ NSRunLoopCommonModes ] retain]); 74 _runLoopModes.reset([@[ NSRunLoopCommonModes ] retain]);
69 else 75 else
70 _runLoopModes.reset([@[ mode, NSRunLoopCommonModes ] retain]); 76 _runLoopModes.reset([@[ mode, NSRunLoopCommonModes ] retain]);
77 _queuedInvocations.reset([[NSMutableArray alloc] init]);
71 } 78 }
72 return self; 79 return self;
73 } 80 }
74 81
75 - (void)invalidate { 82 - (void)invalidate {
76 DCHECK([NSThread currentThread] == _clientThread); 83 DCHECK([NSThread currentThread] == _clientThread);
77 _protocol = nil; 84 _protocol = nil;
78 _requestComplete = YES; 85 _requestComplete = YES;
86 // Note that there may still be queued invocations here, if the chrome network
87 // stack continues to emit events after the system network stack has paused
88 // the request, and then the system network stack destroys the request.
89 _queuedInvocations.reset();
79 } 90 }
80 91
81 - (void)performSelectorOnClientThread:(SEL)aSelector withObject:(id)arg { 92 - (void)runInvocationQueueOnClientThread {
82 [self performSelector:aSelector 93 DCHECK([NSThread currentThread] == _clientThread);
94 DCHECK(!_requestComplete || !_protocol);
95 // Each of the queued invocations may cause the system network stack to pause
96 // this request, in which case |runInvocationQueueOnClientThread| should
97 // immediately stop running further queued invocations. The queue will be
98 // drained again the next time the system network stack calls |resume|.
99 //
100 // Specifically, the system stack can call back into |pause| with this
101 // function still on the call stack. However, since new invocations are
102 // enqueued on this thread via posted invocations, no new invocations can be
103 // added while this function is running.
104 while (!_paused && _queuedInvocations.get().count > 0) {
105 NSInvocation* invocation = [_queuedInvocations objectAtIndex:0];
106 // Since |_queuedInvocations| owns the only reference to each queued
107 // invocation, this function has to retain another reference before removing
108 // the queued invocation from the array.
109 [invocation invoke];
110 [_queuedInvocations removeObjectAtIndex:0];
111 }
112 }
113
114 - (void)postToClientThread:(SEL)aSelector, ... {
115 // Build an NSInvocation representing an invocation of |aSelector| on |self|
116 // with the supplied varargs passed as arguments to the invocation.
117 NSMethodSignature* sig = [self methodSignatureForSelector:aSelector];
118 DCHECK(sig != nil);
119 NSInvocation* inv = [NSInvocation invocationWithMethodSignature:sig];
120 [inv setTarget:self];
121 [inv setSelector:aSelector];
122 [inv retainArguments];
123
124 size_t arg_index = 2;
125 va_list args;
126 va_start(args, aSelector);
127 NSObject* arg = va_arg(args, NSObject*);
128 while (arg != nil) {
129 [inv setArgument:&arg atIndex:arg_index];
130 arg = va_arg(args, NSObject*);
131 arg_index++;
132 }
133 va_end(args);
134
135 DCHECK(arg_index == sig.numberOfArguments);
136 [self performSelector:@selector(invokeOnClientThread:)
83 onThread:_clientThread 137 onThread:_clientThread
84 withObject:arg 138 withObject:inv
85 waitUntilDone:NO 139 waitUntilDone:NO
86 modes:_runLoopModes]; 140 modes:_runLoopModes];
87 } 141 }
88 142
143 - (void)invokeOnClientThread:(NSInvocation*)invocation {
144 DCHECK([NSThread currentThread] == _clientThread);
145 DCHECK(!_requestComplete || !_protocol);
146 if (!_paused) {
147 [invocation invoke];
148 } else {
149 [_queuedInvocations addObject:invocation];
150 }
151 }
152
89 #pragma mark Proxy methods called from any thread. 153 #pragma mark Proxy methods called from any thread.
90 154
91 - (void)didFailWithNSErrorCode:(NSInteger)nsErrorCode 155 - (void)didFailWithNSErrorCode:(NSInteger)nsErrorCode
92 netErrorCode:(int)netErrorCode { 156 netErrorCode:(int)netErrorCode {
93 DCHECK(_clientThread); 157 DCHECK(_clientThread);
94 if (!_protocol) 158 if (!_protocol)
95 return; 159 return;
96 NSError* error = 160 NSError* error =
97 net::GetIOSError(nsErrorCode, netErrorCode, _url, _creationTime); 161 net::GetIOSError(nsErrorCode, netErrorCode, _url, _creationTime);
98 [self performSelectorOnClientThread:@selector(didFailWithErrorOnClientThread:) 162 [self postToClientThread:@selector(didFailWithErrorOnClientThread:), error,
99 withObject:error]; 163 nil];
100 } 164 }
101 165
102 - (void)didLoadData:(NSData*)data { 166 - (void)didLoadData:(NSData*)data {
103 DCHECK(_clientThread); 167 DCHECK(_clientThread);
104 if (!_protocol) 168 if (!_protocol)
105 return; 169 return;
106 [self performSelectorOnClientThread:@selector(didLoadDataOnClientThread:) 170 [self postToClientThread:@selector(didLoadDataOnClientThread:), data, nil];
107 withObject:data];
108 } 171 }
109 172
110 - (void)didReceiveResponse:(NSURLResponse*)response { 173 - (void)didReceiveResponse:(NSURLResponse*)response {
111 DCHECK(_clientThread); 174 DCHECK(_clientThread);
112 if (!_protocol) 175 if (!_protocol)
113 return; 176 return;
114 [self 177 [self postToClientThread:@selector(didReceiveResponseOnClientThread:),
115 performSelectorOnClientThread:@selector(didReceiveResponseOnClientThread:) 178 response, nil];
116 withObject:response];
117 } 179 }
118 180
119 - (void)wasRedirectedToRequest:(NSURLRequest*)request 181 - (void)wasRedirectedToRequest:(NSURLRequest*)request
120 nativeRequest:(net::URLRequest*)nativeRequest 182 nativeRequest:(net::URLRequest*)nativeRequest
121 redirectResponse:(NSURLResponse*)redirectResponse { 183 redirectResponse:(NSURLResponse*)redirectResponse {
122 DCHECK(_clientThread); 184 DCHECK(_clientThread);
123 if (!_protocol) 185 if (!_protocol)
124 return; 186 return;
125 [self performSelectorOnClientThread:@selector( 187 [self postToClientThread:@selector(wasRedirectedToRequestOnClientThread:),
126 wasRedirectedToRequestOnClientThread:) 188 request, redirectResponse, nil];
127 withObject:@[ request, redirectResponse ]];
128 } 189 }
129 190
130 - (void)didFinishLoading { 191 - (void)didFinishLoading {
131 DCHECK(_clientThread); 192 DCHECK(_clientThread);
132 if (!_protocol) 193 if (!_protocol)
133 return; 194 return;
134 [self performSelectorOnClientThread:@selector(didFinishLoadingOnClientThread) 195 [self postToClientThread:@selector(didFinishLoadingOnClientThread), nil];
135 withObject: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
« no previous file with comments | « 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