OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 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 "net/proxy/proxy_resolver_js_bindings.h" | |
6 | |
7 #include "base/compiler_specific.h" | |
8 #include "base/memory/scoped_ptr.h" | |
9 #include "base/string_util.h" | |
10 #include "net/base/address_list.h" | |
11 #include "net/base/host_cache.h" | |
12 #include "net/base/mock_host_resolver.h" | |
13 #include "net/base/net_errors.h" | |
14 #include "net/base/net_log.h" | |
15 #include "net/base/net_log_unittest.h" | |
16 #include "net/base/net_util.h" | |
17 #include "net/base/test_completion_callback.h" | |
18 #include "net/proxy/proxy_resolver_request_context.h" | |
19 #include "net/proxy/sync_host_resolver.h" | |
20 #include "testing/gtest/include/gtest/gtest.h" | |
21 | |
22 namespace net { | |
23 | |
24 namespace { | |
25 | |
26 // This is a HostResolver that synchronously resolves all hosts to the | |
27 // following address list of length 3: | |
28 // 192.168.1.1 | |
29 // 172.22.34.1 | |
30 // 200.100.1.2 | |
31 class MockHostResolverWithMultipleResults : public SyncHostResolver { | |
32 public: | |
33 // HostResolver methods: | |
34 virtual int Resolve(const HostResolver::RequestInfo& info, | |
35 AddressList* addresses, | |
36 const BoundNetLog& bound_net_log) OVERRIDE { | |
37 return ParseAddressList("192.168.1.1,172.22.34.1,200.100.1.2", "", | |
38 addresses); | |
39 } | |
40 | |
41 virtual void Shutdown() OVERRIDE {} | |
42 | |
43 private: | |
44 virtual ~MockHostResolverWithMultipleResults() {} | |
45 }; | |
46 | |
47 class MockFailingHostResolver : public SyncHostResolver { | |
48 public: | |
49 MockFailingHostResolver() : count_(0) {} | |
50 | |
51 // HostResolver methods: | |
52 virtual int Resolve(const HostResolver::RequestInfo& info, | |
53 AddressList* addresses, | |
54 const BoundNetLog& bound_net_log) OVERRIDE { | |
55 count_++; | |
56 return ERR_NAME_NOT_RESOLVED; | |
57 } | |
58 | |
59 virtual void Shutdown() OVERRIDE {} | |
60 | |
61 // Returns the number of times Resolve() has been called. | |
62 int count() const { return count_; } | |
63 void ResetCount() { count_ = 0; } | |
64 | |
65 private: | |
66 int count_; | |
67 }; | |
68 | |
69 class MockSyncHostResolver : public SyncHostResolver { | |
70 public: | |
71 MockSyncHostResolver() { | |
72 resolver_.set_synchronous_mode(true); | |
73 } | |
74 | |
75 virtual int Resolve(const HostResolver::RequestInfo& info, | |
76 AddressList* addresses, | |
77 const BoundNetLog& bound_net_log) OVERRIDE { | |
78 return resolver_.Resolve(info, addresses, CompletionCallback(), NULL, | |
79 bound_net_log); | |
80 } | |
81 | |
82 virtual void Shutdown() OVERRIDE {} | |
83 | |
84 RuleBasedHostResolverProc* rules() { | |
85 return resolver_.rules(); | |
86 } | |
87 | |
88 private: | |
89 MockHostResolver resolver_; | |
90 }; | |
91 | |
92 TEST(ProxyResolverJSBindingsTest, DnsResolve) { | |
93 MockSyncHostResolver* host_resolver = new MockSyncHostResolver; | |
94 | |
95 // Get a hold of a DefaultJSBindings* (it is a hidden impl class). | |
96 scoped_ptr<ProxyResolverJSBindings> bindings( | |
97 ProxyResolverJSBindings::CreateDefault(host_resolver, NULL, NULL)); | |
98 | |
99 std::string ip_address; | |
100 | |
101 // Empty string is not considered a valid host (even though on some systems | |
102 // requesting this will resolve to localhost). | |
103 host_resolver->rules()->AddSimulatedFailure(""); | |
104 EXPECT_FALSE(bindings->DnsResolve("", &ip_address)); | |
105 | |
106 // Should call through to the HostResolver. | |
107 host_resolver->rules()->AddRule("google.com", "192.168.1.1"); | |
108 EXPECT_TRUE(bindings->DnsResolve("google.com", &ip_address)); | |
109 EXPECT_EQ("192.168.1.1", ip_address); | |
110 | |
111 // Resolve failures should give empty string. | |
112 host_resolver->rules()->AddSimulatedFailure("fail"); | |
113 EXPECT_FALSE(bindings->DnsResolve("fail", &ip_address)); | |
114 | |
115 // TODO(eroman): would be nice to have an IPV6 test here too, but that | |
116 // won't work on all systems. | |
117 } | |
118 | |
119 TEST(ProxyResolverJSBindingsTest, MyIpAddress) { | |
120 MockSyncHostResolver* host_resolver = new MockSyncHostResolver; | |
121 | |
122 // Get a hold of a DefaultJSBindings* (it is a hidden impl class). | |
123 scoped_ptr<ProxyResolverJSBindings> bindings( | |
124 ProxyResolverJSBindings::CreateDefault(host_resolver, NULL, NULL)); | |
125 | |
126 // Our IP address is always going to be 127.0.0.1, since we are using a | |
127 // mock host resolver. | |
128 std::string my_ip_address; | |
129 EXPECT_TRUE(bindings->MyIpAddress(&my_ip_address)); | |
130 | |
131 EXPECT_EQ("127.0.0.1", my_ip_address); | |
132 } | |
133 | |
134 // Tests that the regular PAC functions restrict results to IPv4, | |
135 // but that the Microsoft extensions to PAC do not. We test this | |
136 // by seeing whether ADDRESS_FAMILY_IPV4 or ADDRESS_FAMILY_UNSPECIFIED | |
137 // was passed into to the host resolver. | |
138 // | |
139 // Restricted to IPv4 address family: | |
140 // myIpAddress() | |
141 // dnsResolve() | |
142 // | |
143 // Unrestricted address family: | |
144 // myIpAddressEx() | |
145 // dnsResolveEx() | |
146 TEST(ProxyResolverJSBindingsTest, RestrictAddressFamily) { | |
147 MockSyncHostResolver* host_resolver = new MockSyncHostResolver; | |
148 | |
149 // Get a hold of a DefaultJSBindings* (it is a hidden impl class). | |
150 scoped_ptr<ProxyResolverJSBindings> bindings( | |
151 ProxyResolverJSBindings::CreateDefault(host_resolver, NULL, NULL)); | |
152 | |
153 // Make it so requests resolve to particular address patterns based on family: | |
154 // IPV4_ONLY --> 192.168.1.* | |
155 // UNSPECIFIED --> 192.168.2.1 | |
156 host_resolver->rules()->AddRuleForAddressFamily( | |
157 "foo", ADDRESS_FAMILY_IPV4, "192.168.1.1"); | |
158 host_resolver->rules()->AddRuleForAddressFamily( | |
159 "*", ADDRESS_FAMILY_IPV4, "192.168.1.2"); | |
160 host_resolver->rules()->AddRuleForAddressFamily( | |
161 "foo", ADDRESS_FAMILY_UNSPECIFIED, "192.168.2.1"); | |
162 host_resolver->rules()->AddRuleForAddressFamily( | |
163 "*", ADDRESS_FAMILY_UNSPECIFIED, "192.168.2.2"); | |
164 | |
165 // Verify that our mock setups works as expected, and we get different results | |
166 // depending if the address family was IPV4_ONLY or not. | |
167 HostResolver::RequestInfo info(HostPortPair("foo", 80)); | |
168 AddressList address_list; | |
169 EXPECT_EQ(OK, host_resolver->Resolve(info, &address_list, BoundNetLog())); | |
170 ASSERT_FALSE(address_list.empty()); | |
171 EXPECT_EQ("192.168.2.1", address_list.front().ToStringWithoutPort()); | |
172 | |
173 info.set_address_family(ADDRESS_FAMILY_IPV4); | |
174 EXPECT_EQ(OK, host_resolver->Resolve(info, &address_list, BoundNetLog())); | |
175 ASSERT_FALSE(address_list.empty()); | |
176 EXPECT_EQ("192.168.1.1", address_list.front().ToStringWithoutPort()); | |
177 | |
178 std::string ip_address; | |
179 // Now the actual test. | |
180 EXPECT_TRUE(bindings->MyIpAddress(&ip_address)); | |
181 EXPECT_EQ("192.168.1.2", ip_address); // IPv4 restricted. | |
182 | |
183 EXPECT_TRUE(bindings->DnsResolve("foo", &ip_address)); | |
184 EXPECT_EQ("192.168.1.1", ip_address); // IPv4 restricted. | |
185 | |
186 EXPECT_TRUE(bindings->DnsResolve("foo2", &ip_address)); | |
187 EXPECT_EQ("192.168.1.2", ip_address); // IPv4 restricted. | |
188 | |
189 EXPECT_TRUE(bindings->MyIpAddressEx(&ip_address)); | |
190 EXPECT_EQ("192.168.2.2", ip_address); // Unrestricted. | |
191 | |
192 EXPECT_TRUE(bindings->DnsResolveEx("foo", &ip_address)); | |
193 EXPECT_EQ("192.168.2.1", ip_address); // Unrestricted. | |
194 | |
195 EXPECT_TRUE(bindings->DnsResolveEx("foo2", &ip_address)); | |
196 EXPECT_EQ("192.168.2.2", ip_address); // Unrestricted. | |
197 } | |
198 | |
199 // Test that myIpAddressEx() and dnsResolveEx() both return a semi-colon | |
200 // separated list of addresses (as opposed to the non-Ex versions which | |
201 // just return the first result). | |
202 TEST(ProxyResolverJSBindingsTest, ExFunctionsReturnList) { | |
203 SyncHostResolver* host_resolver = | |
204 new MockHostResolverWithMultipleResults; | |
205 | |
206 // Get a hold of a DefaultJSBindings* (it is a hidden impl class). | |
207 scoped_ptr<ProxyResolverJSBindings> bindings( | |
208 ProxyResolverJSBindings::CreateDefault(host_resolver, NULL, NULL)); | |
209 | |
210 std::string ip_addresses; | |
211 | |
212 EXPECT_TRUE(bindings->MyIpAddressEx(&ip_addresses)); | |
213 EXPECT_EQ("192.168.1.1;172.22.34.1;200.100.1.2", ip_addresses); | |
214 | |
215 EXPECT_TRUE(bindings->DnsResolveEx("FOO", &ip_addresses)); | |
216 EXPECT_EQ("192.168.1.1;172.22.34.1;200.100.1.2", ip_addresses); | |
217 } | |
218 | |
219 TEST(ProxyResolverJSBindingsTest, PerRequestDNSCache) { | |
220 MockFailingHostResolver* host_resolver = new MockFailingHostResolver; | |
221 | |
222 // Get a hold of a DefaultJSBindings* (it is a hidden impl class). | |
223 scoped_ptr<ProxyResolverJSBindings> bindings( | |
224 ProxyResolverJSBindings::CreateDefault(host_resolver, NULL, NULL)); | |
225 | |
226 std::string ip_address; | |
227 | |
228 // Call DnsResolve() 4 times for the same hostname -- this should issue | |
229 // 4 separate calls to the underlying host resolver, since there is no | |
230 // current request context. | |
231 EXPECT_FALSE(bindings->DnsResolve("foo", &ip_address)); | |
232 EXPECT_FALSE(bindings->DnsResolve("foo", &ip_address)); | |
233 EXPECT_FALSE(bindings->DnsResolve("foo", &ip_address)); | |
234 EXPECT_FALSE(bindings->DnsResolve("foo", &ip_address)); | |
235 EXPECT_EQ(4, host_resolver->count()); | |
236 | |
237 host_resolver->ResetCount(); | |
238 | |
239 // Now setup a per-request context, and try the same experiment -- we | |
240 // expect the underlying host resolver to receive only 1 request this time, | |
241 // since it will service the others from the per-request DNS cache. | |
242 const unsigned kMaxCacheEntries = 50; | |
243 HostCache cache(kMaxCacheEntries); | |
244 ProxyResolverRequestContext context(NULL, &cache); | |
245 bindings->set_current_request_context(&context); | |
246 | |
247 EXPECT_FALSE(bindings->DnsResolve("foo", &ip_address)); | |
248 EXPECT_FALSE(bindings->DnsResolve("foo", &ip_address)); | |
249 EXPECT_FALSE(bindings->DnsResolve("foo", &ip_address)); | |
250 EXPECT_FALSE(bindings->DnsResolve("foo", &ip_address)); | |
251 EXPECT_EQ(1, host_resolver->count()); | |
252 | |
253 host_resolver->ResetCount(); | |
254 | |
255 // The "Ex" version shares this same cache, however since the flags | |
256 // are different it won't reuse this particular entry. | |
257 EXPECT_FALSE(bindings->DnsResolveEx("foo", &ip_address)); | |
258 EXPECT_EQ(1, host_resolver->count()); | |
259 EXPECT_FALSE(bindings->DnsResolveEx("foo", &ip_address)); | |
260 EXPECT_FALSE(bindings->DnsResolveEx("foo", &ip_address)); | |
261 EXPECT_EQ(1, host_resolver->count()); | |
262 | |
263 bindings->set_current_request_context(NULL); | |
264 } | |
265 | |
266 // Test that when a binding is called, it logs to the per-request NetLog. | |
267 TEST(ProxyResolverJSBindingsTest, NetLog) { | |
268 MockFailingHostResolver* host_resolver = new MockFailingHostResolver; | |
269 | |
270 CapturingNetLog global_log; | |
271 | |
272 // Get a hold of a DefaultJSBindings* (it is a hidden impl class). | |
273 scoped_ptr<ProxyResolverJSBindings> bindings( | |
274 ProxyResolverJSBindings::CreateDefault( | |
275 host_resolver, &global_log, NULL)); | |
276 | |
277 // Attach a capturing NetLog as the current request's log stream. | |
278 CapturingNetLog log; | |
279 BoundNetLog bound_log(BoundNetLog::Make(&log, NetLog::SOURCE_NONE)); | |
280 ProxyResolverRequestContext context(&bound_log, NULL); | |
281 bindings->set_current_request_context(&context); | |
282 | |
283 std::string ip_address; | |
284 net::CapturingNetLog::CapturedEntryList entries; | |
285 log.GetEntries(&entries); | |
286 ASSERT_EQ(0u, entries.size()); | |
287 | |
288 // Call all the bindings. Each call should be logging something to | |
289 // our NetLog. | |
290 | |
291 bindings->MyIpAddress(&ip_address); | |
292 | |
293 log.GetEntries(&entries); | |
294 EXPECT_EQ(2u, entries.size()); | |
295 EXPECT_TRUE(LogContainsBeginEvent( | |
296 entries, 0, NetLog::TYPE_PAC_JAVASCRIPT_MY_IP_ADDRESS)); | |
297 EXPECT_TRUE(LogContainsEndEvent( | |
298 entries, 1, NetLog::TYPE_PAC_JAVASCRIPT_MY_IP_ADDRESS)); | |
299 | |
300 bindings->MyIpAddressEx(&ip_address); | |
301 | |
302 log.GetEntries(&entries); | |
303 EXPECT_EQ(4u, entries.size()); | |
304 EXPECT_TRUE(LogContainsBeginEvent( | |
305 entries, 2, NetLog::TYPE_PAC_JAVASCRIPT_MY_IP_ADDRESS_EX)); | |
306 EXPECT_TRUE(LogContainsEndEvent( | |
307 entries, 3, NetLog::TYPE_PAC_JAVASCRIPT_MY_IP_ADDRESS_EX)); | |
308 | |
309 bindings->DnsResolve("foo", &ip_address); | |
310 | |
311 log.GetEntries(&entries); | |
312 EXPECT_EQ(6u, entries.size()); | |
313 EXPECT_TRUE(LogContainsBeginEvent( | |
314 entries, 4, NetLog::TYPE_PAC_JAVASCRIPT_DNS_RESOLVE)); | |
315 EXPECT_TRUE(LogContainsEndEvent( | |
316 entries, 5, NetLog::TYPE_PAC_JAVASCRIPT_DNS_RESOLVE)); | |
317 | |
318 bindings->DnsResolveEx("foo", &ip_address); | |
319 | |
320 log.GetEntries(&entries); | |
321 EXPECT_EQ(8u, entries.size()); | |
322 EXPECT_TRUE(LogContainsBeginEvent( | |
323 entries, 6, NetLog::TYPE_PAC_JAVASCRIPT_DNS_RESOLVE_EX)); | |
324 EXPECT_TRUE(LogContainsEndEvent( | |
325 entries, 7, NetLog::TYPE_PAC_JAVASCRIPT_DNS_RESOLVE_EX)); | |
326 | |
327 // Nothing has been emitted globally yet. | |
328 net::CapturingNetLog::CapturedEntryList global_log_entries; | |
329 global_log.GetEntries(&global_log_entries); | |
330 EXPECT_EQ(0u, global_log_entries.size()); | |
331 | |
332 bindings->OnError(30, string16()); | |
333 | |
334 log.GetEntries(&entries); | |
335 EXPECT_EQ(9u, entries.size()); | |
336 EXPECT_TRUE(LogContainsEvent( | |
337 entries, 8, NetLog::TYPE_PAC_JAVASCRIPT_ERROR, | |
338 NetLog::PHASE_NONE)); | |
339 | |
340 // We also emit errors to the top-level log stream. | |
341 global_log.GetEntries(&global_log_entries); | |
342 EXPECT_EQ(1u, global_log_entries.size()); | |
343 EXPECT_TRUE(LogContainsEvent( | |
344 global_log_entries, 0, NetLog::TYPE_PAC_JAVASCRIPT_ERROR, | |
345 NetLog::PHASE_NONE)); | |
346 | |
347 bindings->Alert(string16()); | |
348 | |
349 log.GetEntries(&entries); | |
350 EXPECT_EQ(10u, entries.size()); | |
351 EXPECT_TRUE(LogContainsEvent( | |
352 entries, 9, NetLog::TYPE_PAC_JAVASCRIPT_ALERT, | |
353 NetLog::PHASE_NONE)); | |
354 | |
355 // We also emit javascript alerts to the top-level log stream. | |
356 global_log.GetEntries(&global_log_entries); | |
357 EXPECT_EQ(2u, global_log_entries.size()); | |
358 EXPECT_TRUE(LogContainsEvent( | |
359 global_log_entries, 1, NetLog::TYPE_PAC_JAVASCRIPT_ALERT, | |
360 NetLog::PHASE_NONE)); | |
361 } | |
362 | |
363 } // namespace | |
364 | |
365 } // namespace net | |
OLD | NEW |