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

Side by Side Diff: net/proxy/proxy_resolver_mac.cc

Issue 2094373002: Synchronize events of CFNetworkExecuteProxyAutoConfigurationURL (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Addressed Misha's comments Created 4 years, 5 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 | « no previous file | 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 (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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 #include "net/proxy/proxy_resolver_mac.h" 5 #include "net/proxy/proxy_resolver_mac.h"
6 6
7 #include <CoreFoundation/CoreFoundation.h> 7 #include <CoreFoundation/CoreFoundation.h>
8 8
9 #include "base/lazy_instance.h"
9 #include "base/logging.h" 10 #include "base/logging.h"
10 #include "base/mac/foundation_util.h" 11 #include "base/mac/foundation_util.h"
11 #include "base/mac/scoped_cftyperef.h" 12 #include "base/mac/scoped_cftyperef.h"
12 #include "base/strings/string_util.h" 13 #include "base/strings/string_util.h"
13 #include "base/strings/sys_string_conversions.h" 14 #include "base/strings/sys_string_conversions.h"
15 #include "base/synchronization/lock.h"
16 #include "base/threading/thread_checker.h"
14 #include "net/base/net_errors.h" 17 #include "net/base/net_errors.h"
15 #include "net/proxy/proxy_info.h" 18 #include "net/proxy/proxy_info.h"
16 #include "net/proxy/proxy_resolver.h" 19 #include "net/proxy/proxy_resolver.h"
17 #include "net/proxy/proxy_server.h" 20 #include "net/proxy/proxy_server.h"
18 21
19 #if defined(OS_IOS) 22 #if defined(OS_IOS)
20 #include <CFNetwork/CFProxySupport.h> 23 #include <CFNetwork/CFProxySupport.h>
21 #else 24 #else
22 #include <CoreServices/CoreServices.h> 25 #include <CoreServices/CoreServices.h>
23 #endif 26 #endif
24 27
25 namespace net { 28 namespace net {
26 29
27 namespace { 30 namespace {
28 31
32 // A lock shared by all ProxyResolverMac instances. It is used to synchronize
33 // the events of multiple CFNetworkExecuteProxyAutoConfigurationURL run loop
34 // sources. These events are:
35 // 1. Adding the source to the run loop.
36 // 2. Handling the source result.
37 // 3. Removing the source from the run loop.
38 static base::LazyInstance<base::Lock>::Leaky cfnetwork_pac_runloop_lock_ =
mef 2016/06/29 20:13:39 nit: trailing underscore is used only for member v
kapishnikov 2016/06/29 22:41:11 Done.
39 LAZY_INSTANCE_INITIALIZER;
40
41 // Forward declaration of the callback function used by the
42 // SynchronizedRunLoopObserver class.
43 void RunLoopObserverCallBackFunc(CFRunLoopObserverRef observer,
44 CFRunLoopActivity activity,
45 void* info);
46
29 // Utility function to map a CFProxyType to a ProxyServer::Scheme. 47 // Utility function to map a CFProxyType to a ProxyServer::Scheme.
30 // If the type is unknown, returns ProxyServer::SCHEME_INVALID. 48 // If the type is unknown, returns ProxyServer::SCHEME_INVALID.
31 ProxyServer::Scheme GetProxyServerScheme(CFStringRef proxy_type) { 49 ProxyServer::Scheme GetProxyServerScheme(CFStringRef proxy_type) {
32 if (CFEqual(proxy_type, kCFProxyTypeNone)) 50 if (CFEqual(proxy_type, kCFProxyTypeNone))
33 return ProxyServer::SCHEME_DIRECT; 51 return ProxyServer::SCHEME_DIRECT;
34 if (CFEqual(proxy_type, kCFProxyTypeHTTP)) 52 if (CFEqual(proxy_type, kCFProxyTypeHTTP))
35 return ProxyServer::SCHEME_HTTP; 53 return ProxyServer::SCHEME_HTTP;
36 if (CFEqual(proxy_type, kCFProxyTypeHTTPS)) { 54 if (CFEqual(proxy_type, kCFProxyTypeHTTPS)) {
37 // The "HTTPS" on the Mac side here means "proxy applies to https://" URLs; 55 // The "HTTPS" on the Mac side here means "proxy applies to https://" URLs;
38 // the proxy itself is still expected to be an HTTP proxy. 56 // the proxy itself is still expected to be an HTTP proxy.
(...skipping 17 matching lines...) Expand all
56 DCHECK(*result_ptr == NULL); 74 DCHECK(*result_ptr == NULL);
57 75
58 if (error != NULL) { 76 if (error != NULL) {
59 *result_ptr = CFRetain(error); 77 *result_ptr = CFRetain(error);
60 } else { 78 } else {
61 *result_ptr = CFRetain(proxies); 79 *result_ptr = CFRetain(proxies);
62 } 80 }
63 CFRunLoopStop(CFRunLoopGetCurrent()); 81 CFRunLoopStop(CFRunLoopGetCurrent());
64 } 82 }
65 83
84 #pragma mark - SynchronizedRunLoopObserver
85 // A run loop observer that guarantees that no any two run loop sources
86 // protected by the same lock will be fired concurrently in different threads.
87 // The observer does not prevent the parallel execution of the sources but only
88 // synchronizes the run loop events associated with the sources. In the context
89 // of proxy resolver, the observer is used to synchronize the execution of the
90 // callbacks function that handles the result of
91 // CFNetworkExecuteProxyAutoConfigurationURL execution.
92 class SynchronizedRunLoopObserver final {
93 public:
94 // Creates the instance of an observer that will synchronize the sources
95 // using a given |lock|.
96 SynchronizedRunLoopObserver(base::Lock& lock);
97 // Destructor.
98 ~SynchronizedRunLoopObserver();
99 // Adds the observer to the current run loop for a given run loop mode.
100 // This method should always be paired with |RemoveFromCurrentRunLoop|.
101 void AddToCurrentRunLoop(const CFStringRef mode);
102 // Removes the observer from the current run loop for a given run loop mode.
103 // This method should always be paired with |AddToCurrentRunLoop|.
104 void RemoveFromCurrentRunLoop(const CFStringRef mode);
105 // Callback function that is called when an observable run loop event occurs.
106 void RunLoopObserverCallBack(CFRunLoopObserverRef observer,
107 CFRunLoopActivity activity);
108
109 private:
110 // Lock to use to synchronize the run loop sources.
111 base::Lock& lock_;
112 // Indicates whether the current observer holds the lock. It is used to
113 // avoid double locking and releasing.
114 bool lock_acquired_;
115 // The underlying CFRunLoopObserverRef structure wrapped by this instance.
116 base::ScopedCFTypeRef<CFRunLoopObserverRef> observer_;
117 // Validates that all methods of this class are executed on the same thread.
118 base::ThreadChecker thread_checker_;
mef 2016/06/29 20:13:39 Add DISALLOW_COPY_AND_ASSIGN(SynchronizedRunLoopOb
kapishnikov 2016/06/29 22:41:11 Done.
119 };
120
121 SynchronizedRunLoopObserver::SynchronizedRunLoopObserver(base::Lock& lock)
122 : lock_(lock), lock_acquired_(false) {
123 CFRunLoopObserverContext observer_context = {0, this, NULL, NULL, NULL};
124 observer_.reset(CFRunLoopObserverCreate(
125 kCFAllocatorDefault,
126 kCFRunLoopBeforeSources | kCFRunLoopBeforeWaiting | kCFRunLoopExit, true,
127 0, RunLoopObserverCallBackFunc, &observer_context));
128 }
129
130 SynchronizedRunLoopObserver::~SynchronizedRunLoopObserver() {
131 DCHECK(thread_checker_.CalledOnValidThread());
132 DCHECK(!lock_acquired_);
133 }
134
135 void SynchronizedRunLoopObserver::AddToCurrentRunLoop(const CFStringRef mode) {
136 DCHECK(thread_checker_.CalledOnValidThread());
137 CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer_.get(), mode);
138 }
139
140 void SynchronizedRunLoopObserver::RemoveFromCurrentRunLoop(
141 const CFStringRef mode) {
142 DCHECK(thread_checker_.CalledOnValidThread());
143 CFRunLoopRemoveObserver(CFRunLoopGetCurrent(), observer_.get(), mode);
144 }
145
146 void SynchronizedRunLoopObserver::RunLoopObserverCallBack(
147 CFRunLoopObserverRef observer,
148 CFRunLoopActivity activity) {
149 DCHECK(thread_checker_.CalledOnValidThread());
150 // Acquire the lock when a source has been signaled and going to be fired.
151 // In the context of the proxy resolver that happens when the proxy for a
152 // given URL has been resolved and the callback function that handles the
153 // result is going to be fired.
154 // Release the lock when all source events have been handled.
155 switch (activity) {
156 case kCFRunLoopBeforeSources:
157 if (!lock_acquired_) {
158 lock_.Acquire();
159 lock_acquired_ = true;
160 }
161 break;
162 case kCFRunLoopBeforeWaiting:
163 case kCFRunLoopExit:
164 if (lock_acquired_) {
165 lock_acquired_ = false;
166 lock_.Release();
167 }
168 break;
169 }
170 }
171
172 void RunLoopObserverCallBackFunc(CFRunLoopObserverRef observer,
173 CFRunLoopActivity activity,
174 void* info) {
175 // Forward the call to the instance of SynchronizedRunLoopObserver
176 // that is associated with the current CF run loop observer.
177 SynchronizedRunLoopObserver* observerInstance =
178 (SynchronizedRunLoopObserver*)info;
179 observerInstance->RunLoopObserverCallBack(observer, activity);
180 }
181
182 #pragma mark - ProxyResolverMac
66 class ProxyResolverMac : public ProxyResolver { 183 class ProxyResolverMac : public ProxyResolver {
67 public: 184 public:
68 explicit ProxyResolverMac( 185 explicit ProxyResolverMac(
69 const scoped_refptr<ProxyResolverScriptData>& script_data); 186 const scoped_refptr<ProxyResolverScriptData>& script_data);
70 ~ProxyResolverMac() override; 187 ~ProxyResolverMac() override;
71 188
72 // ProxyResolver methods: 189 // ProxyResolver methods:
73 int GetProxyForURL(const GURL& url, 190 int GetProxyForURL(const GURL& url,
74 ProxyInfo* results, 191 ProxyInfo* results,
75 const CompletionCallback& callback, 192 const CompletionCallback& callback,
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
133 CFStreamClientContext context = { 0, &result, NULL, NULL, NULL }; 250 CFStreamClientContext context = { 0, &result, NULL, NULL, NULL };
134 base::ScopedCFTypeRef<CFRunLoopSourceRef> runloop_source( 251 base::ScopedCFTypeRef<CFRunLoopSourceRef> runloop_source(
135 CFNetworkExecuteProxyAutoConfigurationURL( 252 CFNetworkExecuteProxyAutoConfigurationURL(
136 pac_url_ref.get(), query_url_ref.get(), ResultCallback, &context)); 253 pac_url_ref.get(), query_url_ref.get(), ResultCallback, &context));
137 if (!runloop_source) 254 if (!runloop_source)
138 return ERR_FAILED; 255 return ERR_FAILED;
139 256
140 const CFStringRef private_runloop_mode = 257 const CFStringRef private_runloop_mode =
141 CFSTR("org.chromium.ProxyResolverMac"); 258 CFSTR("org.chromium.ProxyResolverMac");
142 259
143 CFRunLoopAddSource(CFRunLoopGetCurrent(), runloop_source.get(), 260 // Add the run loop observer to synchronize events of
144 private_runloop_mode); 261 // CFNetworkExecuteProxyAutoConfigurationURL sources. See the definition of
262 // |cfnetwork_pac_runloop_lock_|.
263 SynchronizedRunLoopObserver observer(cfnetwork_pac_runloop_lock_.Get());
264 observer.AddToCurrentRunLoop(private_runloop_mode);
265
266 // Make sure that no CFNetworkExecuteProxyAutoConfigurationURL sources
267 // are added to the run loop concurrently.
268 {
269 base::AutoLock lock(cfnetwork_pac_runloop_lock_.Get());
270 CFRunLoopAddSource(CFRunLoopGetCurrent(), runloop_source.get(),
271 private_runloop_mode);
272 }
273
145 CFRunLoopRunInMode(private_runloop_mode, DBL_MAX, false); 274 CFRunLoopRunInMode(private_runloop_mode, DBL_MAX, false);
146 CFRunLoopSourceInvalidate(runloop_source.get()); 275
276 // Make sure that no CFNetworkExecuteProxyAutoConfigurationURL sources
277 // are removed from the run loop concurrently.
278 {
279 base::AutoLock lock(cfnetwork_pac_runloop_lock_.Get());
280 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), runloop_source.get(),
281 private_runloop_mode);
282 }
283 observer.RemoveFromCurrentRunLoop(private_runloop_mode);
284
147 DCHECK(result != NULL); 285 DCHECK(result != NULL);
148 286
149 if (CFGetTypeID(result) == CFErrorGetTypeID()) { 287 if (CFGetTypeID(result) == CFErrorGetTypeID()) {
150 // TODO(avi): do something better than this 288 // TODO(avi): do something better than this
151 CFRelease(result); 289 CFRelease(result);
152 return ERR_FAILED; 290 return ERR_FAILED;
153 } 291 }
154 base::ScopedCFTypeRef<CFArrayRef> proxy_array_ref( 292 base::ScopedCFTypeRef<CFArrayRef> proxy_array_ref(
155 base::mac::CFCastStrict<CFArrayRef>(result)); 293 base::mac::CFCastStrict<CFArrayRef>(result));
156 DCHECK(proxy_array_ref != NULL); 294 DCHECK(proxy_array_ref != NULL);
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
221 int ProxyResolverFactoryMac::CreateProxyResolver( 359 int ProxyResolverFactoryMac::CreateProxyResolver(
222 const scoped_refptr<ProxyResolverScriptData>& pac_script, 360 const scoped_refptr<ProxyResolverScriptData>& pac_script,
223 std::unique_ptr<ProxyResolver>* resolver, 361 std::unique_ptr<ProxyResolver>* resolver,
224 const CompletionCallback& callback, 362 const CompletionCallback& callback,
225 std::unique_ptr<Request>* request) { 363 std::unique_ptr<Request>* request) {
226 resolver->reset(new ProxyResolverMac(pac_script)); 364 resolver->reset(new ProxyResolverMac(pac_script));
227 return OK; 365 return OK;
228 } 366 }
229 367
230 } // namespace net 368 } // namespace net
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698