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 |