| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 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 "chrome/browser/net/resolve_proxy_msg_helper.h" | 5 #include "chrome/browser/net/resolve_proxy_msg_helper.h" |
| 6 | 6 |
| 7 #include "base/waitable_event.h" | 7 #include "base/waitable_event.h" |
| 8 #include "net/base/net_errors.h" | 8 #include "net/base/net_errors.h" |
| 9 #include "net/proxy/mock_proxy_resolver.h" |
| 9 #include "net/proxy/proxy_config_service.h" | 10 #include "net/proxy/proxy_config_service.h" |
| 10 #include "net/proxy/proxy_resolver.h" | |
| 11 #include "net/proxy/single_threaded_proxy_resolver.h" | |
| 12 #include "testing/gtest/include/gtest/gtest.h" | 11 #include "testing/gtest/include/gtest/gtest.h" |
| 13 | 12 |
| 14 // This ProxyConfigService always returns "http://pac" as the PAC url to use. | 13 // This ProxyConfigService always returns "http://pac" as the PAC url to use. |
| 15 class MockProxyConfigService: public net::ProxyConfigService { | 14 class MockProxyConfigService : public net::ProxyConfigService { |
| 16 public: | 15 public: |
| 17 virtual int GetProxyConfig(net::ProxyConfig* results) { | 16 virtual int GetProxyConfig(net::ProxyConfig* results) { |
| 18 results->pac_url = GURL("http://pac"); | 17 results->pac_url = GURL("http://pac"); |
| 19 return net::OK; | 18 return net::OK; |
| 20 } | 19 } |
| 21 }; | 20 }; |
| 22 | 21 |
| 23 // This PAC resolver always returns the hostname of the query URL as the | 22 class MyDelegate : public ResolveProxyMsgHelper::Delegate { |
| 24 // proxy to use. The Block() method will make GetProxyForURL() hang until | |
| 25 // Unblock() is called. | |
| 26 class SyncMockProxyResolver : public net::ProxyResolver { | |
| 27 public: | 23 public: |
| 28 SyncMockProxyResolver() : ProxyResolver(false /*expects_pac_bytes*/), | 24 struct PendingResult { |
| 29 event_(false, false), | 25 PendingResult(IPC::Message* msg, |
| 30 is_blocked_(false) { | 26 int error_code, |
| 27 const std::string& proxy_list) |
| 28 : msg(msg), error_code(error_code), proxy_list(proxy_list) { |
| 29 } |
| 30 |
| 31 IPC::Message* msg; |
| 32 int error_code; |
| 33 std::string proxy_list; |
| 34 }; |
| 35 |
| 36 // ResolveProxyMsgHelper::Delegate implementation: |
| 37 virtual void OnResolveProxyCompleted(IPC::Message* reply_msg, |
| 38 int error_code, |
| 39 const std::string& proxy_list) { |
| 40 DCHECK(!pending_result_.get()); |
| 41 pending_result_.reset(new PendingResult(reply_msg, error_code, proxy_list)); |
| 31 } | 42 } |
| 32 | 43 |
| 33 virtual int GetProxyForURL(const GURL& query_url, | 44 const PendingResult* pending_result() const { return pending_result_.get(); } |
| 34 net::ProxyInfo* results, | |
| 35 net::CompletionCallback* callback, | |
| 36 RequestHandle* request) { | |
| 37 if (is_blocked_) | |
| 38 event_.Wait(); | |
| 39 results->UseNamedProxy(query_url.host()); | |
| 40 return net::OK; | |
| 41 } | |
| 42 | 45 |
| 43 virtual void CancelRequest(RequestHandle request) { | 46 void clear_pending_result() { |
| 44 NOTREACHED(); | 47 pending_result_.reset(); |
| 45 } | |
| 46 | |
| 47 virtual int SetPacScript(const GURL& /*pac_url*/, | |
| 48 const std::string& /*bytes*/, | |
| 49 net::CompletionCallback* /*callback*/) { | |
| 50 return net::OK; | |
| 51 } | |
| 52 | |
| 53 void Block() { | |
| 54 is_blocked_ = true; | |
| 55 event_.Reset(); | |
| 56 } | |
| 57 | |
| 58 void Unblock() { | |
| 59 is_blocked_ = false; | |
| 60 event_.Signal(); | |
| 61 } | 48 } |
| 62 | 49 |
| 63 private: | 50 private: |
| 64 base::WaitableEvent event_; | 51 scoped_ptr<PendingResult> pending_result_; |
| 65 bool is_blocked_; | |
| 66 }; | 52 }; |
| 67 | 53 |
| 68 class MockProxyResolver : public net::SingleThreadedProxyResolver { | |
| 69 public: | |
| 70 MockProxyResolver() | |
| 71 : net::SingleThreadedProxyResolver(new SyncMockProxyResolver) { | |
| 72 x = reinterpret_cast<SyncMockProxyResolver*>(resolver()); | |
| 73 } | |
| 74 | |
| 75 // TODO(eroman): cleanup. | |
| 76 SyncMockProxyResolver* x; | |
| 77 }; | |
| 78 | |
| 79 // This struct holds the values that were passed to | |
| 80 // Delegate::OnResolveProxyCompleted(). The caller should use WaitUntilDone() | |
| 81 // to block until the result has been populated. | |
| 82 struct ResultFuture { | |
| 83 public: | |
| 84 ResultFuture() | |
| 85 : reply_msg(NULL), | |
| 86 error_code(0), | |
| 87 started_(false, false), | |
| 88 completed_(false, false) { | |
| 89 } | |
| 90 | |
| 91 // Wait until the request has completed. In other words we have invoked: | |
| 92 // ResolveProxyMsgHelper::Delegate::OnResolveProxyCompleted. | |
| 93 void WaitUntilDone() { | |
| 94 completed_.Wait(); | |
| 95 } | |
| 96 | |
| 97 // Wait until the request has been sent to ResolveProxyMsgHelper. | |
| 98 void WaitUntilStarted() { | |
| 99 started_.Wait(); | |
| 100 } | |
| 101 | |
| 102 bool TimedWaitUntilDone(const base::TimeDelta& max_time) { | |
| 103 return completed_.TimedWait(max_time); | |
| 104 } | |
| 105 | |
| 106 // These fields are only valid after returning from WaitUntilDone(). | |
| 107 IPC::Message* reply_msg; | |
| 108 int error_code; | |
| 109 std::string proxy_list; | |
| 110 | |
| 111 private: | |
| 112 friend class AsyncRequestRunner; | |
| 113 base::WaitableEvent started_; | |
| 114 base::WaitableEvent completed_; | |
| 115 }; | |
| 116 | |
| 117 // This class lives on the io thread. It starts async requests using the | |
| 118 // class under test (ResolveProxyMsgHelper), and signals the result future on | |
| 119 // completion. | |
| 120 class AsyncRequestRunner : public ResolveProxyMsgHelper::Delegate { | |
| 121 public: | |
| 122 AsyncRequestRunner(net::ProxyService* proxy_service) { | |
| 123 resolve_proxy_msg_helper_.reset( | |
| 124 new ResolveProxyMsgHelper(this, proxy_service)); | |
| 125 } | |
| 126 | |
| 127 void Start(ResultFuture* future, const GURL& url, IPC::Message* reply_msg) { | |
| 128 futures_.push_back(future); | |
| 129 resolve_proxy_msg_helper_->Start(url, reply_msg); | |
| 130 | |
| 131 // Notify of request start. | |
| 132 future->started_.Signal(); | |
| 133 } | |
| 134 | |
| 135 virtual void OnResolveProxyCompleted(IPC::Message* reply_msg, | |
| 136 int error_code, | |
| 137 const std::string& proxy_list) { | |
| 138 // Update the result future for this request (top of queue), and signal it. | |
| 139 ResultFuture* future = futures_.front(); | |
| 140 futures_.pop_front(); | |
| 141 | |
| 142 future->reply_msg = reply_msg; | |
| 143 future->error_code = error_code; | |
| 144 future->proxy_list = proxy_list; | |
| 145 | |
| 146 // Notify of request completion. | |
| 147 future->completed_.Signal(); | |
| 148 } | |
| 149 | |
| 150 private: | |
| 151 std::deque<ResultFuture*> futures_; | |
| 152 scoped_ptr<ResolveProxyMsgHelper> resolve_proxy_msg_helper_; | |
| 153 }; | |
| 154 | |
| 155 // Helper class to start async requests on an io thread, and return a | |
| 156 // result future. The caller then uses ResultFuture::WaitUntilDone() to | |
| 157 // get at the results. It "bridges" the originating thread with the helper | |
| 158 // io thread. | |
| 159 class RunnerBridge { | |
| 160 public: | |
| 161 RunnerBridge() : io_thread_("io_thread"), done_(false, false) { | |
| 162 // Start an io thread where we will run the async requests. | |
| 163 base::Thread::Options options; | |
| 164 options.message_loop_type = MessageLoop::TYPE_IO; | |
| 165 io_thread_.StartWithOptions(options); | |
| 166 | |
| 167 // Construct the state that lives on io thread. | |
| 168 io_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod( | |
| 169 this, &RunnerBridge::DoConstruct)); | |
| 170 done_.Wait(); | |
| 171 } | |
| 172 | |
| 173 // Start an async request on the io thread. | |
| 174 ResultFuture* Start(const GURL& url, IPC::Message* reply_msg) { | |
| 175 ResultFuture* future = new ResultFuture(); | |
| 176 | |
| 177 io_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod( | |
| 178 async_runner_, &AsyncRequestRunner::Start, future, url, reply_msg)); | |
| 179 | |
| 180 return future; | |
| 181 } | |
| 182 | |
| 183 void DestroyAsyncRunner() { | |
| 184 io_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod( | |
| 185 this, &RunnerBridge::DoDestroyAsyncRunner)); | |
| 186 done_.Wait(); | |
| 187 } | |
| 188 | |
| 189 ~RunnerBridge() { | |
| 190 io_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod( | |
| 191 this, &RunnerBridge::DoDestroy)); | |
| 192 done_.Wait(); | |
| 193 } | |
| 194 | |
| 195 MockProxyResolver* proxy_resolver() { | |
| 196 return proxy_resolver_; | |
| 197 } | |
| 198 | |
| 199 // Called from io thread. | |
| 200 void DoConstruct() { | |
| 201 proxy_resolver_ = new MockProxyResolver(); | |
| 202 proxy_service_ = new net::ProxyService(new MockProxyConfigService(), | |
| 203 proxy_resolver_); | |
| 204 async_runner_ = new AsyncRequestRunner(proxy_service_); | |
| 205 done_.Signal(); | |
| 206 } | |
| 207 | |
| 208 // Called from io thread. | |
| 209 void DoDestroy() { | |
| 210 delete async_runner_; | |
| 211 delete proxy_service_; | |
| 212 done_.Signal(); | |
| 213 } | |
| 214 | |
| 215 // Called from io thread. | |
| 216 void DoDestroyAsyncRunner() { | |
| 217 delete async_runner_; | |
| 218 async_runner_ = NULL; | |
| 219 done_.Signal(); | |
| 220 } | |
| 221 | |
| 222 private: | |
| 223 base::Thread io_thread_; | |
| 224 base::WaitableEvent done_; | |
| 225 | |
| 226 net::ProxyService* proxy_service_; | |
| 227 MockProxyResolver* proxy_resolver_; // Owned by proxy_service_. | |
| 228 | |
| 229 AsyncRequestRunner* async_runner_; | |
| 230 }; | |
| 231 | |
| 232 // Avoid the need to have an AddRef / Release | |
| 233 template<> | |
| 234 void RunnableMethodTraits<RunnerBridge>::RetainCallee(RunnerBridge*) {} | |
| 235 template<> | |
| 236 void RunnableMethodTraits<RunnerBridge>::ReleaseCallee(RunnerBridge*) {} | |
| 237 | |
| 238 template<> | |
| 239 void RunnableMethodTraits<AsyncRequestRunner>::RetainCallee( | |
| 240 AsyncRequestRunner*) {} | |
| 241 template<> | |
| 242 void RunnableMethodTraits<AsyncRequestRunner>::ReleaseCallee( | |
| 243 AsyncRequestRunner*) {} | |
| 244 | |
| 245 | |
| 246 // Issue three sequential requests -- each should succeed. | 54 // Issue three sequential requests -- each should succeed. |
| 247 TEST(ResolveProxyMsgHelperTest, Sequential) { | 55 TEST(ResolveProxyMsgHelperTest, Sequential) { |
| 248 RunnerBridge runner; | 56 net::MockAsyncProxyResolver* resolver = new net::MockAsyncProxyResolver; |
| 57 net::ProxyService service(new MockProxyConfigService, resolver); |
| 58 |
| 59 MyDelegate delegate; |
| 60 ResolveProxyMsgHelper helper(&delegate, &service); |
| 249 | 61 |
| 250 GURL url1("http://www.google1.com/"); | 62 GURL url1("http://www.google1.com/"); |
| 251 GURL url2("http://www.google2.com/"); | 63 GURL url2("http://www.google2.com/"); |
| 252 GURL url3("http://www.google3.com/"); | 64 GURL url3("http://www.google3.com/"); |
| 253 | 65 |
| 254 scoped_ptr<IPC::Message> msg1(new IPC::Message()); | 66 scoped_ptr<IPC::Message> msg1(new IPC::Message()); |
| 255 scoped_ptr<IPC::Message> msg2(new IPC::Message()); | 67 scoped_ptr<IPC::Message> msg2(new IPC::Message()); |
| 256 scoped_ptr<IPC::Message> msg3(new IPC::Message()); | 68 scoped_ptr<IPC::Message> msg3(new IPC::Message()); |
| 257 | 69 |
| 258 // Execute each request sequentially (so there are never 2 requests | 70 // Execute each request sequentially (so there are never 2 requests |
| 259 // outstanding at the same time). | 71 // outstanding at the same time). |
| 260 | 72 |
| 261 scoped_ptr<ResultFuture> result1(runner.Start(url1, msg1.get())); | 73 helper.Start(url1, msg1.get()); |
| 262 result1->WaitUntilDone(); | |
| 263 | 74 |
| 264 scoped_ptr<ResultFuture> result2(runner.Start(url2, msg2.get())); | 75 // Finish ProxyService's initialization. |
| 265 result2->WaitUntilDone(); | 76 resolver->pending_set_pac_script_request()->CompleteNow(net::OK); |
| 266 | 77 |
| 267 scoped_ptr<ResultFuture> result3(runner.Start(url3, msg3.get())); | 78 ASSERT_EQ(1u, resolver->pending_requests().size()); |
| 268 result3->WaitUntilDone(); | 79 EXPECT_EQ(url1, resolver->pending_requests()[0]->url()); |
| 80 resolver->pending_requests()[0]->results()->UseNamedProxy("result1:80"); |
| 81 resolver->pending_requests()[0]->CompleteNow(net::OK); |
| 269 | 82 |
| 270 // Check that each request gave the expected result. | 83 // Check result. |
| 84 EXPECT_EQ(msg1.get(), delegate.pending_result()->msg); |
| 85 EXPECT_EQ(net::OK, delegate.pending_result()->error_code); |
| 86 EXPECT_EQ("PROXY result1:80", delegate.pending_result()->proxy_list); |
| 87 delegate.clear_pending_result(); |
| 271 | 88 |
| 272 EXPECT_EQ(msg1.get(), result1->reply_msg); | 89 helper.Start(url2, msg2.get()); |
| 273 EXPECT_EQ(net::OK, result1->error_code); | |
| 274 EXPECT_EQ("PROXY www.google1.com:80", result1->proxy_list); | |
| 275 | 90 |
| 276 EXPECT_EQ(msg2.get(), result2->reply_msg); | 91 ASSERT_EQ(1u, resolver->pending_requests().size()); |
| 277 EXPECT_EQ(net::OK, result2->error_code); | 92 EXPECT_EQ(url2, resolver->pending_requests()[0]->url()); |
| 278 EXPECT_EQ("PROXY www.google2.com:80", result2->proxy_list); | 93 resolver->pending_requests()[0]->results()->UseNamedProxy("result2:80"); |
| 94 resolver->pending_requests()[0]->CompleteNow(net::OK); |
| 279 | 95 |
| 280 EXPECT_EQ(msg3.get(), result3->reply_msg); | 96 // Check result. |
| 281 EXPECT_EQ(net::OK, result3->error_code); | 97 EXPECT_EQ(msg2.get(), delegate.pending_result()->msg); |
| 282 EXPECT_EQ("PROXY www.google3.com:80", result3->proxy_list); | 98 EXPECT_EQ(net::OK, delegate.pending_result()->error_code); |
| 99 EXPECT_EQ("PROXY result2:80", delegate.pending_result()->proxy_list); |
| 100 delegate.clear_pending_result(); |
| 101 |
| 102 helper.Start(url3, msg3.get()); |
| 103 |
| 104 ASSERT_EQ(1u, resolver->pending_requests().size()); |
| 105 EXPECT_EQ(url3, resolver->pending_requests()[0]->url()); |
| 106 resolver->pending_requests()[0]->results()->UseNamedProxy("result3:80"); |
| 107 resolver->pending_requests()[0]->CompleteNow(net::OK); |
| 108 |
| 109 // Check result. |
| 110 EXPECT_EQ(msg3.get(), delegate.pending_result()->msg); |
| 111 EXPECT_EQ(net::OK, delegate.pending_result()->error_code); |
| 112 EXPECT_EQ("PROXY result3:80", delegate.pending_result()->proxy_list); |
| 113 delegate.clear_pending_result(); |
| 283 } | 114 } |
| 284 | 115 |
| 285 // Issue a request while one is already in progress -- should be queued. | 116 // Issue a request while one is already in progress -- should be queued. |
| 286 TEST(ResolveProxyMsgHelperTest, QueueRequests) { | 117 TEST(ResolveProxyMsgHelperTest, QueueRequests) { |
| 287 RunnerBridge runner; | 118 net::MockAsyncProxyResolver* resolver = new net::MockAsyncProxyResolver; |
| 119 net::ProxyService service(new MockProxyConfigService, resolver); |
| 120 |
| 121 MyDelegate delegate; |
| 122 ResolveProxyMsgHelper helper(&delegate, &service); |
| 288 | 123 |
| 289 GURL url1("http://www.google1.com/"); | 124 GURL url1("http://www.google1.com/"); |
| 290 GURL url2("http://www.google2.com/"); | 125 GURL url2("http://www.google2.com/"); |
| 291 GURL url3("http://www.google3.com/"); | 126 GURL url3("http://www.google3.com/"); |
| 292 | 127 |
| 293 scoped_ptr<IPC::Message> msg1(new IPC::Message()); | 128 scoped_ptr<IPC::Message> msg1(new IPC::Message()); |
| 294 scoped_ptr<IPC::Message> msg2(new IPC::Message()); | 129 scoped_ptr<IPC::Message> msg2(new IPC::Message()); |
| 295 scoped_ptr<IPC::Message> msg3(new IPC::Message()); | 130 scoped_ptr<IPC::Message> msg3(new IPC::Message()); |
| 296 | 131 |
| 297 // Make the proxy resolver hang on the next request. | 132 // Start three requests. Since the proxy resolver is async, all the |
| 298 runner.proxy_resolver()->x->Block(); | 133 // requests will be pending. |
| 299 | 134 |
| 300 // Start three requests. Since the proxy resolver is hung, the second two | 135 helper.Start(url1, msg1.get()); |
| 301 // will be pending. | |
| 302 | 136 |
| 303 scoped_ptr<ResultFuture> result1(runner.Start(url1, msg1.get())); | 137 // Finish ProxyService's initialization. |
| 304 scoped_ptr<ResultFuture> result2(runner.Start(url2, msg2.get())); | 138 resolver->pending_set_pac_script_request()->CompleteNow(net::OK); |
| 305 scoped_ptr<ResultFuture> result3(runner.Start(url3, msg3.get())); | |
| 306 | 139 |
| 307 // Wait for the final request to have been scheduled. Otherwise we may rush | 140 helper.Start(url2, msg2.get()); |
| 308 // to calling Unblock() without actually having blocked anything. | 141 helper.Start(url3, msg3.get()); |
| 309 result3->WaitUntilStarted(); | |
| 310 | 142 |
| 311 // Unblock the proxy service so requests 1-3 can complete. | 143 // ResolveProxyHelper only keeps 1 request outstanding in ProxyService |
| 312 runner.proxy_resolver()->x->Unblock(); | 144 // at a time. |
| 145 ASSERT_EQ(1u, resolver->pending_requests().size()); |
| 146 EXPECT_EQ(url1, resolver->pending_requests()[0]->url()); |
| 313 | 147 |
| 314 // Wait for all the requests to finish (they run in FIFO order). | 148 resolver->pending_requests()[0]->results()->UseNamedProxy("result1:80"); |
| 315 result3->WaitUntilDone(); | 149 resolver->pending_requests()[0]->CompleteNow(net::OK); |
| 316 | 150 |
| 317 // Check that each call invoked the callback with the right parameters. | 151 // Check result. |
| 152 EXPECT_EQ(msg1.get(), delegate.pending_result()->msg); |
| 153 EXPECT_EQ(net::OK, delegate.pending_result()->error_code); |
| 154 EXPECT_EQ("PROXY result1:80", delegate.pending_result()->proxy_list); |
| 155 delegate.clear_pending_result(); |
| 318 | 156 |
| 319 EXPECT_EQ(msg1.get(), result1->reply_msg); | 157 ASSERT_EQ(1u, resolver->pending_requests().size()); |
| 320 EXPECT_EQ(net::OK, result1->error_code); | 158 EXPECT_EQ(url2, resolver->pending_requests()[0]->url()); |
| 321 EXPECT_EQ("PROXY www.google1.com:80", result1->proxy_list); | |
| 322 | 159 |
| 323 EXPECT_EQ(msg2.get(), result2->reply_msg); | 160 resolver->pending_requests()[0]->results()->UseNamedProxy("result2:80"); |
| 324 EXPECT_EQ(net::OK, result2->error_code); | 161 resolver->pending_requests()[0]->CompleteNow(net::OK); |
| 325 EXPECT_EQ("PROXY www.google2.com:80", result2->proxy_list); | |
| 326 | 162 |
| 327 EXPECT_EQ(msg3.get(), result3->reply_msg); | 163 // Check result. |
| 328 EXPECT_EQ(net::OK, result3->error_code); | 164 EXPECT_EQ(msg2.get(), delegate.pending_result()->msg); |
| 329 EXPECT_EQ("PROXY www.google3.com:80", result3->proxy_list); | 165 EXPECT_EQ(net::OK, delegate.pending_result()->error_code); |
| 166 EXPECT_EQ("PROXY result2:80", delegate.pending_result()->proxy_list); |
| 167 delegate.clear_pending_result(); |
| 168 |
| 169 ASSERT_EQ(1u, resolver->pending_requests().size()); |
| 170 EXPECT_EQ(url3, resolver->pending_requests()[0]->url()); |
| 171 |
| 172 resolver->pending_requests()[0]->results()->UseNamedProxy("result3:80"); |
| 173 resolver->pending_requests()[0]->CompleteNow(net::OK); |
| 174 |
| 175 // Check result. |
| 176 EXPECT_EQ(msg3.get(), delegate.pending_result()->msg); |
| 177 EXPECT_EQ(net::OK, delegate.pending_result()->error_code); |
| 178 EXPECT_EQ("PROXY result3:80", delegate.pending_result()->proxy_list); |
| 179 delegate.clear_pending_result(); |
| 330 } | 180 } |
| 331 | 181 |
| 332 // Delete the helper while a request is in progress, and others are pending. | 182 // Delete the helper while a request is in progress, and others are pending. |
| 333 TEST(ResolveProxyMsgHelperTest, CancelPendingRequests) { | 183 TEST(ResolveProxyMsgHelperTest, CancelPendingRequests) { |
| 334 RunnerBridge runner; | 184 net::MockAsyncProxyResolver* resolver = new net::MockAsyncProxyResolver; |
| 185 net::ProxyService service(new MockProxyConfigService, resolver); |
| 186 |
| 187 MyDelegate delegate; |
| 188 scoped_ptr<ResolveProxyMsgHelper> helper( |
| 189 new ResolveProxyMsgHelper(&delegate, &service)); |
| 335 | 190 |
| 336 GURL url1("http://www.google1.com/"); | 191 GURL url1("http://www.google1.com/"); |
| 337 GURL url2("http://www.google2.com/"); | 192 GURL url2("http://www.google2.com/"); |
| 338 GURL url3("http://www.google3.com/"); | 193 GURL url3("http://www.google3.com/"); |
| 339 | 194 |
| 340 // NOTE: these are not scoped ptr, since they will be deleted by the | 195 // NOTE: these are not scoped ptr, since they will be deleted by the |
| 341 // request's cancellation. | 196 // request's cancellation. |
| 342 IPC::Message* msg1 = new IPC::Message(); | 197 IPC::Message* msg1 = new IPC::Message(); |
| 343 IPC::Message* msg2 = new IPC::Message(); | 198 IPC::Message* msg2 = new IPC::Message(); |
| 344 IPC::Message* msg3 = new IPC::Message(); | 199 IPC::Message* msg3 = new IPC::Message(); |
| 345 | 200 |
| 346 // Make the next request block. | 201 // Start three requests. Since the proxy resolver is async, all the |
| 347 runner.proxy_resolver()->x->Block(); | 202 // requests will be pending. |
| 348 | 203 |
| 349 // Start three requests; since the first one blocked, the other two should | 204 helper->Start(url1, msg1); |
| 350 // be pending. | |
| 351 | 205 |
| 352 scoped_ptr<ResultFuture> result1(runner.Start(url1, msg1)); | 206 // Finish ProxyService's initialization. |
| 353 scoped_ptr<ResultFuture> result2(runner.Start(url2, msg2)); | 207 resolver->pending_set_pac_script_request()->CompleteNow(net::OK); |
| 354 scoped_ptr<ResultFuture> result3(runner.Start(url3, msg3)); | |
| 355 | 208 |
| 356 result3->WaitUntilStarted(); | 209 helper->Start(url2, msg2); |
| 210 helper->Start(url3, msg3); |
| 211 |
| 212 // ResolveProxyHelper only keeps 1 request outstanding in ProxyService |
| 213 // at a time. |
| 214 ASSERT_EQ(1u, resolver->pending_requests().size()); |
| 215 EXPECT_EQ(url1, resolver->pending_requests()[0]->url()); |
| 357 | 216 |
| 358 // Delete the underlying ResolveProxyMsgHelper -- this should cancel all | 217 // Delete the underlying ResolveProxyMsgHelper -- this should cancel all |
| 359 // the requests which are outstanding. | 218 // the requests which are outstanding. |
| 360 runner.DestroyAsyncRunner(); | 219 helper.reset(); |
| 361 | 220 |
| 362 // Unblocking the proxy resolver means the three requests can complete -- | 221 // The pending requests sent to the proxy resolver should have been cancelled. |
| 363 // however they should not try to notify the delegate since we have already | |
| 364 // deleted the helper. | |
| 365 runner.proxy_resolver()->x->Unblock(); | |
| 366 | 222 |
| 367 // Check that none of the requests were sent to the delegate. | 223 EXPECT_EQ(0u, resolver->pending_requests().size()); |
| 368 EXPECT_FALSE( | 224 |
| 369 result1->TimedWaitUntilDone(base::TimeDelta::FromMilliseconds(2))); | 225 EXPECT_EQ(NULL, delegate.pending_result()); |
| 370 EXPECT_FALSE( | |
| 371 result2->TimedWaitUntilDone(base::TimeDelta::FromMilliseconds(2))); | |
| 372 EXPECT_FALSE( | |
| 373 result3->TimedWaitUntilDone(base::TimeDelta::FromMilliseconds(2))); | |
| 374 | 226 |
| 375 // It should also be the case that msg1, msg2, msg3 were deleted by the | 227 // It should also be the case that msg1, msg2, msg3 were deleted by the |
| 376 // cancellation. (Else will show up as a leak in Purify). | 228 // cancellation. (Else will show up as a leak in Purify/Valgrind). |
| 377 } | 229 } |
| OLD | NEW |