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

Unified Diff: ios/net/crn_http_protocol_handler_proxy_with_client_thread.mm

Issue 994823004: [iOS] Upstream //ios/net (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 9 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 side-by-side diff with in-line comments
Download patch
Index: ios/net/crn_http_protocol_handler_proxy_with_client_thread.mm
diff --git a/ios/net/crn_http_protocol_handler_proxy_with_client_thread.mm b/ios/net/crn_http_protocol_handler_proxy_with_client_thread.mm
new file mode 100644
index 0000000000000000000000000000000000000000..0289e81d630f848a358f9dac2a4aae8fb0025f61
--- /dev/null
+++ b/ios/net/crn_http_protocol_handler_proxy_with_client_thread.mm
@@ -0,0 +1,201 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/net/crn_http_protocol_handler_proxy_with_client_thread.h"
+
+#include "base/logging.h"
+#import "base/mac/scoped_nsobject.h"
+#include "base/time/time.h"
+#import "ios/net/protocol_handler_util.h"
+#include "net/base/auth.h"
+#include "net/url_request/url_request.h"
+
+// When the protocol is invalidated, no synchronization (lock) is needed:
+// - The actual calls to the protocol and its invalidation are all done on
+// clientThread_ and thus are serialized.
+// - When a proxy method is called, the protocol is compared to nil. There may
+// be a conflict at this point, in the case the protocol is being invalidated
+// during this comparison. However, in such a case, the actual value of the
+// pointer does not matter: an invalid pointer will behave as a valid one and
+// post a task on the clientThread_, and that task will be handled correctly,
+// as described by the item above.
+
+@interface CRNHTTPProtocolHandlerProxyWithClientThread () {
+ __weak NSURLProtocol* _protocol;
+ // Thread used to call the client back.
+ // This thread does not have a base::MessageLoop, and thus does not work with
+ // the usual task posting functions.
+ __weak NSThread* _clientThread;
+ // The run loop modes to use when posting tasks to |clientThread_|.
+ base::scoped_nsobject<NSArray> _runLoopModes;
+ // The request URL.
+ base::scoped_nsobject<NSString> _url;
+ // The creation time of the request.
+ base::Time _creationTime;
+ // |requestComplete_| is used in debug to check that the client is not called
+ // after completion.
+ BOOL _requestComplete;
+}
+
+// Performs the selector on |clientThread_| using |runLoopModes_|.
+- (void)performSelectorOnClientThread:(SEL)aSelector withObject:(id)arg;
+// These functions are just wrappers around the corresponding
+// NSURLProtocolClient methods, used for task posting.
+- (void)didFailWithErrorOnClientThread:(NSError*)error;
+- (void)didLoadDataOnClientThread:(NSData*)data;
+- (void)didReceiveResponseOnClientThread:(NSURLResponse*)response;
+- (void)wasRedirectedToRequestOnClientThread:(NSArray*)params;
+- (void)didFinishLoadingOnClientThread;
+@end
+
+@implementation CRNHTTPProtocolHandlerProxyWithClientThread
+
+- (instancetype)initWithProtocol:(NSURLProtocol*)protocol
+ clientThread:(NSThread*)clientThread
+ runLoopMode:(NSString*)mode {
+ DCHECK(protocol);
+ DCHECK(clientThread);
+ if ((self = [super init])) {
+ _protocol = protocol;
+ _url.reset([[[[protocol request] URL] absoluteString] copy]);
+ _creationTime = base::Time::Now();
+ _clientThread = clientThread;
+ // Use the common run loop mode in addition to the client thread mode, in
+ // hope that our tasks are executed even if the client thread changes mode
+ // later on.
+ if ([mode isEqualToString:NSRunLoopCommonModes])
+ _runLoopModes.reset([@[ NSRunLoopCommonModes ] retain]);
+ else
+ _runLoopModes.reset([@[ mode, NSRunLoopCommonModes ] retain]);
+ }
+ return self;
+}
+
+- (void)invalidate {
+ DCHECK([NSThread currentThread] == _clientThread);
+ _protocol = nil;
+ _requestComplete = YES;
+}
+
+- (void)performSelectorOnClientThread:(SEL)aSelector withObject:(id)arg {
+ [self performSelector:aSelector
+ onThread:_clientThread
+ withObject:arg
+ waitUntilDone:NO
+ modes:_runLoopModes];
+}
+
+#pragma mark Proxy methods called from any thread.
+
+- (void)didFailWithNSErrorCode:(NSInteger)nsErrorCode
+ netErrorCode:(int)netErrorCode {
+ DCHECK(_clientThread);
+ if (!_protocol)
+ return;
+ NSError* error =
+ net::GetIOSError(nsErrorCode, netErrorCode, _url, _creationTime);
+ [self performSelectorOnClientThread:@selector(didFailWithErrorOnClientThread:)
+ withObject:error];
+}
+
+- (void)didLoadData:(NSData*)data {
+ DCHECK(_clientThread);
+ if (!_protocol)
+ return;
+ [self performSelectorOnClientThread:@selector(didLoadDataOnClientThread:)
+ withObject:data];
+}
+
+- (void)didReceiveResponse:(NSURLResponse*)response {
+ DCHECK(_clientThread);
+ if (!_protocol)
+ return;
+ [self
+ performSelectorOnClientThread:@selector(didReceiveResponseOnClientThread:)
+ withObject:response];
+}
+
+- (void)wasRedirectedToRequest:(NSURLRequest*)request
+ nativeRequest:(net::URLRequest*)nativeRequest
+ redirectResponse:(NSURLResponse*)redirectResponse {
+ DCHECK(_clientThread);
+ if (!_protocol)
+ return;
+ [self performSelectorOnClientThread:@selector(
+ wasRedirectedToRequestOnClientThread:)
+ withObject:@[ request, redirectResponse ]];
+}
+
+- (void)didFinishLoading {
+ DCHECK(_clientThread);
+ if (!_protocol)
+ return;
+ [self performSelectorOnClientThread:@selector(didFinishLoadingOnClientThread)
+ withObject:nil];
+}
+
+// Feature support methods that don't forward to the NSURLProtocolClient.
+- (void)didCreateNativeRequest:(net::URLRequest*)nativeRequest {
+ // no-op.
+}
+
+- (void)didRecieveAuthChallenge:(net::AuthChallengeInfo*)authInfo
+ nativeRequest:(const net::URLRequest&)nativeRequest
+ callback:(const network_client::AuthCallback&)callback {
+ // If we get this far, authentication has failed.
+ base::string16 empty;
+ callback.Run(false, empty, empty);
+}
+
+- (void)cancelAuthRequest {
+ // no-op.
+}
+
+- (void)setUnderlyingClient:(id<CRNNetworkClientProtocol>)underlyingClient {
+ // This is the lowest level.
+ DCHECK(!underlyingClient);
+}
+
+#pragma mark Proxy methods called from the client thread.
+
+- (void)didFailWithErrorOnClientThread:(NSError*)error {
+ DCHECK([NSThread currentThread] == _clientThread);
+ DCHECK(!_requestComplete || !_protocol);
+ _requestComplete = YES;
+ [[_protocol client] URLProtocol:_protocol didFailWithError:error];
+}
+
+- (void)didLoadDataOnClientThread:(NSData*)data {
+ DCHECK([NSThread currentThread] == _clientThread);
+ DCHECK(!_requestComplete || !_protocol);
+ [[_protocol client] URLProtocol:_protocol didLoadData:data];
+}
+
+- (void)didReceiveResponseOnClientThread:(NSURLResponse*)response {
+ DCHECK([NSThread currentThread] == _clientThread);
+ DCHECK(!_requestComplete || !_protocol);
+ [[_protocol client] URLProtocol:_protocol
+ didReceiveResponse:response
+ cacheStoragePolicy:NSURLCacheStorageNotAllowed];
+}
+
+- (void)wasRedirectedToRequestOnClientThread:(NSArray*)params {
+ DCHECK([NSThread currentThread] == _clientThread);
+ DCHECK_EQ(2u, [params count]);
+ DCHECK([params[0] isKindOfClass:[NSURLRequest class]]);
+ DCHECK([params[1] isKindOfClass:[NSURLResponse class]]);
+ DCHECK(!_requestComplete || !_protocol);
+ [[_protocol client] URLProtocol:_protocol
+ wasRedirectedToRequest:params[0]
+ redirectResponse:params[1]];
+}
+
+- (void)didFinishLoadingOnClientThread {
+ DCHECK([NSThread currentThread] == _clientThread);
+ DCHECK(!_requestComplete || !_protocol);
+ _requestComplete = YES;
+ [[_protocol client] URLProtocolDidFinishLoading:_protocol];
+}
+
+@end

Powered by Google App Engine
This is Rietveld 408576698