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

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

Issue 21328: Add support to ProxyService for downloading a PAC script on behalf of the Pro... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Add missing files (for constructor boolean flag fall-out) 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
« no previous file with comments | « net/proxy/proxy_service.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 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 "googleurl/src/gurl.h" 6 #include "googleurl/src/gurl.h"
6 #include "net/base/net_errors.h" 7 #include "net/base/net_errors.h"
7 #include "net/proxy/proxy_service.h" 8 #include "net/proxy/proxy_service.h"
8 #include "testing/gtest/include/gtest/gtest.h" 9 #include "testing/gtest/include/gtest/gtest.h"
9 10
10 namespace { 11 namespace {
11 12
12 class MockProxyConfigService: public net::ProxyConfigService { 13 class MockProxyConfigService: public net::ProxyConfigService {
13 public: 14 public:
14 MockProxyConfigService() {} // Direct connect. 15 MockProxyConfigService() {} // Direct connect.
15 explicit MockProxyConfigService(const net::ProxyConfig& pc) : config(pc) {} 16 explicit MockProxyConfigService(const net::ProxyConfig& pc) : config(pc) {}
16 explicit MockProxyConfigService(const std::string& pac_url) { 17 explicit MockProxyConfigService(const std::string& pac_url) {
17 config.pac_url = GURL(pac_url); 18 config.pac_url = GURL(pac_url);
18 } 19 }
19 20
20 virtual int GetProxyConfig(net::ProxyConfig* results) { 21 virtual int GetProxyConfig(net::ProxyConfig* results) {
21 *results = config; 22 *results = config;
22 return net::OK; 23 return net::OK;
23 } 24 }
24 25
25 net::ProxyConfig config; 26 net::ProxyConfig config;
26 }; 27 };
27 28
28 class MockProxyResolver : public net::ProxyResolver { 29 class MockProxyResolver : public net::ProxyResolver {
29 public: 30 public:
30 MockProxyResolver() : fail_get_proxy_for_url(false) { 31 MockProxyResolver() : net::ProxyResolver(true),
32 fail_get_proxy_for_url(false) {
31 } 33 }
32 34
33 virtual int GetProxyForURL(const GURL& query_url, 35 virtual int GetProxyForURL(const GURL& query_url,
34 const GURL& pac_url, 36 const GURL& pac_url,
35 net::ProxyInfo* results) { 37 net::ProxyInfo* results) {
36 if (fail_get_proxy_for_url) 38 if (fail_get_proxy_for_url)
37 return net::ERR_FAILED; 39 return net::ERR_FAILED;
38 if (GURL(query_url).host() == info_predicate_query_host) { 40 if (GURL(query_url).host() == info_predicate_query_host) {
39 results->Use(info); 41 results->Use(info);
40 } else { 42 } else {
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
73 int ReconsiderProxyAfterError(const GURL& url, net::ProxyInfo* proxy_info) { 75 int ReconsiderProxyAfterError(const GURL& url, net::ProxyInfo* proxy_info) {
74 return sync_proxy_service_->ReconsiderProxyAfterError(url, proxy_info); 76 return sync_proxy_service_->ReconsiderProxyAfterError(url, proxy_info);
75 } 77 }
76 78
77 private: 79 private:
78 base::Thread io_thread_; 80 base::Thread io_thread_;
79 net::ProxyService service_; 81 net::ProxyService service_;
80 scoped_refptr<net::SyncProxyServiceHelper> sync_proxy_service_; 82 scoped_refptr<net::SyncProxyServiceHelper> sync_proxy_service_;
81 }; 83 };
82 84
85 // ResultFuture is a handle to get at the result from
86 // ProxyService::ResolveProxyForURL() that ran on another thread.
87 class ResultFuture : public base::RefCountedThreadSafe<ResultFuture> {
88 public:
89 // |service| is the ProxyService to issue requests on, and |io_message_loop|
90 // is the message loop where ProxyService lives.
91 ResultFuture(MessageLoop* io_message_loop,
92 net::ProxyService* service)
93 : io_message_loop_(io_message_loop),
94 service_(service),
95 request_(NULL),
96 ALLOW_THIS_IN_INITIALIZER_LIST(
97 callback_(this, &ResultFuture::OnCompletion)),
98 completion_(true, false),
99 cancelled_(false, false),
100 started_(false, false),
101 did_complete_(false) {
102 }
103
104 // Block until the request has completed, then return the result.
105 int GetResultCode() {
106 DCHECK(MessageLoop::current() != io_message_loop_);
107 WaitUntilCompleted();
108 return result_code_;
109 }
110
111 // Block until the request has completed, then return the result.
112 const net::ProxyInfo& GetProxyInfo() {
113 DCHECK(MessageLoop::current() != io_message_loop_);
114 WaitUntilCompleted();
115 return proxy_info_;
116 }
117
118 // Cancel this request (wait until the cancel has been issued before
119 // returning).
120 void Cancel() {
121 DCHECK(MessageLoop::current() != io_message_loop_);
122 io_message_loop_->PostTask(FROM_HERE, NewRunnableMethod(
123 this, &ResultFuture::DoCancel));
124 cancelled_.Wait();
125 }
126
127 // Return true if the request has already completed.
128 bool IsCompleted() {
129 DCHECK(MessageLoop::current() != io_message_loop_);
130 return did_complete_;
131 }
132
133 // Wait until the ProxyService completes this request.
134 void WaitUntilCompleted() {
135 DCHECK(MessageLoop::current() != io_message_loop_);
136 completion_.Wait();
137 DCHECK(did_complete_);
138 }
139
140 private:
141 friend class ProxyServiceWithFutures;
142
143 // Start the request. Return once ProxyService::GetProxyForURL() returns.
144 void StartResolve(const GURL& url) {
145 DCHECK(MessageLoop::current() != io_message_loop_);
146 io_message_loop_->PostTask(FROM_HERE, NewRunnableMethod(
147 this, &ResultFuture::DoStartResolve, url));
148 started_.Wait();
149 }
150
151 // Called on |io_message_loop_|.
152 void DoStartResolve(const GURL& url) {
153 DCHECK(MessageLoop::current() == io_message_loop_);
154 int rv = service_->ResolveProxy(url, &proxy_info_, &callback_, &request_);
155 if (rv != net::ERR_IO_PENDING) {
156 // Completed synchronously.
157 OnCompletion(rv);
158 }
159 started_.Signal();
160 }
161
162 // Called on |io_message_loop_|.
163 void DoCancel() {
164 DCHECK(MessageLoop::current() == io_message_loop_);
165 if (!did_complete_)
166 service_->CancelPacRequest(request_);
167 cancelled_.Signal();
168 }
169
170 // Called on |io_message_loop_|.
171 void OnCompletion(int result) {
172 DCHECK(MessageLoop::current() == io_message_loop_);
173 DCHECK(!did_complete_);
174 did_complete_ = true;
175 result_code_ = result;
176 request_ = NULL;
177 completion_.Signal();
178 }
179
180 // The message loop where the ProxyService lives.
181 MessageLoop* io_message_loop_;
182
183 // The proxy service that started this request.
184 net::ProxyService* service_;
185
186 // The in-progress request.
187 net::ProxyService::PacRequest* request_;
188
189 net::CompletionCallbackImpl<ResultFuture> callback_;
190 base::WaitableEvent completion_;
191 base::WaitableEvent cancelled_;
192 base::WaitableEvent started_;
193 bool did_complete_;
194
195 // Results from the request.
196 int result_code_;
197 net::ProxyInfo proxy_info_;
198 };
199
200 // Wraps a ProxyService running on its own IO thread.
201 class ProxyServiceWithFutures {
202 public:
203 ProxyServiceWithFutures(net::ProxyConfigService* config_service,
204 net::ProxyResolver* resolver)
205 : io_thread_("IO_Thread"),
206 service_(config_service, resolver) {
207 base::Thread::Options options;
208 options.message_loop_type = MessageLoop::TYPE_IO;
209 io_thread_.StartWithOptions(options);
210 }
211
212 // Start the request on |io_thread_|, and return a handle that can be
213 // used to access the results. The caller is responsible for freeing
214 // the ResultFuture.
215 void ResolveProxy(scoped_refptr<ResultFuture>* result, const GURL& url) {
216 (*result) = new ResultFuture(io_thread_.message_loop(), &service_);
217 (*result)->StartResolve(url);
218 }
219
220 void SetProxyScriptFetcher(net::ProxyScriptFetcher* proxy_script_fetcher) {
221 service_.SetProxyScriptFetcher(proxy_script_fetcher);
222 }
223
224 private:
225 base::Thread io_thread_;
226 net::ProxyService service_;
227 };
228
229 // A ProxyResolver which can be set to block upon reaching GetProxyForURL.
230 class BlockableProxyResolver : public net::ProxyResolver {
231 public:
232 BlockableProxyResolver() : net::ProxyResolver(true),
233 should_block_(false),
234 unblocked_(true, true),
235 blocked_(true, false) {
236 }
237
238 void Block() {
239 should_block_ = true;
240 unblocked_.Reset();
241 }
242
243 void Unblock() {
244 should_block_ = false;
245 blocked_.Reset();
246 unblocked_.Signal();
247 }
248
249 void WaitUntilBlocked() {
250 blocked_.Wait();
251 }
252
253 // net::ProxyResolver implementation:
254 virtual int GetProxyForURL(const GURL& query_url,
255 const GURL& pac_url,
256 net::ProxyInfo* results) {
257 if (should_block_) {
258 blocked_.Signal();
259 unblocked_.Wait();
260 }
261
262 results->UseNamedProxy(query_url.host());
263 return net::OK;
264 }
265
266 private:
267 bool should_block_;
268 base::WaitableEvent unblocked_;
269 base::WaitableEvent blocked_;
270 };
271
272 // A mock ProxyResolverWithoutFetch which concatenates the query's host with
273 // the last download PAC contents. This way the result describes what the last
274 // downloaded PAC script's contents were, in addition to the query url itself.
275 class MockProxyResolverWithoutFetch : public net::ProxyResolver {
276 public:
277 MockProxyResolverWithoutFetch() : net::ProxyResolver(false),
278 last_pac_contents_("NONE") {}
279
280 // net::ProxyResolver implementation:
281 virtual int GetProxyForURL(const GURL& query_url,
282 const GURL& pac_url,
283 net::ProxyInfo* results) {
284 results->UseNamedProxy(last_pac_contents_ + "." + query_url.host());
285 return net::OK;
286 }
287
288 virtual void SetPacScript(const std::string& bytes) {
289 last_pac_contents_ = bytes;
290 }
291
292 private:
293 std::string last_pac_contents_;
294 };
295
83 } // namespace 296 } // namespace
84 297
298 // A mock ProxyScriptFetcher. No result will be returned to the fetch client
299 // until we call NotifyFetchCompletion() to set the results.
300 class MockProxyScriptFetcher : public net::ProxyScriptFetcher {
301 public:
302 MockProxyScriptFetcher() : pending_request_loop_(NULL),
303 pending_request_callback_(NULL), pending_request_bytes_(NULL) {}
304
305 // net::ProxyScriptFetcher implementation.
306 virtual void Fetch(const GURL& url, std::string* bytes,
307 net::CompletionCallback* callback) {
308 DCHECK(!HasPendingRequest());
309
310 // Save the caller's information, and have them wait.
311 pending_request_loop_ = MessageLoop::current();
312 pending_request_url_ = url;
313 pending_request_callback_ = callback;
314 pending_request_bytes_ = bytes;
315 }
316
317 void NotifyFetchCompletion(int result, const std::string& bytes) {
318 DCHECK(HasPendingRequest());
319 pending_request_loop_->PostTask(FROM_HERE, NewRunnableMethod(
320 this, &MockProxyScriptFetcher::DoNotifyFetchCompletion, result, bytes));
321 }
322
323 virtual void Cancel() {}
324
325 private:
326 // Runs on |pending_request_loop_|.
327 void DoNotifyFetchCompletion(int result, const std::string& bytes) {
328 DCHECK(HasPendingRequest());
329 *pending_request_bytes_ = bytes;
330 pending_request_callback_->Run(result);
331 }
332
333 bool HasPendingRequest() const {
334 return pending_request_loop_ != NULL;
335 }
336
337 MessageLoop* pending_request_loop_;
338 GURL pending_request_url_;
339 net::CompletionCallback* pending_request_callback_;
340 std::string* pending_request_bytes_;
341 };
342
343 // Template specialization so MockProxyScriptFetcher does not have to be refcoun ted.
344 template<>
345 void RunnableMethodTraits<MockProxyScriptFetcher>::RetainCallee(
346 MockProxyScriptFetcher* remover) {}
347 template<>
348 void RunnableMethodTraits<MockProxyScriptFetcher>::ReleaseCallee(
349 MockProxyScriptFetcher* remover) {}
350
85 // Test parsing from a PAC string. 351 // Test parsing from a PAC string.
86 TEST(ProxyListTest, SetFromPacString) { 352 TEST(ProxyListTest, SetFromPacString) {
87 const struct { 353 const struct {
88 const char* pac_input; 354 const char* pac_input;
89 const char* pac_output; 355 const char* pac_output;
90 } tests[] = { 356 } tests[] = {
91 // Valid inputs: 357 // Valid inputs:
92 { "PROXY foopy:10", 358 { "PROXY foopy:10",
93 "PROXY foopy:10", 359 "PROXY foopy:10",
94 }, 360 },
(...skipping 317 matching lines...) Expand 10 before | Expand all | Expand 10 after
412 EXPECT_EQ("foopy1:8080", info3.proxy_server().ToURI()); 678 EXPECT_EQ("foopy1:8080", info3.proxy_server().ToURI());
413 } 679 }
414 680
415 TEST(ProxyServiceTest, ProxyBypassList) { 681 TEST(ProxyServiceTest, ProxyBypassList) {
416 // Test what happens when a proxy bypass list is specified. 682 // Test what happens when a proxy bypass list is specified.
417 683
418 net::ProxyConfig config; 684 net::ProxyConfig config;
419 config.proxy_rules = "foopy1:8080;foopy2:9090"; 685 config.proxy_rules = "foopy1:8080;foopy2:9090";
420 config.auto_detect = false; 686 config.auto_detect = false;
421 config.proxy_bypass_local_names = true; 687 config.proxy_bypass_local_names = true;
422 688
423 SyncProxyService service(new MockProxyConfigService(config), 689 SyncProxyService service(new MockProxyConfigService(config),
424 new MockProxyResolver()); 690 new MockProxyResolver());
425 GURL url("http://www.google.com/"); 691 GURL url("http://www.google.com/");
426 // Get the proxy information. 692 // Get the proxy information.
427 net::ProxyInfo info; 693 net::ProxyInfo info;
428 int rv = service.ResolveProxy(url, &info); 694 int rv = service.ResolveProxy(url, &info);
429 EXPECT_EQ(rv, net::OK); 695 EXPECT_EQ(rv, net::OK);
430 EXPECT_FALSE(info.is_direct()); 696 EXPECT_FALSE(info.is_direct());
431 697
432 SyncProxyService service1(new MockProxyConfigService(config), 698 SyncProxyService service1(new MockProxyConfigService(config),
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
530 SyncProxyService service4(new MockProxyConfigService(config), 796 SyncProxyService service4(new MockProxyConfigService(config),
531 new MockProxyResolver); 797 new MockProxyResolver);
532 GURL test_url4("www.microsoft.com"); 798 GURL test_url4("www.microsoft.com");
533 net::ProxyInfo info4; 799 net::ProxyInfo info4;
534 rv = service4.ResolveProxy(test_url4, &info4); 800 rv = service4.ResolveProxy(test_url4, &info4);
535 EXPECT_EQ(rv, net::OK); 801 EXPECT_EQ(rv, net::OK);
536 EXPECT_FALSE(info4.is_direct()); 802 EXPECT_FALSE(info4.is_direct());
537 EXPECT_EQ("foopy1:8080", info4.proxy_server().ToURI()); 803 EXPECT_EQ("foopy1:8080", info4.proxy_server().ToURI());
538 } 804 }
539 805
806 // Test cancellation of a queued request.
807 TEST(ProxyServiceTest, CancelQueuedRequest) {
808 MockProxyConfigService* config_service =
809 new MockProxyConfigService("http://foopy/proxy.pac");
810
811 BlockableProxyResolver* resolver = new BlockableProxyResolver;
812
813 ProxyServiceWithFutures service(config_service, resolver);
814
815 // Cause requests to pile up, by having them block in the PAC thread.
816 resolver->Block();
817
818 // Start 3 requests.
819 scoped_refptr<ResultFuture> result1;
820 service.ResolveProxy(&result1, GURL("http://request1"));
821
822 scoped_refptr<ResultFuture> result2;
823 service.ResolveProxy(&result2, GURL("http://request2"));
824
825 scoped_refptr<ResultFuture> result3;
826 service.ResolveProxy(&result3, GURL("http://request3"));
827
828 // Wait until the first request has become blocked in the PAC thread.
829 resolver->WaitUntilBlocked();
830
831 // Cancel the second request
832 result2->Cancel();
833
834 // Unblock the PAC thread.
835 resolver->Unblock();
836
837 // Wait for the final request to complete.
838 result3->WaitUntilCompleted();
839
840 // Verify that requests ran as expected.
841
842 EXPECT_TRUE(result1->IsCompleted());
843 EXPECT_EQ(net::OK, result1->GetResultCode());
844 EXPECT_EQ("request1:80", result1->GetProxyInfo().proxy_server().ToURI());
845
846 EXPECT_FALSE(result2->IsCompleted()); // Cancelled.
847
848 EXPECT_TRUE(result3->IsCompleted());
849 EXPECT_EQ(net::OK, result3->GetResultCode());
850 EXPECT_EQ("request3:80", result3->GetProxyInfo().proxy_server().ToURI());
851 }
852
853 // Test cancellation of an in-progress request.
854 TEST(ProxyServiceTest, CancelInprogressRequest) {
855 MockProxyConfigService* config_service =
856 new MockProxyConfigService("http://foopy/proxy.pac");
857
858 BlockableProxyResolver* resolver = new BlockableProxyResolver;
859
860 ProxyServiceWithFutures service(config_service, resolver);
861
862 // Cause requests to pile up, by having them block in the PAC thread.
863 resolver->Block();
864
865 // Start 3 requests.
866 scoped_refptr<ResultFuture> result1;
867 service.ResolveProxy(&result1, GURL("http://request1"));
868
869 scoped_refptr<ResultFuture> result2;
870 service.ResolveProxy(&result2, GURL("http://request2"));
871
872 scoped_refptr<ResultFuture> result3;
873 service.ResolveProxy(&result3, GURL("http://request3"));
874
875 // Wait until the first request has become blocked in the PAC thread.
876 resolver->WaitUntilBlocked();
877
878 // Cancel the first request
879 result1->Cancel();
880
881 // Unblock the PAC thread.
882 resolver->Unblock();
883
884 // Wait for the final request to complete.
885 result3->WaitUntilCompleted();
886
887 // Verify that requests ran as expected.
888
889 EXPECT_FALSE(result1->IsCompleted()); // Cancelled.
890
891 EXPECT_TRUE(result2->IsCompleted());
892 EXPECT_EQ(net::OK, result2->GetResultCode());
893 EXPECT_EQ("request2:80", result2->GetProxyInfo().proxy_server().ToURI());
894
895 EXPECT_TRUE(result3->IsCompleted());
896 EXPECT_EQ(net::OK, result3->GetResultCode());
897 EXPECT_EQ("request3:80", result3->GetProxyInfo().proxy_server().ToURI());
898 }
899
900 // Test the initial PAC download for ProxyResolverWithoutFetch.
901 TEST(ProxyServiceTest, InitialPACScriptDownload) {
902 MockProxyConfigService* config_service =
903 new MockProxyConfigService("http://foopy/proxy.pac");
904
905 MockProxyResolverWithoutFetch* resolver = new MockProxyResolverWithoutFetch;
906
907 ProxyServiceWithFutures service(config_service, resolver);
908
909 MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher;
910 service.SetProxyScriptFetcher(fetcher);
911
912 // Start 3 requests.
913 scoped_refptr<ResultFuture> result1;
914 service.ResolveProxy(&result1, GURL("http://request1"));
915
916 scoped_refptr<ResultFuture> result2;
917 service.ResolveProxy(&result2, GURL("http://request2"));
918
919 scoped_refptr<ResultFuture> result3;
920 service.ResolveProxy(&result3, GURL("http://request3"));
921
922 // At this point the ProxyService should be waiting for the
923 // ProxyScriptFetcher to invoke its completion callback, notifying it of
924 // PAC script download completion.
925 fetcher->NotifyFetchCompletion(net::OK, "pac-v1");
926
927 // Complete all the requests.
928 result3->WaitUntilCompleted();
929
930 EXPECT_TRUE(result1->IsCompleted());
931 EXPECT_EQ(net::OK, result1->GetResultCode());
932 EXPECT_EQ("pac-v1.request1:80",
933 result1->GetProxyInfo().proxy_server().ToURI());
934
935 EXPECT_TRUE(result2->IsCompleted());
936 EXPECT_EQ(net::OK, result2->GetResultCode());
937 EXPECT_EQ("pac-v1.request2:80",
938 result2->GetProxyInfo().proxy_server().ToURI());
939
940 EXPECT_TRUE(result3->IsCompleted());
941 EXPECT_EQ(net::OK, result3->GetResultCode());
942 EXPECT_EQ("pac-v1.request3:80",
943 result3->GetProxyInfo().proxy_server().ToURI());
944 }
945
946 // Test cancellation of a request, while the PAC script is being fetched.
947 TEST(ProxyServiceTest, CancelWhilePACFetching) {
948 MockProxyConfigService* config_service =
949 new MockProxyConfigService("http://foopy/proxy.pac");
950
951 MockProxyResolverWithoutFetch* resolver = new MockProxyResolverWithoutFetch;
952
953 ProxyServiceWithFutures service(config_service, resolver);
954
955 MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher;
956 service.SetProxyScriptFetcher(fetcher);
957
958 // Start 3 requests.
959 scoped_refptr<ResultFuture> result1;
960 service.ResolveProxy(&result1, GURL("http://request1"));
961
962 scoped_refptr<ResultFuture> result2;
963 service.ResolveProxy(&result2, GURL("http://request2"));
964
965 scoped_refptr<ResultFuture> result3;
966 service.ResolveProxy(&result3, GURL("http://request3"));
967
968 // Cancel the first 2 requests.
969 result1->Cancel();
970 result2->Cancel();
971
972 // At this point the ProxyService should be waiting for the
973 // ProxyScriptFetcher to invoke its completion callback, notifying it of
974 // PAC script download completion.
975 fetcher->NotifyFetchCompletion(net::OK, "pac-v1");
976
977 // Complete all the requests.
978 result3->WaitUntilCompleted();
979
980 EXPECT_FALSE(result1->IsCompleted()); // Cancelled.
981 EXPECT_FALSE(result2->IsCompleted()); // Cancelled.
982
983 EXPECT_TRUE(result3->IsCompleted());
984 EXPECT_EQ(net::OK, result3->GetResultCode());
985 EXPECT_EQ("pac-v1.request3:80",
986 result3->GetProxyInfo().proxy_server().ToURI());
987 }
988
OLDNEW
« no previous file with comments | « net/proxy/proxy_service.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698