| OLD | NEW |
| 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 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/compiler_specific.h" | 9 #include "base/compiler_specific.h" |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| 11 #include "base/message_loop.h" |
| 11 #include "base/string_util.h" | 12 #include "base/string_util.h" |
| 12 #include "googleurl/src/gurl.h" | 13 #include "googleurl/src/gurl.h" |
| 13 #include "net/base/net_errors.h" | 14 #include "net/base/net_errors.h" |
| 14 #include "net/proxy/proxy_config_service_fixed.h" | 15 #include "net/proxy/proxy_config_service_fixed.h" |
| 15 #include "net/proxy/proxy_script_fetcher.h" | 16 #include "net/proxy/proxy_script_fetcher.h" |
| 16 #if defined(OS_WIN) | 17 #if defined(OS_WIN) |
| 17 #include "net/proxy/proxy_config_service_win.h" | 18 #include "net/proxy/proxy_config_service_win.h" |
| 18 #include "net/proxy/proxy_resolver_winhttp.h" | 19 #include "net/proxy/proxy_resolver_winhttp.h" |
| 19 #elif defined(OS_MACOSX) | 20 #elif defined(OS_MACOSX) |
| 20 #include "net/proxy/proxy_resolver_mac.h" | 21 #include "net/proxy/proxy_resolver_mac.h" |
| 21 #elif defined(OS_LINUX) | 22 #elif defined(OS_LINUX) |
| 22 #include "net/proxy/proxy_config_service_linux.h" | 23 #include "net/proxy/proxy_config_service_linux.h" |
| 23 #endif | 24 #endif |
| 24 #include "net/proxy/proxy_resolver.h" | 25 #include "net/proxy/proxy_resolver.h" |
| 25 #include "net/proxy/proxy_resolver_v8.h" | 26 #include "net/proxy/proxy_resolver_v8.h" |
| 27 #include "net/proxy/single_threaded_proxy_resolver.h" |
| 26 #include "net/url_request/url_request_context.h" | 28 #include "net/url_request/url_request_context.h" |
| 27 | 29 |
| 28 using base::TimeDelta; | 30 using base::TimeDelta; |
| 29 using base::TimeTicks; | 31 using base::TimeTicks; |
| 30 | 32 |
| 31 namespace net { | 33 namespace net { |
| 32 | 34 |
| 33 // Config getter that fails every time. | 35 // Config getter that fails every time. |
| 34 class ProxyConfigServiceNull : public ProxyConfigService { | 36 class ProxyConfigServiceNull : public ProxyConfigService { |
| 35 public: | 37 public: |
| 36 // ProxyConfigService implementation: | 38 // ProxyConfigService implementation: |
| 37 virtual int GetProxyConfig(ProxyConfig* config) { | 39 virtual int GetProxyConfig(ProxyConfig* config) { |
| 38 return ERR_NOT_IMPLEMENTED; | 40 return ERR_NOT_IMPLEMENTED; |
| 39 } | 41 } |
| 40 }; | 42 }; |
| 41 | 43 |
| 42 // Proxy resolver that fails every time. | 44 // Proxy resolver that fails every time. |
| 43 class ProxyResolverNull : public ProxyResolver { | 45 class ProxyResolverNull : public ProxyResolver { |
| 44 public: | 46 public: |
| 45 ProxyResolverNull() : ProxyResolver(true /*does_fetch*/) {} | 47 ProxyResolverNull() : ProxyResolver(false /*expects_pac_bytes*/) {} |
| 46 | 48 |
| 47 // ProxyResolver implementation: | 49 // ProxyResolver implementation: |
| 48 virtual int GetProxyForURL(const GURL& /*query_url*/, | 50 virtual int GetProxyForURL(const GURL& url, |
| 49 const GURL& /*pac_url*/, | 51 ProxyInfo* results, |
| 50 ProxyInfo* /*results*/) { | 52 CompletionCallback* callback, |
| 53 RequestHandle* request) { |
| 51 return ERR_NOT_IMPLEMENTED; | 54 return ERR_NOT_IMPLEMENTED; |
| 52 } | 55 } |
| 56 |
| 57 virtual void CancelRequest(RequestHandle request) { |
| 58 NOTREACHED(); |
| 59 } |
| 60 |
| 61 private: |
| 62 virtual void SetPacScriptByUrlInternal(const GURL& pac_url) {} |
| 53 }; | 63 }; |
| 54 | 64 |
| 55 // Strip away any reference fragments and the username/password, as they | 65 // Strip away any reference fragments and the username/password, as they |
| 56 // are not relevant to proxy resolution. | 66 // are not relevant to proxy resolution. |
| 57 static GURL SanitizeURLForProxyResolver(const GURL& url) { | 67 static GURL SanitizeURLForProxyResolver(const GURL& url) { |
| 58 // TODO(eroman): The following duplicates logic from | 68 // TODO(eroman): The following duplicates logic from |
| 59 // HttpUtil::SpecForRequest. Should probably live in net_util.h | 69 // HttpUtil::SpecForRequest. Should probably live in net_util.h |
| 60 GURL::Replacements replacements; | 70 GURL::Replacements replacements; |
| 61 replacements.ClearUsername(); | 71 replacements.ClearUsername(); |
| 62 replacements.ClearPassword(); | 72 replacements.ClearPassword(); |
| 63 replacements.ClearRef(); | 73 replacements.ClearRef(); |
| 64 return url.ReplaceComponents(replacements); | 74 return url.ReplaceComponents(replacements); |
| 65 } | 75 } |
| 66 | 76 |
| 67 // Runs on the PAC thread to notify the proxy resolver of the fetched PAC | |
| 68 // script contents. This task shouldn't outlive ProxyService, since | |
| 69 // |resolver| is owned by ProxyService. | |
| 70 class NotifyFetchCompletionTask : public Task { | |
| 71 public: | |
| 72 NotifyFetchCompletionTask(ProxyResolver* resolver, const std::string& bytes) | |
| 73 : resolver_(resolver), bytes_(bytes) {} | |
| 74 | |
| 75 virtual void Run() { | |
| 76 resolver_->SetPacScript(bytes_); | |
| 77 } | |
| 78 | |
| 79 private: | |
| 80 ProxyResolver* resolver_; | |
| 81 std::string bytes_; | |
| 82 }; | |
| 83 | |
| 84 // ProxyService::PacRequest --------------------------------------------------- | 77 // ProxyService::PacRequest --------------------------------------------------- |
| 85 | 78 |
| 86 // We rely on the fact that the origin thread (and its message loop) will not | |
| 87 // be destroyed until after the PAC thread is destroyed. | |
| 88 | |
| 89 class ProxyService::PacRequest | 79 class ProxyService::PacRequest |
| 90 : public base::RefCountedThreadSafe<ProxyService::PacRequest> { | 80 : public base::RefCounted<ProxyService::PacRequest> { |
| 91 public: | 81 public: |
| 92 // |service| -- the ProxyService that owns this request. | |
| 93 // |url| -- the url of the query. | |
| 94 // |results| -- the structure to fill with proxy resolve results. | |
| 95 PacRequest(ProxyService* service, | 82 PacRequest(ProxyService* service, |
| 96 const GURL& url, | 83 const GURL& url, |
| 97 ProxyInfo* results, | 84 ProxyInfo* results, |
| 98 CompletionCallback* callback) | 85 CompletionCallback* user_callback) |
| 99 : service_(service), | 86 : service_(service), |
| 100 callback_(callback), | 87 user_callback_(user_callback), |
| 88 ALLOW_THIS_IN_INITIALIZER_LIST(io_callback_( |
| 89 this, &PacRequest::QueryComplete)), |
| 101 results_(results), | 90 results_(results), |
| 102 url_(url), | 91 url_(url), |
| 103 is_started_(false), | 92 resolve_job_(NULL), |
| 104 origin_loop_(MessageLoop::current()) { | 93 config_id_(ProxyConfig::INVALID_ID) { |
| 105 DCHECK(callback); | 94 DCHECK(user_callback); |
| 106 } | 95 } |
| 107 | 96 |
| 108 // Start the resolve proxy request on the PAC thread. | 97 // Starts the resolve proxy request. |
| 109 void Query() { | 98 int Start() { |
| 110 is_started_ = true; | 99 DCHECK(!was_cancelled()); |
| 111 AddRef(); // balanced in QueryComplete | 100 DCHECK(!is_started()); |
| 112 | 101 |
| 113 GURL query_url = SanitizeURLForProxyResolver(url_); | 102 config_id_ = service_->config_.id(); |
| 114 const GURL& pac_url = service_->config_.pac_url; | |
| 115 results_->config_id_ = service_->config_.id(); | |
| 116 | 103 |
| 117 service_->pac_thread()->message_loop()->PostTask(FROM_HERE, | 104 return resolver()->GetProxyForURL( |
| 118 NewRunnableMethod(this, &ProxyService::PacRequest::DoQuery, | 105 url_, results_, &io_callback_, &resolve_job_); |
| 119 service_->resolver(), query_url, pac_url)); | |
| 120 } | 106 } |
| 121 | 107 |
| 122 // Run the request's callback on the current message loop. | 108 bool is_started() const { |
| 123 void PostCallback(int result_code) { | 109 // Note that !! casts to bool. (VS gives a warning otherwise). |
| 124 AddRef(); // balanced in DoCallback | 110 return !!resolve_job_; |
| 125 MessageLoop::current()->PostTask(FROM_HERE, | 111 } |
| 126 NewRunnableMethod(this, &ProxyService::PacRequest::DoCallback, | 112 |
| 127 result_code)); | 113 void StartAndComplete() { |
| 114 int rv = Start(); |
| 115 if (rv != ERR_IO_PENDING) |
| 116 QueryComplete(rv); |
| 128 } | 117 } |
| 129 | 118 |
| 130 void Cancel() { | 119 void Cancel() { |
| 131 // Clear these to inform QueryComplete that it should not try to | 120 // The request may already be running in the resolver. |
| 132 // access them. | 121 if (is_started()) { |
| 122 resolver()->CancelRequest(resolve_job_); |
| 123 resolve_job_ = NULL; |
| 124 } |
| 125 |
| 126 // Mark as cancelled, to prevent accessing this again later. |
| 133 service_ = NULL; | 127 service_ = NULL; |
| 134 callback_ = NULL; | 128 user_callback_ = NULL; |
| 135 results_ = NULL; | 129 results_ = NULL; |
| 136 } | 130 } |
| 137 | 131 |
| 138 // Returns true if Cancel() has been called. | 132 // Returns true if Cancel() has been called. |
| 139 bool was_cancelled() const { return callback_ == NULL; } | 133 bool was_cancelled() const { return user_callback_ == NULL; } |
| 134 |
| 135 // Helper to call after ProxyResolver completion (both synchronous and |
| 136 // asynchronous). Fixes up the result that is to be returned to user. |
| 137 int QueryDidComplete(int result_code) { |
| 138 DCHECK(!was_cancelled()); |
| 139 |
| 140 // Make a note in the results which configuration was in use at the |
| 141 // time of the resolve. |
| 142 results_->config_id_ = config_id_; |
| 143 |
| 144 // Reset the state associated with in-progress-resolve. |
| 145 resolve_job_ = NULL; |
| 146 config_id_ = ProxyConfig::INVALID_ID; |
| 147 |
| 148 // Notify the service of the completion. |
| 149 service_->DidCompletePacRequest(results_->config_id_, result_code); |
| 150 |
| 151 // Clean up the results list. |
| 152 if (result_code == OK) |
| 153 results_->RemoveBadProxies(service_->proxy_retry_info_); |
| 154 |
| 155 return result_code; |
| 156 } |
| 140 | 157 |
| 141 private: | 158 private: |
| 142 friend class ProxyService; | 159 // Callback for when the ProxyResolver request has completed. |
| 160 void QueryComplete(int result_code) { |
| 161 result_code = QueryDidComplete(result_code); |
| 143 | 162 |
| 144 // Runs on the PAC thread. | 163 // Remove this completed PacRequest from the service's pending list. |
| 145 void DoQuery(ProxyResolver* resolver, | 164 /// (which will probably cause deletion of |this|). |
| 146 const GURL& query_url, | 165 CompletionCallback* callback = user_callback_; |
| 147 const GURL& pac_url) { | 166 service_->RemovePendingRequest(this); |
| 148 int rv = resolver->GetProxyForURL(query_url, pac_url, &results_buf_); | 167 |
| 149 origin_loop_->PostTask(FROM_HERE, | 168 callback->Run(result_code); |
| 150 NewRunnableMethod(this, &PacRequest::QueryComplete, rv)); | |
| 151 } | 169 } |
| 152 | 170 |
| 153 // Runs the completion callback on the origin thread. | 171 ProxyResolver* resolver() const { return service_->resolver_.get(); } |
| 154 void QueryComplete(int result_code) { | |
| 155 // The PacRequest may have been cancelled after it was started. | |
| 156 if (!was_cancelled()) { | |
| 157 service_->DidCompletePacRequest(results_->config_id_, result_code); | |
| 158 | 172 |
| 159 if (result_code == OK) { | |
| 160 results_->Use(results_buf_); | |
| 161 results_->RemoveBadProxies(service_->proxy_retry_info_); | |
| 162 } | |
| 163 callback_->Run(result_code); | |
| 164 | |
| 165 // We check for cancellation once again, in case the callback deleted | |
| 166 // the owning ProxyService (whose destructor will in turn cancel us). | |
| 167 if (!was_cancelled()) | |
| 168 service_->RemoveFrontOfRequestQueue(this); | |
| 169 } | |
| 170 | |
| 171 Release(); // balances the AddRef in Query. we may get deleted after | |
| 172 // we return. | |
| 173 } | |
| 174 | |
| 175 // Runs the completion callback on the origin thread. | |
| 176 void DoCallback(int result_code) { | |
| 177 if (!was_cancelled()) { | |
| 178 callback_->Run(result_code); | |
| 179 } | |
| 180 Release(); // balances the AddRef in PostCallback. | |
| 181 } | |
| 182 | |
| 183 // Must only be used on the "origin" thread. | |
| 184 ProxyService* service_; | 173 ProxyService* service_; |
| 185 CompletionCallback* callback_; | 174 CompletionCallback* user_callback_; |
| 175 CompletionCallbackImpl<PacRequest> io_callback_; |
| 186 ProxyInfo* results_; | 176 ProxyInfo* results_; |
| 187 GURL url_; | 177 GURL url_; |
| 188 bool is_started_; | 178 ProxyResolver::RequestHandle resolve_job_; |
| 189 | 179 ProxyConfig::ID config_id_; // The config id when the resolve was started. |
| 190 // Usable from within DoQuery on the PAC thread. | |
| 191 ProxyInfo results_buf_; | |
| 192 MessageLoop* origin_loop_; | |
| 193 }; | 180 }; |
| 194 | 181 |
| 195 // ProxyService --------------------------------------------------------------- | 182 // ProxyService --------------------------------------------------------------- |
| 196 | 183 |
| 197 ProxyService::ProxyService(ProxyConfigService* config_service, | 184 ProxyService::ProxyService(ProxyConfigService* config_service, |
| 198 ProxyResolver* resolver) | 185 ProxyResolver* resolver) |
| 199 : config_service_(config_service), | 186 : config_service_(config_service), |
| 200 resolver_(resolver), | 187 resolver_(resolver), |
| 201 next_config_id_(1), | 188 next_config_id_(1), |
| 202 config_is_bad_(false), | 189 config_is_bad_(false), |
| (...skipping 21 matching lines...) Expand all Loading... |
| 224 // Send javascript errors and alerts to LOG(INFO). | 211 // Send javascript errors and alerts to LOG(INFO). |
| 225 HostResolver* host_resolver = url_request_context->host_resolver(); | 212 HostResolver* host_resolver = url_request_context->host_resolver(); |
| 226 ProxyResolverV8::JSBindings* js_bindings = | 213 ProxyResolverV8::JSBindings* js_bindings = |
| 227 ProxyResolverV8::CreateDefaultBindings(host_resolver, io_loop); | 214 ProxyResolverV8::CreateDefaultBindings(host_resolver, io_loop); |
| 228 | 215 |
| 229 proxy_resolver = new ProxyResolverV8(js_bindings); | 216 proxy_resolver = new ProxyResolverV8(js_bindings); |
| 230 } else { | 217 } else { |
| 231 proxy_resolver = CreateNonV8ProxyResolver(); | 218 proxy_resolver = CreateNonV8ProxyResolver(); |
| 232 } | 219 } |
| 233 | 220 |
| 221 // Wrap the (synchronous) ProxyResolver implementation in a single-threaded |
| 222 // runner. This will dispatch requests to a threadpool of size 1. |
| 223 proxy_resolver = new SingleThreadedProxyResolver(proxy_resolver); |
| 224 |
| 234 ProxyService* proxy_service = new ProxyService( | 225 ProxyService* proxy_service = new ProxyService( |
| 235 proxy_config_service, proxy_resolver); | 226 proxy_config_service, proxy_resolver); |
| 236 | 227 |
| 237 if (!proxy_resolver->does_fetch()) { | 228 if (proxy_resolver->expects_pac_bytes()) { |
| 238 // Configure PAC script downloads to be issued using |url_request_context|. | 229 // Configure PAC script downloads to be issued using |url_request_context|. |
| 239 DCHECK(url_request_context); | 230 DCHECK(url_request_context); |
| 240 proxy_service->SetProxyScriptFetcher( | 231 proxy_service->SetProxyScriptFetcher( |
| 241 ProxyScriptFetcher::Create(url_request_context)); | 232 ProxyScriptFetcher::Create(url_request_context)); |
| 242 } | 233 } |
| 243 | 234 |
| 244 return proxy_service; | 235 return proxy_service; |
| 245 } | 236 } |
| 246 | 237 |
| 247 // static | 238 // static |
| 248 ProxyService* ProxyService::CreateFixed(const ProxyConfig& pc) { | 239 ProxyService* ProxyService::CreateFixed(const ProxyConfig& pc) { |
| 249 return Create(&pc, false, NULL, NULL); | 240 return Create(&pc, false, NULL, NULL); |
| 250 } | 241 } |
| 251 | 242 |
| 252 // static | 243 // static |
| 253 ProxyService* ProxyService::CreateNull() { | 244 ProxyService* ProxyService::CreateNull() { |
| 254 // Use a configuration fetcher and proxy resolver which always fail. | 245 // Use a configuration fetcher and proxy resolver which always fail. |
| 255 return new ProxyService(new ProxyConfigServiceNull, new ProxyResolverNull); | 246 return new ProxyService(new ProxyConfigServiceNull, new ProxyResolverNull); |
| 256 } | 247 } |
| 257 | 248 |
| 258 int ProxyService::ResolveProxy(const GURL& url, ProxyInfo* result, | 249 int ProxyService::ResolveProxy(const GURL& raw_url, ProxyInfo* result, |
| 259 CompletionCallback* callback, | 250 CompletionCallback* callback, |
| 260 PacRequest** pac_request) { | 251 PacRequest** pac_request) { |
| 261 DCHECK(callback); | 252 DCHECK(callback); |
| 262 | 253 |
| 254 GURL url = SanitizeURLForProxyResolver(raw_url); |
| 255 |
| 263 // Check if the request can be completed right away. This is the case when | 256 // Check if the request can be completed right away. This is the case when |
| 264 // using a direct connection, or when the config is bad. | 257 // using a direct connection, or when the config is bad. |
| 265 UpdateConfigIfOld(); | 258 UpdateConfigIfOld(); |
| 266 int rv = TryToCompleteSynchronously(url, result); | 259 int rv = TryToCompleteSynchronously(url, result); |
| 267 if (rv != ERR_IO_PENDING) | 260 if (rv != ERR_IO_PENDING) |
| 268 return rv; | 261 return rv; |
| 269 | 262 |
| 270 // Otherwise, push the request into the work queue. | |
| 271 scoped_refptr<PacRequest> req = new PacRequest(this, url, result, callback); | 263 scoped_refptr<PacRequest> req = new PacRequest(this, url, result, callback); |
| 264 |
| 265 bool resolver_is_ready = PrepareResolverForRequests(); |
| 266 |
| 267 if (resolver_is_ready) { |
| 268 // Start the resolve request. |
| 269 rv = req->Start(); |
| 270 if (rv != ERR_IO_PENDING) |
| 271 return req->QueryDidComplete(rv); |
| 272 } |
| 273 |
| 274 DCHECK_EQ(ERR_IO_PENDING, rv); |
| 275 DCHECK(!ContainsPendingRequest(req)); |
| 272 pending_requests_.push_back(req); | 276 pending_requests_.push_back(req); |
| 273 ProcessPendingRequests(req.get()); | |
| 274 | 277 |
| 275 // Completion will be notifed through |callback|, unless the caller cancels | 278 // Completion will be notifed through |callback|, unless the caller cancels |
| 276 // the request using |pac_request|. | 279 // the request using |pac_request|. |
| 277 if (pac_request) | 280 if (pac_request) |
| 278 *pac_request = req.get(); | 281 *pac_request = req.get(); |
| 279 return rv; // ERR_IO_PENDING | 282 return rv; // ERR_IO_PENDING |
| 280 } | 283 } |
| 281 | 284 |
| 282 int ProxyService::TryToCompleteSynchronously(const GURL& url, | 285 int ProxyService::TryToCompleteSynchronously(const GURL& url, |
| 283 ProxyInfo* result) { | 286 ProxyInfo* result) { |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 343 } | 346 } |
| 344 break; | 347 break; |
| 345 } | 348 } |
| 346 default: | 349 default: |
| 347 result->UseDirect(); | 350 result->UseDirect(); |
| 348 NOTREACHED(); | 351 NOTREACHED(); |
| 349 break; | 352 break; |
| 350 } | 353 } |
| 351 } | 354 } |
| 352 | 355 |
| 353 void ProxyService::InitPacThread() { | |
| 354 if (!pac_thread_.get()) { | |
| 355 pac_thread_.reset(new base::Thread("pac-thread")); | |
| 356 pac_thread_->Start(); | |
| 357 } | |
| 358 } | |
| 359 | |
| 360 ProxyService::~ProxyService() { | 356 ProxyService::~ProxyService() { |
| 361 // Cancel the inprogress request (if any), and free the rest. | 357 // Cancel any inprogress requests. |
| 362 for (PendingRequestsQueue::iterator it = pending_requests_.begin(); | 358 for (PendingRequests::iterator it = pending_requests_.begin(); |
| 363 it != pending_requests_.end(); | 359 it != pending_requests_.end(); |
| 364 ++it) { | 360 ++it) { |
| 365 (*it)->Cancel(); | 361 (*it)->Cancel(); |
| 366 } | 362 } |
| 367 } | 363 } |
| 368 | 364 |
| 369 void ProxyService::ProcessPendingRequests(PacRequest* recent_req) { | 365 void ProxyService::ResumeAllPendingRequests() { |
| 370 if (pending_requests_.empty()) | 366 // Make a copy in case |this| is deleted during the synchronous completion |
| 371 return; | 367 // of one of the requests. If |this| is deleted then all of the PacRequest |
| 368 // instances will be Cancel()-ed. |
| 369 PendingRequests pending_copy = pending_requests_; |
| 372 | 370 |
| 373 // While the PAC script is being downloaded, requests are blocked. | 371 for (PendingRequests::iterator it = pending_copy.begin(); |
| 372 it != pending_copy.end(); |
| 373 ++it) { |
| 374 PacRequest* req = it->get(); |
| 375 if (!req->is_started() && !req->was_cancelled()) |
| 376 req->StartAndComplete(); |
| 377 } |
| 378 } |
| 379 |
| 380 bool ProxyService::PrepareResolverForRequests() { |
| 381 // While the PAC script is being downloaded, block requests. |
| 374 if (IsFetchingPacScript()) | 382 if (IsFetchingPacScript()) |
| 375 return; | 383 return false; |
| 376 | |
| 377 // Get the next request to process (FIFO). | |
| 378 PacRequest* req = pending_requests_.front().get(); | |
| 379 if (req->is_started_) | |
| 380 return; | |
| 381 | |
| 382 // The configuration may have changed since |req| was added to the | |
| 383 // queue. It could be this request now completes synchronously. | |
| 384 if (req != recent_req) { | |
| 385 UpdateConfigIfOld(); | |
| 386 int rv = TryToCompleteSynchronously(req->url_, req->results_); | |
| 387 if (rv != ERR_IO_PENDING) { | |
| 388 req->PostCallback(rv); | |
| 389 RemoveFrontOfRequestQueue(req); | |
| 390 return; | |
| 391 } | |
| 392 } | |
| 393 | 384 |
| 394 // Check if a new PAC script needs to be downloaded. | 385 // Check if a new PAC script needs to be downloaded. |
| 395 DCHECK(config_.id() != ProxyConfig::INVALID_ID); | 386 DCHECK(config_.id() != ProxyConfig::INVALID_ID); |
| 396 if (!resolver_->does_fetch() && config_.id() != fetched_pac_config_id_) { | 387 if (resolver_->expects_pac_bytes() && |
| 388 config_.id() != fetched_pac_config_id_) { |
| 397 // For auto-detect we use the well known WPAD url. | 389 // For auto-detect we use the well known WPAD url. |
| 398 GURL pac_url = config_.auto_detect ? | 390 GURL pac_url = config_.auto_detect ? |
| 399 GURL("http://wpad/wpad.dat") : config_.pac_url; | 391 GURL("http://wpad/wpad.dat") : config_.pac_url; |
| 400 | 392 |
| 401 in_progress_fetch_config_id_ = config_.id(); | 393 in_progress_fetch_config_id_ = config_.id(); |
| 402 | 394 |
| 403 LOG(INFO) << "Starting fetch of PAC script " << pac_url | 395 LOG(INFO) << "Starting fetch of PAC script " << pac_url |
| 404 << " for config_id=" << in_progress_fetch_config_id_; | 396 << " for config_id=" << in_progress_fetch_config_id_; |
| 405 | 397 |
| 406 proxy_script_fetcher_->Fetch( | 398 proxy_script_fetcher_->Fetch( |
| 407 pac_url, &in_progress_fetch_bytes_, &proxy_script_fetcher_callback_); | 399 pac_url, &in_progress_fetch_bytes_, &proxy_script_fetcher_callback_); |
| 408 return; | 400 return false; |
| 409 } | 401 } |
| 410 | 402 |
| 411 // The only choice left now is to actually run the ProxyResolver on | 403 // We are good to go. |
| 412 // the PAC thread. | 404 return true; |
| 413 InitPacThread(); | |
| 414 req->Query(); | |
| 415 } | |
| 416 | |
| 417 void ProxyService::RemoveFrontOfRequestQueue(PacRequest* expected_req) { | |
| 418 DCHECK(pending_requests_.front().get() == expected_req); | |
| 419 pending_requests_.pop_front(); | |
| 420 | |
| 421 // Start next work item. | |
| 422 ProcessPendingRequests(NULL); | |
| 423 } | 405 } |
| 424 | 406 |
| 425 void ProxyService::OnScriptFetchCompletion(int result) { | 407 void ProxyService::OnScriptFetchCompletion(int result) { |
| 426 DCHECK(IsFetchingPacScript()); | 408 DCHECK(IsFetchingPacScript()); |
| 427 DCHECK(!resolver_->does_fetch()); | 409 DCHECK(resolver_->expects_pac_bytes()); |
| 428 | 410 |
| 429 LOG(INFO) << "Completed PAC script fetch for config_id=" | 411 LOG(INFO) << "Completed PAC script fetch for config_id=" |
| 430 << in_progress_fetch_config_id_ | 412 << in_progress_fetch_config_id_ |
| 431 << " with error " << ErrorToString(result) | 413 << " with error " << ErrorToString(result) |
| 432 << ". Fetched a total of " << in_progress_fetch_bytes_.size() | 414 << ". Fetched a total of " << in_progress_fetch_bytes_.size() |
| 433 << " bytes"; | 415 << " bytes"; |
| 434 | 416 |
| 435 // Notify the ProxyResolver of the new script data (will be empty string if | 417 // Notify the ProxyResolver of the new script data (will be empty string if |
| 436 // result != OK). | 418 // result != OK). |
| 437 InitPacThread(); | 419 resolver_->SetPacScriptByData(in_progress_fetch_bytes_); |
| 438 pac_thread()->message_loop()->PostTask(FROM_HERE, | |
| 439 new NotifyFetchCompletionTask( | |
| 440 resolver_.get(), in_progress_fetch_bytes_)); | |
| 441 | 420 |
| 442 fetched_pac_config_id_ = in_progress_fetch_config_id_; | 421 fetched_pac_config_id_ = in_progress_fetch_config_id_; |
| 443 fetched_pac_error_ = result; | 422 fetched_pac_error_ = result; |
| 444 in_progress_fetch_config_id_ = ProxyConfig::INVALID_ID; | 423 in_progress_fetch_config_id_ = ProxyConfig::INVALID_ID; |
| 445 in_progress_fetch_bytes_.clear(); | 424 in_progress_fetch_bytes_.clear(); |
| 446 | 425 |
| 447 // Start a pending request if any. | 426 // Resume any requests which we had to defer until the PAC script was |
| 448 ProcessPendingRequests(NULL); | 427 // downloaded. |
| 428 ResumeAllPendingRequests(); |
| 449 } | 429 } |
| 450 | 430 |
| 451 int ProxyService::ReconsiderProxyAfterError(const GURL& url, | 431 int ProxyService::ReconsiderProxyAfterError(const GURL& url, |
| 452 ProxyInfo* result, | 432 ProxyInfo* result, |
| 453 CompletionCallback* callback, | 433 CompletionCallback* callback, |
| 454 PacRequest** pac_request) { | 434 PacRequest** pac_request) { |
| 455 // Check to see if we have a new config since ResolveProxy was called. We | 435 // Check to see if we have a new config since ResolveProxy was called. We |
| 456 // want to re-run ResolveProxy in two cases: 1) we have a new config, or 2) a | 436 // want to re-run ResolveProxy in two cases: 1) we have a new config, or 2) a |
| 457 // direct connection failed and we never tried the current config. | 437 // direct connection failed and we never tried the current config. |
| 458 | 438 |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 491 | 471 |
| 492 // If we already tried a direct connection, then just give up. | 472 // If we already tried a direct connection, then just give up. |
| 493 if (was_direct) | 473 if (was_direct) |
| 494 return ERR_FAILED; | 474 return ERR_FAILED; |
| 495 | 475 |
| 496 // Try going direct. | 476 // Try going direct. |
| 497 result->UseDirect(); | 477 result->UseDirect(); |
| 498 return OK; | 478 return OK; |
| 499 } | 479 } |
| 500 | 480 |
| 501 // There are four states of the request we need to handle: | |
| 502 // (1) Not started (just sitting in the queue). | |
| 503 // (2) Executing PacRequest::DoQuery in the PAC thread. | |
| 504 // (3) Waiting for PacRequest::QueryComplete to be run on the origin thread. | |
| 505 // (4) Waiting for PacRequest::DoCallback to be run on the origin thread. | |
| 506 void ProxyService::CancelPacRequest(PacRequest* req) { | 481 void ProxyService::CancelPacRequest(PacRequest* req) { |
| 507 DCHECK(req); | 482 DCHECK(req); |
| 483 req->Cancel(); |
| 484 RemovePendingRequest(req); |
| 485 } |
| 508 | 486 |
| 509 bool is_active_request = req->is_started_ && !pending_requests_.empty() && | 487 bool ProxyService::ContainsPendingRequest(PacRequest* req) { |
| 510 pending_requests_.front().get() == req; | 488 PendingRequests::iterator it = std::find( |
| 489 pending_requests_.begin(), pending_requests_.end(), req); |
| 490 return pending_requests_.end() != it; |
| 491 } |
| 511 | 492 |
| 512 req->Cancel(); | 493 void ProxyService::RemovePendingRequest(PacRequest* req) { |
| 513 | 494 DCHECK(ContainsPendingRequest(req)); |
| 514 if (is_active_request) { | 495 PendingRequests::iterator it = std::find( |
| 515 RemoveFrontOfRequestQueue(req); | |
| 516 return; | |
| 517 } | |
| 518 | |
| 519 // Otherwise just delete the request from the queue. | |
| 520 PendingRequestsQueue::iterator it = std::find( | |
| 521 pending_requests_.begin(), pending_requests_.end(), req); | 496 pending_requests_.begin(), pending_requests_.end(), req); |
| 522 if (it != pending_requests_.end()) { | 497 pending_requests_.erase(it); |
| 523 pending_requests_.erase(it); | |
| 524 } | |
| 525 } | 498 } |
| 526 | 499 |
| 527 void ProxyService::SetProxyScriptFetcher( | 500 void ProxyService::SetProxyScriptFetcher( |
| 528 ProxyScriptFetcher* proxy_script_fetcher) { | 501 ProxyScriptFetcher* proxy_script_fetcher) { |
| 529 proxy_script_fetcher_.reset(proxy_script_fetcher); | 502 proxy_script_fetcher_.reset(proxy_script_fetcher); |
| 530 } | 503 } |
| 531 | 504 |
| 532 void ProxyService::ResetConfigService( | 505 void ProxyService::ResetConfigService( |
| 533 ProxyConfigService* new_proxy_config_service) { | 506 ProxyConfigService* new_proxy_config_service) { |
| 534 config_service_.reset(new_proxy_config_service); | 507 config_service_.reset(new_proxy_config_service); |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 614 config_ = config; | 587 config_ = config; |
| 615 | 588 |
| 616 // Increment the ID to reflect that the config has changed. | 589 // Increment the ID to reflect that the config has changed. |
| 617 config_.set_id(next_config_id_++); | 590 config_.set_id(next_config_id_++); |
| 618 | 591 |
| 619 LOG(INFO) << "New proxy configuration was loaded:\n" << config_; | 592 LOG(INFO) << "New proxy configuration was loaded:\n" << config_; |
| 620 | 593 |
| 621 // Reset state associated with latest config. | 594 // Reset state associated with latest config. |
| 622 config_is_bad_ = false; | 595 config_is_bad_ = false; |
| 623 proxy_retry_info_.clear(); | 596 proxy_retry_info_.clear(); |
| 597 |
| 598 // Tell the resolver to use the new PAC URL (for resolver's that fetch the |
| 599 // PAC script internally). |
| 600 // TODO(eroman): this isn't quite right. See http://crbug.com/9985 |
| 601 if ((config_.pac_url.is_valid() || config_.auto_detect) && |
| 602 !resolver_->expects_pac_bytes()) { |
| 603 const GURL pac_url = config_.auto_detect ? GURL() : config_.pac_url; |
| 604 resolver_->SetPacScriptByUrl(pac_url); |
| 605 } |
| 624 } | 606 } |
| 625 | 607 |
| 626 void ProxyService::UpdateConfigIfOld() { | 608 void ProxyService::UpdateConfigIfOld() { |
| 627 // The overhead of calling ProxyConfigService::GetProxyConfig is very low. | 609 // The overhead of calling ProxyConfigService::GetProxyConfig is very low. |
| 628 const TimeDelta kProxyConfigMaxAge = TimeDelta::FromSeconds(5); | 610 const TimeDelta kProxyConfigMaxAge = TimeDelta::FromSeconds(5); |
| 629 | 611 |
| 630 // Periodically check for a new config. | 612 // Periodically check for a new config. |
| 631 if (!config_has_been_initialized() || | 613 if (!config_has_been_initialized() || |
| 632 (TimeTicks::Now() - config_last_update_time_) > kProxyConfigMaxAge) | 614 (TimeTicks::Now() - config_last_update_time_) > kProxyConfigMaxAge) |
| 633 UpdateConfig(); | 615 UpdateConfig(); |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 761 OnCompletion(result_); | 743 OnCompletion(result_); |
| 762 } | 744 } |
| 763 } | 745 } |
| 764 | 746 |
| 765 void SyncProxyServiceHelper::OnCompletion(int rv) { | 747 void SyncProxyServiceHelper::OnCompletion(int rv) { |
| 766 result_ = rv; | 748 result_ = rv; |
| 767 event_.Signal(); | 749 event_.Signal(); |
| 768 } | 750 } |
| 769 | 751 |
| 770 } // namespace net | 752 } // namespace net |
| OLD | NEW |