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

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

Issue 19502: Get rid of synchronous ResolveProxy API. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 10 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2006-2008 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_service.h" 5 #include "net/proxy/proxy_service.h"
6 6
7 #if defined(OS_WIN) 7 #if defined(OS_WIN)
8 #include <windows.h> 8 #include <windows.h>
9 #include <winhttp.h> 9 #include <winhttp.h>
10 #endif 10 #endif
11 11
12 #include <algorithm> 12 #include <algorithm>
13 13
14 #include "base/compiler_specific.h"
14 #include "base/logging.h" 15 #include "base/logging.h"
15 #include "base/message_loop.h" 16 #include "base/message_loop.h"
16 #include "base/string_tokenizer.h" 17 #include "base/string_tokenizer.h"
17 #include "base/string_util.h" 18 #include "base/string_util.h"
18 #include "googleurl/src/gurl.h" 19 #include "googleurl/src/gurl.h"
19 #include "net/base/net_errors.h" 20 #include "net/base/net_errors.h"
20 #include "net/proxy/proxy_config_service_fixed.h" 21 #include "net/proxy/proxy_config_service_fixed.h"
21 #if defined(OS_WIN) 22 #if defined(OS_WIN)
22 #include "net/proxy/proxy_config_service_win.h" 23 #include "net/proxy/proxy_config_service_win.h"
23 #include "net/proxy/proxy_resolver_winhttp.h" 24 #include "net/proxy/proxy_resolver_winhttp.h"
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after
158 } 159 }
159 160
160 void ProxyInfo::UseDirect() { 161 void ProxyInfo::UseDirect() {
161 proxy_list_.Set(std::string()); 162 proxy_list_.Set(std::string());
162 } 163 }
163 164
164 void ProxyInfo::UseNamedProxy(const std::string& proxy_server) { 165 void ProxyInfo::UseNamedProxy(const std::string& proxy_server) {
165 proxy_list_.Set(proxy_server); 166 proxy_list_.Set(proxy_server);
166 } 167 }
167 168
168 #if defined(OS_WIN)
169 void ProxyInfo::Apply(HINTERNET request_handle) {
170 WINHTTP_PROXY_INFO pi;
171 std::wstring proxy; // We need to declare this variable here because
172 // lpszProxy needs to be valid in WinHttpSetOption.
173 if (is_direct()) {
174 pi.dwAccessType = WINHTTP_ACCESS_TYPE_NO_PROXY;
175 pi.lpszProxy = WINHTTP_NO_PROXY_NAME;
176 pi.lpszProxyBypass = WINHTTP_NO_PROXY_BYPASS;
177 } else {
178 proxy = ASCIIToWide(proxy_list_.Get());
179 pi.dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
180 pi.lpszProxy = const_cast<LPWSTR>(proxy.c_str());
181 // NOTE: Specifying a bypass list here would serve no purpose.
182 pi.lpszProxyBypass = WINHTTP_NO_PROXY_BYPASS;
183 }
184 WinHttpSetOption(request_handle, WINHTTP_OPTION_PROXY, &pi, sizeof(pi));
185 }
186 #endif
187
188 std::string ProxyInfo::GetAnnotatedProxyList() { 169 std::string ProxyInfo::GetAnnotatedProxyList() {
189 return is_direct() ? "DIRECT" : proxy_list_.GetAnnotatedList(); 170 return is_direct() ? "DIRECT" : proxy_list_.GetAnnotatedList();
190 } 171 }
191 172
192 // ProxyService::PacRequest --------------------------------------------------- 173 // ProxyService::PacRequest ---------------------------------------------------
193 174
194 // We rely on the fact that the origin thread (and its message loop) will not 175 // We rely on the fact that the origin thread (and its message loop) will not
195 // be destroyed until after the PAC thread is destroyed. 176 // be destroyed until after the PAC thread is destroyed.
196 177
197 class ProxyService::PacRequest : 178 class ProxyService::PacRequest :
198 public base::RefCountedThreadSafe<ProxyService::PacRequest> { 179 public base::RefCountedThreadSafe<ProxyService::PacRequest> {
199 public: 180 public:
200 PacRequest(ProxyService* service, 181 PacRequest(ProxyService* service,
201 const GURL& pac_url, 182 const GURL& pac_url,
202 CompletionCallback* callback) 183 CompletionCallback* callback)
203 : service_(service), 184 : service_(service),
204 callback_(callback), 185 callback_(callback),
205 results_(NULL), 186 results_(NULL),
206 config_id_(service->config_id()), 187 config_id_(service->config_id()),
207 pac_url_(pac_url), 188 pac_url_(pac_url),
208 origin_loop_(NULL) { 189 origin_loop_(MessageLoop::current()) {
209 // We need to remember original loop if only in case of asynchronous call 190 DCHECK(callback);
210 if (callback_)
211 origin_loop_ = MessageLoop::current();
212 } 191 }
213 192
214 void Query(const GURL& url, ProxyInfo* results) { 193 void Query(const GURL& url, ProxyInfo* results) {
215 results_ = results; 194 results_ = results;
216 // If we have a valid callback then execute Query asynchronously 195 // Execute Query asynchronously
217 if (callback_) { 196 AddRef(); // balanced in QueryComplete
218 AddRef(); // balanced in QueryComplete 197 service_->pac_thread()->message_loop()->PostTask(FROM_HERE,
219 service_->pac_thread()->message_loop()->PostTask(FROM_HERE, 198 NewRunnableMethod(this, &ProxyService::PacRequest::DoQuery,
220 NewRunnableMethod(this, &ProxyService::PacRequest::DoQuery, 199 service_->resolver(), url, pac_url_));
221 service_->resolver(), url, pac_url_));
222 } else {
223 DoQuery(service_->resolver(), url, pac_url_);
224 }
225 } 200 }
226 201
227 void Cancel() { 202 void Cancel() {
228 // Clear these to inform QueryComplete that it should not try to 203 // Clear these to inform QueryComplete that it should not try to
229 // access them. 204 // access them.
230 service_ = NULL; 205 service_ = NULL;
231 callback_ = NULL; 206 callback_ = NULL;
232 results_ = NULL; 207 results_ = NULL;
233 } 208 }
234 209
235 private: 210 private:
236 // Runs on the PAC thread if a valid callback is provided. 211 // Runs on the PAC thread.
237 void DoQuery(ProxyResolver* resolver, 212 void DoQuery(ProxyResolver* resolver,
238 const GURL& query_url, 213 const GURL& query_url,
239 const GURL& pac_url) { 214 const GURL& pac_url) {
240 int rv = resolver->GetProxyForURL(query_url, pac_url, &results_buf_); 215 int rv = resolver->GetProxyForURL(query_url, pac_url, &results_buf_);
241 if (origin_loop_) { 216 origin_loop_->PostTask(FROM_HERE,
242 origin_loop_->PostTask(FROM_HERE, 217 NewRunnableMethod(this, &PacRequest::QueryComplete, rv));
243 NewRunnableMethod(this, &PacRequest::QueryComplete, rv));
244 } else {
245 QueryComplete(rv);
246 }
247 } 218 }
248 219
249 // If a valid callback is provided, this runs on the origin thread to 220 // Runs the completion callback on the origin thread.
250 // indicate that the completion callback should be run.
251 void QueryComplete(int result_code) { 221 void QueryComplete(int result_code) {
252 if (service_) 222 // The PacRequest may have been cancelled after it was started. If it was
223 // cancelled then |callback_|, |service_|, and |results_| will be NULL.
224 bool was_cancelled = callback_ == NULL;
225
226 if (!was_cancelled) {
253 service_->DidCompletePacRequest(config_id_, result_code); 227 service_->DidCompletePacRequest(config_id_, result_code);
254 228
255 if (result_code == OK && results_) { 229 if (result_code == OK) {
256 results_->Use(results_buf_); 230 results_->Use(results_buf_);
257 results_->RemoveBadProxies(service_->proxy_retry_info_); 231 results_->RemoveBadProxies(service_->proxy_retry_info_);
232 }
233 callback_->Run(result_code);
258 } 234 }
259 235
260 if (callback_) 236 Release(); // balances the AddRef in Query. we may get deleted after
261 callback_->Run(result_code); 237 // we return.
262
263 if (origin_loop_) {
264 Release(); // balances the AddRef in Query. we may get deleted after
265 // we return.
266 }
267 } 238 }
268 239
269 // Must only be used on the "origin" thread. 240 // Must only be used on the "origin" thread.
270 ProxyService* service_; 241 ProxyService* service_;
271 CompletionCallback* callback_; 242 CompletionCallback* callback_;
272 ProxyInfo* results_; 243 ProxyInfo* results_;
273 ProxyConfig::ID config_id_; 244 ProxyConfig::ID config_id_;
274 245
275 // Usable from within DoQuery on the PAC thread. 246 // Usable from within DoQuery on the PAC thread.
276 ProxyInfo results_buf_; 247 ProxyInfo results_buf_;
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
314 // static 285 // static
315 ProxyService* ProxyService::CreateNull() { 286 ProxyService* ProxyService::CreateNull() {
316 // The ProxyResolver is set to NULL, since it should never be called 287 // The ProxyResolver is set to NULL, since it should never be called
317 // (because the configuration will never require PAC). 288 // (because the configuration will never require PAC).
318 return new ProxyService(new ProxyConfigServiceNull, NULL); 289 return new ProxyService(new ProxyConfigServiceNull, NULL);
319 } 290 }
320 291
321 int ProxyService::ResolveProxy(const GURL& url, ProxyInfo* result, 292 int ProxyService::ResolveProxy(const GURL& url, ProxyInfo* result,
322 CompletionCallback* callback, 293 CompletionCallback* callback,
323 PacRequest** pac_request) { 294 PacRequest** pac_request) {
295 DCHECK(callback);
324 // The overhead of calling ProxyConfigService::GetProxyConfig is very low. 296 // The overhead of calling ProxyConfigService::GetProxyConfig is very low.
325 const TimeDelta kProxyConfigMaxAge = TimeDelta::FromSeconds(5); 297 const TimeDelta kProxyConfigMaxAge = TimeDelta::FromSeconds(5);
326 298
327 // Periodically check for a new config. 299 // Periodically check for a new config.
328 if (!config_has_been_updated_ || 300 if (!config_has_been_updated_ ||
329 (TimeTicks::Now() - config_last_update_time_) > kProxyConfigMaxAge) 301 (TimeTicks::Now() - config_last_update_time_) > kProxyConfigMaxAge)
330 UpdateConfig(); 302 UpdateConfig();
331 result->config_id_ = config_.id(); 303 result->config_id_ = config_.id();
332 304
333 // Fallback to a "direct" (no proxy) connection if the current configuration 305 // Fallback to a "direct" (no proxy) connection if the current configuration
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
374 } 346 }
375 } 347 }
376 // We failed to find a matching proxy server for the current URL 348 // We failed to find a matching proxy server for the current URL
377 // scheme. Default to direct. 349 // scheme. Default to direct.
378 result->UseDirect(); 350 result->UseDirect();
379 } 351 }
380 return OK; 352 return OK;
381 } 353 }
382 354
383 if (config_.pac_url.is_valid() || config_.auto_detect) { 355 if (config_.pac_url.is_valid() || config_.auto_detect) {
384 if (callback) { 356 if (!pac_thread_.get()) {
385 // Create PAC thread for asynchronous mode. 357 pac_thread_.reset(new base::Thread("pac-thread"));
386 if (!pac_thread_.get()) { 358 pac_thread_->Start();
387 pac_thread_.reset(new base::Thread("pac-thread"));
388 pac_thread_->Start();
389 }
390 } else {
391 // If this request is synchronous, then there's no point
392 // in returning PacRequest instance
393 DCHECK(!pac_request);
394 } 359 }
395 360
396 scoped_refptr<PacRequest> req = 361 scoped_refptr<PacRequest> req =
397 new PacRequest(this, config_.pac_url, callback); 362 new PacRequest(this, config_.pac_url, callback);
398 363
399 // Strip away any reference fragments and the username/password, as they 364 // Strip away any reference fragments and the username/password, as they
400 // are not relevant to proxy resolution. 365 // are not relevant to proxy resolution.
401 GURL sanitized_url; 366 GURL sanitized_url;
402 { // TODO(eroman): The following duplicates logic from 367 { // TODO(eroman): The following duplicates logic from
403 // HttpUtil::SpecForRequest. Should probably live in net_util.h 368 // HttpUtil::SpecForRequest. Should probably live in net_util.h
404 GURL::Replacements replacements; 369 GURL::Replacements replacements;
405 replacements.ClearUsername(); 370 replacements.ClearUsername();
406 replacements.ClearPassword(); 371 replacements.ClearPassword();
407 replacements.ClearRef(); 372 replacements.ClearRef();
408 sanitized_url = url.ReplaceComponents(replacements); 373 sanitized_url = url.ReplaceComponents(replacements);
409 } 374 }
410 375
411 req->Query(sanitized_url, result); 376 req->Query(sanitized_url, result);
412 377
413 if (callback) { 378 if (pac_request)
414 if (pac_request) 379 *pac_request = req;
415 *pac_request = req; 380
416 return ERR_IO_PENDING; // Wait for callback. 381 return ERR_IO_PENDING; // Wait for callback.
417 }
418 return OK;
419 } 382 }
420 } 383 }
421 384
422 // otherwise, we have no proxy config 385 // otherwise, we have no proxy config
423 result->UseDirect(); 386 result->UseDirect();
424 return OK; 387 return OK;
425 } 388 }
426 389
427 int ProxyService::ReconsiderProxyAfterError(const GURL& url, 390 int ProxyService::ReconsiderProxyAfterError(const GURL& url,
428 ProxyInfo* result, 391 ProxyInfo* result,
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
547 // Some systems (the Mac, for example) allow CIDR-style specification of 510 // Some systems (the Mac, for example) allow CIDR-style specification of
548 // proxy bypass for IP-specified hosts (e.g. "10.0.0.0/8"; see 511 // proxy bypass for IP-specified hosts (e.g. "10.0.0.0/8"; see
549 // http://www.tcd.ie/iss/internet/osx_proxy.php for a real-world example). 512 // http://www.tcd.ie/iss/internet/osx_proxy.php for a real-world example).
550 // That's kinda cool so we'll provide that for everyone. 513 // That's kinda cool so we'll provide that for everyone.
551 // TODO(avi): implement here 514 // TODO(avi): implement here
552 } 515 }
553 516
554 return false; 517 return false;
555 } 518 }
556 519
520 SyncProxyServiceHelper::SyncProxyServiceHelper(MessageLoop* io_message_loop,
521 ProxyService* proxy_service)
522 : io_message_loop_(io_message_loop),
523 proxy_service_(proxy_service),
524 event_(false, false),
525 ALLOW_THIS_IN_INITIALIZER_LIST(callback_(
526 this, &SyncProxyServiceHelper::OnCompletion)) {
527 DCHECK(io_message_loop_ != MessageLoop::current());
528 }
529
530 int SyncProxyServiceHelper::ResolveProxy(const GURL& url,
531 ProxyInfo* proxy_info) {
532 DCHECK(io_message_loop_ != MessageLoop::current());
533
534 io_message_loop_->PostTask(FROM_HERE, NewRunnableMethod(
535 this, &SyncProxyServiceHelper::StartAsyncResolve, url));
536
537 event_.Wait();
538
539 if (result_ == net::OK) {
540 *proxy_info = proxy_info_;
541 }
542 return result_;
543 }
544
545 int SyncProxyServiceHelper::ReconsiderProxyAfterError(const GURL& url,
546 ProxyInfo* proxy_info) {
547 DCHECK(io_message_loop_ != MessageLoop::current());
548
549 io_message_loop_->PostTask(FROM_HERE, NewRunnableMethod(
550 this, &SyncProxyServiceHelper::StartAsyncReconsider, url));
551
552 event_.Wait();
553
554 if (result_ == net::OK) {
555 *proxy_info = proxy_info_;
556 }
557 return result_;
558 }
559
560 void SyncProxyServiceHelper::StartAsyncResolve(const GURL& url) {
561 result_ = proxy_service_->ResolveProxy(url, &proxy_info_, &callback_, NULL);
562 if (result_ != net::ERR_IO_PENDING) {
563 OnCompletion(result_);
564 }
565 }
566
567 void SyncProxyServiceHelper::StartAsyncReconsider(const GURL& url) {
568 result_ = proxy_service_->ReconsiderProxyAfterError(
569 url, &proxy_info_, &callback_, NULL);
570 if (result_ != net::ERR_IO_PENDING) {
571 OnCompletion(result_);
572 }
573 }
574
575 void SyncProxyServiceHelper::OnCompletion(int rv) {
576 result_ = rv;
577 event_.Signal();
578 }
579
557 } // namespace net 580 } // namespace net
558 581
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698