1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/net/resolve_proxy_msg_helper.h" 6 7 #include "content/common/child_process_messages.h" 8 #include "ipc/ipc_test_sink.h" 9 #include "net/base/net_errors.h" 10 #include "net/proxy/mock_proxy_resolver.h" 11 #include "net/proxy/proxy_config_service.h" 12 #include "testing/gtest/include/gtest/gtest.h" 13 14 // This ProxyConfigService always returns "http://pac" as the PAC url to use. 15 class MockProxyConfigService : public net::ProxyConfigService { 16 public: 17 virtual void AddObserver(Observer* observer) {} 18 virtual void RemoveObserver(Observer* observer) {} 19 virtual ConfigAvailability GetLatestProxyConfig(net::ProxyConfig* results) { 20 *results = net::ProxyConfig::CreateFromCustomPacURL(GURL("http://pac")); 21 return CONFIG_VALID; 22 } 23 }; 24 25 class ResolveProxyMsgHelperTest : public testing::Test, 26 public IPC::Channel::Listener { 27 public: 28 struct PendingResult { 29 PendingResult(int error_code, 30 const std::string& proxy_list) 31 : error_code(error_code), proxy_list(proxy_list) { 32 } 33 34 int error_code; 35 std::string proxy_list; 36 }; 37 38 ResolveProxyMsgHelperTest() 39 : resolver_(new net::MockAsyncProxyResolver), 40 service_(new net::ProxyService( 41 new MockProxyConfigService, resolver_, NULL)), 42 helper_(new ResolveProxyMsgHelper(service_.get())), 43 message_loop_(MessageLoop::TYPE_IO), 44 io_thread_(BrowserThread::IO, &message_loop_) { 45 test_sink_.AddFilter(this); 46 helper_->OnFilterAdded(&test_sink_); 47 } 48 49 protected: 50 const PendingResult* pending_result() const { return pending_result_.get(); } 51 52 void clear_pending_result() { 53 pending_result_.reset(); 54 } 55 56 IPC::Message* GenerateReply() { 57 int temp_int; 58 std::string temp_string; 59 ChildProcessHostMsg_ResolveProxy message(GURL(), &temp_int, &temp_string); 60 return IPC::SyncMessage::GenerateReply(&message); 61 } 62 63 net::MockAsyncProxyResolver* resolver_; 64 scoped_refptr<net::ProxyService> service_; 65 scoped_refptr<ResolveProxyMsgHelper> helper_; 66 scoped_ptr<PendingResult> pending_result_; 67 68 private: 69 virtual bool OnMessageReceived(const IPC::Message& msg) { 70 TupleTypes<ChildProcessHostMsg_ResolveProxy::ReplyParam>::ValueTuple 71 reply_data; 72 EXPECT_TRUE( 73 ChildProcessHostMsg_ResolveProxy::ReadReplyParam(&msg, &reply_data)); 74 DCHECK(!pending_result_.get()); 75 pending_result_.reset(new PendingResult(reply_data.a, reply_data.b)); 76 test_sink_.ClearMessages(); 77 return true; 78 } 79 80 MessageLoop message_loop_; 81 BrowserThread io_thread_; 82 IPC::TestSink test_sink_; 83 }; 84 85 // Issue three sequential requests -- each should succeed. 86 TEST_F(ResolveProxyMsgHelperTest, Sequential) { 87 GURL url1("http://www.google1.com/"); 88 GURL url2("http://www.google2.com/"); 89 GURL url3("http://www.google3.com/"); 90 91 // Messages are deleted by the sink. 92 IPC::Message* msg1 = GenerateReply(); 93 IPC::Message* msg2 = GenerateReply(); 94 IPC::Message* msg3 = GenerateReply(); 95 96 // Execute each request sequentially (so there are never 2 requests 97 // outstanding at the same time). 98 99 helper_->OnResolveProxy(url1, msg1); 100 101 // Finish ProxyService's initialization. 102 resolver_->pending_set_pac_script_request()->CompleteNow(net::OK); 103 104 ASSERT_EQ(1u, resolver_->pending_requests().size()); 105 EXPECT_EQ(url1, resolver_->pending_requests()[0]->url()); 106 resolver_->pending_requests()[0]->results()->UseNamedProxy("result1:80"); 107 resolver_->pending_requests()[0]->CompleteNow(net::OK); 108 109 // Check result. 110 EXPECT_EQ(net::OK, pending_result()->error_code); 111 EXPECT_EQ("PROXY result1:80", pending_result()->proxy_list); 112 clear_pending_result(); 113 114 helper_->OnResolveProxy(url2, msg2); 115 116 ASSERT_EQ(1u, resolver_->pending_requests().size()); 117 EXPECT_EQ(url2, resolver_->pending_requests()[0]->url()); 118 resolver_->pending_requests()[0]->results()->UseNamedProxy("result2:80"); 119 resolver_->pending_requests()[0]->CompleteNow(net::OK); 120 121 // Check result. 122 EXPECT_EQ(net::OK, pending_result()->error_code); 123 EXPECT_EQ("PROXY result2:80", pending_result()->proxy_list); 124 clear_pending_result(); 125 126 helper_->OnResolveProxy(url3, msg3); 127 128 ASSERT_EQ(1u, resolver_->pending_requests().size()); 129 EXPECT_EQ(url3, resolver_->pending_requests()[0]->url()); 130 resolver_->pending_requests()[0]->results()->UseNamedProxy("result3:80"); 131 resolver_->pending_requests()[0]->CompleteNow(net::OK); 132 133 // Check result. 134 EXPECT_EQ(net::OK, pending_result()->error_code); 135 EXPECT_EQ("PROXY result3:80", pending_result()->proxy_list); 136 clear_pending_result(); 137 } 138 139 // Issue a request while one is already in progress -- should be queued. 140 TEST_F(ResolveProxyMsgHelperTest, QueueRequests) { 141 GURL url1("http://www.google1.com/"); 142 GURL url2("http://www.google2.com/"); 143 GURL url3("http://www.google3.com/"); 144 145 IPC::Message* msg1 = GenerateReply(); 146 IPC::Message* msg2 = GenerateReply(); 147 IPC::Message* msg3 = GenerateReply(); 148 149 // Start three requests. Since the proxy resolver is async, all the 150 // requests will be pending. 151 152 helper_->OnResolveProxy(url1, msg1); 153 154 // Finish ProxyService's initialization. 155 resolver_->pending_set_pac_script_request()->CompleteNow(net::OK); 156 157 helper_->OnResolveProxy(url2, msg2); 158 helper_->OnResolveProxy(url3, msg3); 159 160 // ResolveProxyHelper only keeps 1 request outstanding in ProxyService 161 // at a time. 162 ASSERT_EQ(1u, resolver_->pending_requests().size()); 163 EXPECT_EQ(url1, resolver_->pending_requests()[0]->url()); 164 165 resolver_->pending_requests()[0]->results()->UseNamedProxy("result1:80"); 166 resolver_->pending_requests()[0]->CompleteNow(net::OK); 167 168 // Check result. 169 EXPECT_EQ(net::OK, pending_result()->error_code); 170 EXPECT_EQ("PROXY result1:80", pending_result()->proxy_list); 171 clear_pending_result(); 172 173 ASSERT_EQ(1u, resolver_->pending_requests().size()); 174 EXPECT_EQ(url2, resolver_->pending_requests()[0]->url()); 175 176 resolver_->pending_requests()[0]->results()->UseNamedProxy("result2:80"); 177 resolver_->pending_requests()[0]->CompleteNow(net::OK); 178 179 // Check result. 180 EXPECT_EQ(net::OK, pending_result()->error_code); 181 EXPECT_EQ("PROXY result2:80", pending_result()->proxy_list); 182 clear_pending_result(); 183 184 ASSERT_EQ(1u, resolver_->pending_requests().size()); 185 EXPECT_EQ(url3, resolver_->pending_requests()[0]->url()); 186 187 resolver_->pending_requests()[0]->results()->UseNamedProxy("result3:80"); 188 resolver_->pending_requests()[0]->CompleteNow(net::OK); 189 190 // Check result. 191 EXPECT_EQ(net::OK, pending_result()->error_code); 192 EXPECT_EQ("PROXY result3:80", pending_result()->proxy_list); 193 clear_pending_result(); 194 } 195 196 // Delete the helper while a request is in progress, and others are pending. 197 TEST_F(ResolveProxyMsgHelperTest, CancelPendingRequests) { 198 GURL url1("http://www.google1.com/"); 199 GURL url2("http://www.google2.com/"); 200 GURL url3("http://www.google3.com/"); 201 202 // They will be deleted by the request's cancellation. 203 IPC::Message* msg1 = GenerateReply(); 204 IPC::Message* msg2 = GenerateReply(); 205 IPC::Message* msg3 = GenerateReply(); 206 207 // Start three requests. Since the proxy resolver is async, all the 208 // requests will be pending. 209 210 helper_->OnResolveProxy(url1, msg1); 211 212 // Finish ProxyService's initialization. 213 resolver_->pending_set_pac_script_request()->CompleteNow(net::OK); 214 215 helper_->OnResolveProxy(url2, msg2); 216 helper_->OnResolveProxy(url3, msg3); 217 218 // ResolveProxyHelper only keeps 1 request outstanding in ProxyService 219 // at a time. 220 ASSERT_EQ(1u, resolver_->pending_requests().size()); 221 EXPECT_EQ(url1, resolver_->pending_requests()[0]->url()); 222 223 // Delete the underlying ResolveProxyMsgHelper -- this should cancel all 224 // the requests which are outstanding. 225 helper_ = NULL; 226 227 // The pending requests sent to the proxy resolver should have been cancelled. 228 229 EXPECT_EQ(0u, resolver_->pending_requests().size()); 230 231 EXPECT_TRUE(pending_result() == NULL); 232 233 // It should also be the case that msg1, msg2, msg3 were deleted by the 234 // cancellation. (Else will show up as a leak in Purify/Valgrind). 235 } 236