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 "base/compiler_specific.h" | 5 #include "base/compiler_specific.h" |
6 #include "googleurl/src/gurl.h" | 6 #include "googleurl/src/gurl.h" |
7 #include "net/base/net_errors.h" | 7 #include "net/base/net_errors.h" |
8 #include "net/proxy/proxy_config_service.h" | 8 #include "net/proxy/proxy_config_service.h" |
9 #include "net/proxy/proxy_resolver.h" | 9 #include "net/proxy/proxy_resolver.h" |
10 #include "net/proxy/proxy_script_fetcher.h" | 10 #include "net/proxy/proxy_script_fetcher.h" |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
51 net::ProxyInfo info; | 51 net::ProxyInfo info; |
52 | 52 |
53 // info is only returned if query_url in GetProxyForURL matches this: | 53 // info is only returned if query_url in GetProxyForURL matches this: |
54 std::string info_predicate_query_host; | 54 std::string info_predicate_query_host; |
55 | 55 |
56 // If true, then GetProxyForURL will fail, which simulates failure to | 56 // If true, then GetProxyForURL will fail, which simulates failure to |
57 // download or execute the PAC file. | 57 // download or execute the PAC file. |
58 bool fail_get_proxy_for_url; | 58 bool fail_get_proxy_for_url; |
59 }; | 59 }; |
60 | 60 |
61 class SyncProxyService { | |
62 public: | |
63 SyncProxyService(net::ProxyConfigService* config_service, | |
64 net::ProxyResolver* resolver) | |
65 : io_thread_("IO_Thread"), | |
66 service_(config_service, resolver) { | |
67 base::Thread::Options options; | |
68 options.message_loop_type = MessageLoop::TYPE_IO; | |
69 io_thread_.StartWithOptions(options); | |
70 sync_proxy_service_ = new net::SyncProxyServiceHelper( | |
71 io_thread_.message_loop(), &service_); | |
72 } | |
73 | |
74 int ResolveProxy(const GURL& url, net::ProxyInfo* proxy_info) { | |
75 return sync_proxy_service_->ResolveProxy(url, proxy_info); | |
76 } | |
77 | |
78 int ReconsiderProxyAfterError(const GURL& url, net::ProxyInfo* proxy_info) { | |
79 return sync_proxy_service_->ReconsiderProxyAfterError(url, proxy_info); | |
80 } | |
81 | |
82 private: | |
83 base::Thread io_thread_; | |
84 net::ProxyService service_; | |
85 scoped_refptr<net::SyncProxyServiceHelper> sync_proxy_service_; | |
86 }; | |
87 | |
88 // ResultFuture is a handle to get at the result from | 61 // ResultFuture is a handle to get at the result from |
89 // ProxyService::ResolveProxyForURL() that ran on another thread. | 62 // ProxyService::ResolveProxyForURL() that ran on another thread. |
90 class ResultFuture : public base::RefCountedThreadSafe<ResultFuture> { | 63 class ResultFuture : public base::RefCountedThreadSafe<ResultFuture> { |
91 public: | 64 public: |
92 // |service| is the ProxyService to issue requests on, and |io_message_loop| | 65 // |service| is the ProxyService to issue requests on, and |io_message_loop| |
93 // is the message loop where ProxyService lives. | 66 // is the message loop where ProxyService lives. |
94 ResultFuture(MessageLoop* io_message_loop, | 67 ResultFuture(MessageLoop* io_message_loop, |
95 net::ProxyService* service) | 68 net::ProxyService* service) |
96 : io_message_loop_(io_message_loop), | 69 : io_message_loop_(io_message_loop), |
97 service_(service), | 70 service_(service), |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
136 // Wait until the ProxyService completes this request. | 109 // Wait until the ProxyService completes this request. |
137 void WaitUntilCompleted() { | 110 void WaitUntilCompleted() { |
138 DCHECK(MessageLoop::current() != io_message_loop_); | 111 DCHECK(MessageLoop::current() != io_message_loop_); |
139 completion_.Wait(); | 112 completion_.Wait(); |
140 DCHECK(did_complete_); | 113 DCHECK(did_complete_); |
141 } | 114 } |
142 | 115 |
143 private: | 116 private: |
144 friend class ProxyServiceWithFutures; | 117 friend class ProxyServiceWithFutures; |
145 | 118 |
146 // Start the request. Return once ProxyService::GetProxyForURL() returns. | 119 typedef int (net::ProxyService::*RequestMethod)(const GURL&, net::ProxyInfo*, |
| 120 net::CompletionCallback*, net::ProxyService::PacRequest**); |
| 121 |
147 void StartResolve(const GURL& url) { | 122 void StartResolve(const GURL& url) { |
| 123 StartRequest(url, &net::ProxyService::ResolveProxy); |
| 124 } |
| 125 |
| 126 // |proxy_info| is the *previous* result (that we are reconsidering). |
| 127 void StartReconsider(const GURL& url, const net::ProxyInfo& proxy_info) { |
| 128 proxy_info_ = proxy_info; |
| 129 StartRequest(url, &net::ProxyService::ReconsiderProxyAfterError); |
| 130 } |
| 131 |
| 132 // Start the request. Return once ProxyService::GetProxyForURL() or |
| 133 // ProxyService::ReconsiderProxyAfterError() returns. |
| 134 void StartRequest(const GURL& url, RequestMethod method) { |
148 DCHECK(MessageLoop::current() != io_message_loop_); | 135 DCHECK(MessageLoop::current() != io_message_loop_); |
149 io_message_loop_->PostTask(FROM_HERE, NewRunnableMethod( | 136 io_message_loop_->PostTask(FROM_HERE, NewRunnableMethod( |
150 this, &ResultFuture::DoStartResolve, url)); | 137 this, &ResultFuture::DoStartRequest, url, method)); |
151 started_.Wait(); | 138 started_.Wait(); |
152 } | 139 } |
153 | 140 |
154 // Called on |io_message_loop_|. | 141 // Called on |io_message_loop_|. |
155 void DoStartResolve(const GURL& url) { | 142 void DoStartRequest(const GURL& url, RequestMethod method) { |
156 DCHECK(MessageLoop::current() == io_message_loop_); | 143 DCHECK(MessageLoop::current() == io_message_loop_); |
157 int rv = service_->ResolveProxy(url, &proxy_info_, &callback_, &request_); | 144 int rv = (service_->*method)(url, &proxy_info_, &callback_, &request_); |
158 if (rv != net::ERR_IO_PENDING) { | 145 if (rv != net::ERR_IO_PENDING) { |
159 // Completed synchronously. | 146 // Completed synchronously. |
160 OnCompletion(rv); | 147 OnCompletion(rv); |
161 } | 148 } |
162 started_.Signal(); | 149 started_.Signal(); |
163 } | 150 } |
164 | 151 |
165 // Called on |io_message_loop_|. | 152 // Called on |io_message_loop_|. |
166 void DoCancel() { | 153 void DoCancel() { |
167 DCHECK(MessageLoop::current() == io_message_loop_); | 154 DCHECK(MessageLoop::current() == io_message_loop_); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
199 int result_code_; | 186 int result_code_; |
200 net::ProxyInfo proxy_info_; | 187 net::ProxyInfo proxy_info_; |
201 }; | 188 }; |
202 | 189 |
203 // Wraps a ProxyService running on its own IO thread. | 190 // Wraps a ProxyService running on its own IO thread. |
204 class ProxyServiceWithFutures { | 191 class ProxyServiceWithFutures { |
205 public: | 192 public: |
206 ProxyServiceWithFutures(net::ProxyConfigService* config_service, | 193 ProxyServiceWithFutures(net::ProxyConfigService* config_service, |
207 net::ProxyResolver* resolver) | 194 net::ProxyResolver* resolver) |
208 : io_thread_("IO_Thread"), | 195 : io_thread_("IO_Thread"), |
209 service_(config_service, resolver) { | 196 io_thread_state_(new IOThreadState) { |
210 base::Thread::Options options; | 197 base::Thread::Options options; |
211 options.message_loop_type = MessageLoop::TYPE_IO; | 198 options.message_loop_type = MessageLoop::TYPE_IO; |
212 io_thread_.StartWithOptions(options); | 199 io_thread_.StartWithOptions(options); |
| 200 |
| 201 // Initialize state that lives on |io_thread_|. |
| 202 io_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod( |
| 203 io_thread_state_.get(), &IOThreadState::DoInit, |
| 204 config_service, resolver)); |
| 205 io_thread_state_->event.Wait(); |
| 206 } |
| 207 |
| 208 ~ProxyServiceWithFutures() { |
| 209 // Destroy state that lives on |io_thread_|. |
| 210 io_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod( |
| 211 io_thread_state_.get(), &IOThreadState::DoDestroy)); |
| 212 io_thread_state_->event.Wait(); |
213 } | 213 } |
214 | 214 |
215 // Start the request on |io_thread_|, and return a handle that can be | 215 // Start the request on |io_thread_|, and return a handle that can be |
216 // used to access the results. The caller is responsible for freeing | 216 // used to access the results. The caller is responsible for freeing |
217 // the ResultFuture. | 217 // the ResultFuture. |
218 void ResolveProxy(scoped_refptr<ResultFuture>* result, const GURL& url) { | 218 void ResolveProxy(scoped_refptr<ResultFuture>* result, const GURL& url) { |
219 (*result) = new ResultFuture(io_thread_.message_loop(), &service_); | 219 *result = new ResultFuture(io_thread_.message_loop(), |
| 220 io_thread_state_->service); |
220 (*result)->StartResolve(url); | 221 (*result)->StartResolve(url); |
221 } | 222 } |
222 | 223 |
| 224 // Same as above, but for "ReconsiderProxyAfterError()". |
| 225 void ReconsiderProxyAfterError(scoped_refptr<ResultFuture>* result, |
| 226 const GURL& url, |
| 227 const net::ProxyInfo& proxy_info) { |
| 228 *result = new ResultFuture(io_thread_.message_loop(), |
| 229 io_thread_state_->service); |
| 230 (*result)->StartReconsider(url, proxy_info); |
| 231 } |
| 232 |
223 void SetProxyScriptFetcher(net::ProxyScriptFetcher* proxy_script_fetcher) { | 233 void SetProxyScriptFetcher(net::ProxyScriptFetcher* proxy_script_fetcher) { |
224 service_.SetProxyScriptFetcher(proxy_script_fetcher); | 234 io_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod( |
| 235 io_thread_state_.get(), &IOThreadState::DoSetProxyScriptFetcher, |
| 236 proxy_script_fetcher)); |
| 237 io_thread_state_->event.Wait(); |
225 } | 238 } |
226 | 239 |
227 private: | 240 private: |
| 241 // Class that encapsulates the state living on IO thread. It needs to be |
| 242 // ref-counted for posting tasks. |
| 243 class IOThreadState : public base::RefCounted<IOThreadState> { |
| 244 public: |
| 245 IOThreadState() : event(false, false), service(NULL) {} |
| 246 |
| 247 void DoInit(net::ProxyConfigService* config_service, |
| 248 net::ProxyResolver* resolver) { |
| 249 service = new net::ProxyService(config_service, resolver); |
| 250 event.Signal(); |
| 251 } |
| 252 |
| 253 void DoDestroy() { |
| 254 delete service; |
| 255 service = NULL; |
| 256 event.Signal(); |
| 257 } |
| 258 |
| 259 void DoSetProxyScriptFetcher( |
| 260 net::ProxyScriptFetcher* proxy_script_fetcher) { |
| 261 service->SetProxyScriptFetcher(proxy_script_fetcher); |
| 262 event.Signal(); |
| 263 } |
| 264 |
| 265 base::WaitableEvent event; |
| 266 net::ProxyService* service; |
| 267 }; |
| 268 |
228 base::Thread io_thread_; | 269 base::Thread io_thread_; |
229 net::ProxyService service_; | 270 scoped_refptr<IOThreadState> io_thread_state_; // Lives on |io_thread_|. |
| 271 }; |
| 272 |
| 273 // Wrapper around ProxyServiceWithFutures to do one request at a time. |
| 274 class SyncProxyService { |
| 275 public: |
| 276 SyncProxyService(net::ProxyConfigService* config_service, |
| 277 net::ProxyResolver* resolver) |
| 278 : service_(config_service, resolver) { |
| 279 } |
| 280 |
| 281 int ResolveProxy(const GURL& url, net::ProxyInfo* proxy_info) { |
| 282 scoped_refptr<ResultFuture> result; |
| 283 service_.ResolveProxy(&result, url); |
| 284 *proxy_info = result->GetProxyInfo(); |
| 285 return result->GetResultCode(); |
| 286 } |
| 287 |
| 288 int ReconsiderProxyAfterError(const GURL& url, net::ProxyInfo* proxy_info) { |
| 289 scoped_refptr<ResultFuture> result; |
| 290 service_.ReconsiderProxyAfterError(&result, url, *proxy_info); |
| 291 *proxy_info = result->GetProxyInfo(); |
| 292 return result->GetResultCode(); |
| 293 } |
| 294 |
| 295 private: |
| 296 ProxyServiceWithFutures service_; |
230 }; | 297 }; |
231 | 298 |
232 // A ProxyResolver which can be set to block upon reaching GetProxyForURL. | 299 // A ProxyResolver which can be set to block upon reaching GetProxyForURL. |
233 class BlockableProxyResolver : public net::ProxyResolver { | 300 class BlockableProxyResolver : public net::ProxyResolver { |
234 public: | 301 public: |
235 BlockableProxyResolver() : net::ProxyResolver(true), | 302 BlockableProxyResolver() : net::ProxyResolver(true), |
236 should_block_(false), | 303 should_block_(false), |
237 unblocked_(true, true), | 304 unblocked_(true, true), |
238 blocked_(true, false) { | 305 blocked_(true, false) { |
239 } | 306 } |
(...skipping 676 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
916 result3->WaitUntilCompleted(); | 983 result3->WaitUntilCompleted(); |
917 | 984 |
918 EXPECT_FALSE(result1->IsCompleted()); // Cancelled. | 985 EXPECT_FALSE(result1->IsCompleted()); // Cancelled. |
919 EXPECT_FALSE(result2->IsCompleted()); // Cancelled. | 986 EXPECT_FALSE(result2->IsCompleted()); // Cancelled. |
920 | 987 |
921 EXPECT_TRUE(result3->IsCompleted()); | 988 EXPECT_TRUE(result3->IsCompleted()); |
922 EXPECT_EQ(net::OK, result3->GetResultCode()); | 989 EXPECT_EQ(net::OK, result3->GetResultCode()); |
923 EXPECT_EQ("pac-v1.request3:80", | 990 EXPECT_EQ("pac-v1.request3:80", |
924 result3->GetProxyInfo().proxy_server().ToURI()); | 991 result3->GetProxyInfo().proxy_server().ToURI()); |
925 } | 992 } |
OLD | NEW |