Initial import of Cobalt 2.8885 2016-07-27
diff --git a/src/net/proxy/proxy_resolver_js_bindings_unittest.cc b/src/net/proxy/proxy_resolver_js_bindings_unittest.cc
new file mode 100644
index 0000000..f4d5a30
--- /dev/null
+++ b/src/net/proxy/proxy_resolver_js_bindings_unittest.cc
@@ -0,0 +1,378 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/proxy/proxy_resolver_js_bindings.h"
+
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/string_util.h"
+#include "net/base/address_list.h"
+#include "net/base/host_cache.h"
+#include "net/base/mock_host_resolver.h"
+#include "net/base/net_errors.h"
+#include "net/base/net_log.h"
+#include "net/base/net_log_unittest.h"
+#include "net/base/net_util.h"
+#include "net/base/test_completion_callback.h"
+#include "net/proxy/proxy_resolver_request_context.h"
+#include "net/proxy/sync_host_resolver.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_STARBOARD)
+// Starboard doesn't implement GetHostName.
+#define MAYBE_MyIpAddress DISABLED_MyIpAddress
+#else
+#define MAYBE_MyIpAddress MyIpAddress
+#endif
+
+namespace net {
+
+namespace {
+
+// This is a HostResolver that synchronously resolves all hosts to the
+// following address list of length 3:
+//     192.168.1.1
+//     172.22.34.1
+//     200.100.1.2
+class MockHostResolverWithMultipleResults : public SyncHostResolver {
+ public:
+  // HostResolver methods:
+  virtual int Resolve(const HostResolver::RequestInfo& info,
+                      AddressList* addresses,
+                      const BoundNetLog& bound_net_log) OVERRIDE {
+    return ParseAddressList("192.168.1.1,172.22.34.1,200.100.1.2", "",
+                            addresses);
+  }
+
+  virtual void Shutdown() OVERRIDE {}
+
+ private:
+  virtual ~MockHostResolverWithMultipleResults() {}
+};
+
+class MockFailingHostResolver : public SyncHostResolver {
+ public:
+  MockFailingHostResolver() : count_(0) {}
+
+  // HostResolver methods:
+  virtual int Resolve(const HostResolver::RequestInfo& info,
+                      AddressList* addresses,
+                      const BoundNetLog& bound_net_log) OVERRIDE {
+    count_++;
+    return ERR_NAME_NOT_RESOLVED;
+  }
+
+  virtual void Shutdown() OVERRIDE {}
+
+  // Returns the number of times Resolve() has been called.
+  int count() const { return count_; }
+  void ResetCount() { count_ = 0; }
+
+ private:
+  int count_;
+};
+
+class MockSyncHostResolver : public SyncHostResolver {
+ public:
+  MockSyncHostResolver() {
+    resolver_.set_synchronous_mode(true);
+  }
+
+  virtual int Resolve(const HostResolver::RequestInfo& info,
+                      AddressList* addresses,
+                      const BoundNetLog& bound_net_log) OVERRIDE {
+    return resolver_.Resolve(info, addresses, CompletionCallback(), NULL,
+                             bound_net_log);
+  }
+
+  virtual void Shutdown() OVERRIDE {}
+
+  RuleBasedHostResolverProc* rules() {
+    return resolver_.rules();
+  }
+
+ private:
+  MockHostResolver resolver_;
+};
+
+TEST(ProxyResolverJSBindingsTest, DnsResolve) {
+  MockSyncHostResolver* host_resolver = new MockSyncHostResolver;
+
+  // Get a hold of a DefaultJSBindings* (it is a hidden impl class).
+  scoped_ptr<ProxyResolverJSBindings> bindings(
+      ProxyResolverJSBindings::CreateDefault(host_resolver, NULL, NULL));
+
+  std::string ip_address;
+
+  // Empty string is not considered a valid host (even though on some systems
+  // requesting this will resolve to localhost).
+  host_resolver->rules()->AddSimulatedFailure("");
+  EXPECT_FALSE(bindings->DnsResolve("", &ip_address));
+
+  // Should call through to the HostResolver.
+  host_resolver->rules()->AddRule("google.com", "192.168.1.1");
+  EXPECT_TRUE(bindings->DnsResolve("google.com", &ip_address));
+  EXPECT_EQ("192.168.1.1", ip_address);
+
+  // Resolve failures should give empty string.
+  host_resolver->rules()->AddSimulatedFailure("fail");
+  EXPECT_FALSE(bindings->DnsResolve("fail", &ip_address));
+
+  // TODO(eroman): would be nice to have an IPV6 test here too, but that
+  // won't work on all systems.
+}
+
+TEST(ProxyResolverJSBindingsTest, MAYBE_MyIpAddress) {
+  MockSyncHostResolver* host_resolver = new MockSyncHostResolver;
+
+  // Get a hold of a DefaultJSBindings* (it is a hidden impl class).
+  scoped_ptr<ProxyResolverJSBindings> bindings(
+      ProxyResolverJSBindings::CreateDefault(host_resolver, NULL, NULL));
+
+  // Our IP address is always going to be 127.0.0.1, since we are using a
+  // mock host resolver.
+  std::string my_ip_address;
+  EXPECT_TRUE(bindings->MyIpAddress(&my_ip_address));
+
+  EXPECT_EQ("127.0.0.1", my_ip_address);
+}
+
+// Tests that the regular PAC functions restrict results to IPv4,
+// but that the Microsoft extensions to PAC do not. We test this
+// by seeing whether ADDRESS_FAMILY_IPV4 or ADDRESS_FAMILY_UNSPECIFIED
+// was passed into to the host resolver.
+//
+//   Restricted to IPv4 address family:
+//     myIpAddress()
+//     dnsResolve()
+//
+//   Unrestricted address family:
+//     myIpAddressEx()
+//     dnsResolveEx()
+TEST(ProxyResolverJSBindingsTest, RestrictAddressFamily) {
+  MockSyncHostResolver* host_resolver = new MockSyncHostResolver;
+
+  // Get a hold of a DefaultJSBindings* (it is a hidden impl class).
+  scoped_ptr<ProxyResolverJSBindings> bindings(
+      ProxyResolverJSBindings::CreateDefault(host_resolver, NULL, NULL));
+
+  // Make it so requests resolve to particular address patterns based on family:
+  //  IPV4_ONLY --> 192.168.1.*
+  //  UNSPECIFIED --> 192.168.2.1
+  host_resolver->rules()->AddRuleForAddressFamily(
+      "foo", ADDRESS_FAMILY_IPV4, "192.168.1.1");
+  host_resolver->rules()->AddRuleForAddressFamily(
+      "*", ADDRESS_FAMILY_IPV4, "192.168.1.2");
+  host_resolver->rules()->AddRuleForAddressFamily(
+      "foo", ADDRESS_FAMILY_UNSPECIFIED, "192.168.2.1");
+  host_resolver->rules()->AddRuleForAddressFamily(
+      "*", ADDRESS_FAMILY_UNSPECIFIED, "192.168.2.2");
+
+  // Verify that our mock setups works as expected, and we get different results
+  // depending if the address family was IPV4_ONLY or not.
+  HostResolver::RequestInfo info(HostPortPair("foo", 80));
+  AddressList address_list;
+  EXPECT_EQ(OK, host_resolver->Resolve(info, &address_list, BoundNetLog()));
+  ASSERT_FALSE(address_list.empty());
+  EXPECT_EQ("192.168.2.1", address_list.front().ToStringWithoutPort());
+
+  info.set_address_family(ADDRESS_FAMILY_IPV4);
+  EXPECT_EQ(OK, host_resolver->Resolve(info, &address_list, BoundNetLog()));
+  ASSERT_FALSE(address_list.empty());
+  EXPECT_EQ("192.168.1.1", address_list.front().ToStringWithoutPort());
+
+  std::string ip_address;
+  // Now the actual test.
+#if !defined(OS_STARBOARD)
+  EXPECT_TRUE(bindings->MyIpAddress(&ip_address));
+  EXPECT_EQ("192.168.1.2", ip_address);  // IPv4 restricted.
+#endif
+
+  EXPECT_TRUE(bindings->DnsResolve("foo", &ip_address));
+  EXPECT_EQ("192.168.1.1", ip_address);  // IPv4 restricted.
+
+  EXPECT_TRUE(bindings->DnsResolve("foo2", &ip_address));
+  EXPECT_EQ("192.168.1.2", ip_address);  // IPv4 restricted.
+
+#if !defined(OS_STARBOARD)
+  EXPECT_TRUE(bindings->MyIpAddressEx(&ip_address));
+  EXPECT_EQ("192.168.2.2", ip_address);  // Unrestricted.
+#endif
+
+  EXPECT_TRUE(bindings->DnsResolveEx("foo", &ip_address));
+  EXPECT_EQ("192.168.2.1", ip_address);  // Unrestricted.
+
+  EXPECT_TRUE(bindings->DnsResolveEx("foo2", &ip_address));
+  EXPECT_EQ("192.168.2.2", ip_address);  // Unrestricted.
+}
+
+// Test that myIpAddressEx() and dnsResolveEx() both return a semi-colon
+// separated list of addresses (as opposed to the non-Ex versions which
+// just return the first result).
+TEST(ProxyResolverJSBindingsTest, ExFunctionsReturnList) {
+  SyncHostResolver* host_resolver =
+      new MockHostResolverWithMultipleResults;
+
+  // Get a hold of a DefaultJSBindings* (it is a hidden impl class).
+  scoped_ptr<ProxyResolverJSBindings> bindings(
+      ProxyResolverJSBindings::CreateDefault(host_resolver, NULL, NULL));
+
+  std::string ip_addresses;
+
+#if !defined(OS_STARBOARD)
+  EXPECT_TRUE(bindings->MyIpAddressEx(&ip_addresses));
+  EXPECT_EQ("192.168.1.1;172.22.34.1;200.100.1.2", ip_addresses);
+#endif
+
+  EXPECT_TRUE(bindings->DnsResolveEx("FOO", &ip_addresses));
+  EXPECT_EQ("192.168.1.1;172.22.34.1;200.100.1.2", ip_addresses);
+}
+
+TEST(ProxyResolverJSBindingsTest, PerRequestDNSCache) {
+  MockFailingHostResolver* host_resolver = new MockFailingHostResolver;
+
+  // Get a hold of a DefaultJSBindings* (it is a hidden impl class).
+  scoped_ptr<ProxyResolverJSBindings> bindings(
+      ProxyResolverJSBindings::CreateDefault(host_resolver, NULL, NULL));
+
+  std::string ip_address;
+
+  // Call DnsResolve() 4 times for the same hostname -- this should issue
+  // 4 separate calls to the underlying host resolver, since there is no
+  // current request context.
+  EXPECT_FALSE(bindings->DnsResolve("foo", &ip_address));
+  EXPECT_FALSE(bindings->DnsResolve("foo", &ip_address));
+  EXPECT_FALSE(bindings->DnsResolve("foo", &ip_address));
+  EXPECT_FALSE(bindings->DnsResolve("foo", &ip_address));
+  EXPECT_EQ(4, host_resolver->count());
+
+  host_resolver->ResetCount();
+
+  // Now setup a per-request context, and try the same experiment -- we
+  // expect the underlying host resolver to receive only 1 request this time,
+  // since it will service the others from the per-request DNS cache.
+  const unsigned kMaxCacheEntries = 50;
+  HostCache cache(kMaxCacheEntries);
+  ProxyResolverRequestContext context(NULL, &cache);
+  bindings->set_current_request_context(&context);
+
+  EXPECT_FALSE(bindings->DnsResolve("foo", &ip_address));
+  EXPECT_FALSE(bindings->DnsResolve("foo", &ip_address));
+  EXPECT_FALSE(bindings->DnsResolve("foo", &ip_address));
+  EXPECT_FALSE(bindings->DnsResolve("foo", &ip_address));
+  EXPECT_EQ(1, host_resolver->count());
+
+  host_resolver->ResetCount();
+
+  // The "Ex" version shares this same cache, however since the flags
+  // are different it won't reuse this particular entry.
+  EXPECT_FALSE(bindings->DnsResolveEx("foo", &ip_address));
+  EXPECT_EQ(1, host_resolver->count());
+  EXPECT_FALSE(bindings->DnsResolveEx("foo", &ip_address));
+  EXPECT_FALSE(bindings->DnsResolveEx("foo", &ip_address));
+  EXPECT_EQ(1, host_resolver->count());
+
+  bindings->set_current_request_context(NULL);
+}
+
+// Test that when a binding is called, it logs to the per-request NetLog.
+TEST(ProxyResolverJSBindingsTest, NetLog) {
+  MockFailingHostResolver* host_resolver = new MockFailingHostResolver;
+
+  CapturingNetLog global_log;
+
+  // Get a hold of a DefaultJSBindings* (it is a hidden impl class).
+  scoped_ptr<ProxyResolverJSBindings> bindings(
+      ProxyResolverJSBindings::CreateDefault(
+          host_resolver, &global_log, NULL));
+
+  // Attach a capturing NetLog as the current request's log stream.
+  CapturingNetLog log;
+  BoundNetLog bound_log(BoundNetLog::Make(&log, NetLog::SOURCE_NONE));
+  ProxyResolverRequestContext context(&bound_log, NULL);
+  bindings->set_current_request_context(&context);
+
+  std::string ip_address;
+  net::CapturingNetLog::CapturedEntryList entries;
+  log.GetEntries(&entries);
+  ASSERT_EQ(0u, entries.size());
+
+  // Call all the bindings. Each call should be logging something to
+  // our NetLog.
+
+  bindings->MyIpAddress(&ip_address);
+
+  log.GetEntries(&entries);
+  EXPECT_EQ(2u, entries.size());
+  EXPECT_TRUE(LogContainsBeginEvent(
+      entries, 0, NetLog::TYPE_PAC_JAVASCRIPT_MY_IP_ADDRESS));
+  EXPECT_TRUE(LogContainsEndEvent(
+      entries, 1, NetLog::TYPE_PAC_JAVASCRIPT_MY_IP_ADDRESS));
+
+  bindings->MyIpAddressEx(&ip_address);
+
+  log.GetEntries(&entries);
+  EXPECT_EQ(4u, entries.size());
+  EXPECT_TRUE(LogContainsBeginEvent(
+      entries, 2, NetLog::TYPE_PAC_JAVASCRIPT_MY_IP_ADDRESS_EX));
+  EXPECT_TRUE(LogContainsEndEvent(
+      entries, 3, NetLog::TYPE_PAC_JAVASCRIPT_MY_IP_ADDRESS_EX));
+
+  bindings->DnsResolve("foo", &ip_address);
+
+  log.GetEntries(&entries);
+  EXPECT_EQ(6u, entries.size());
+  EXPECT_TRUE(LogContainsBeginEvent(
+      entries, 4, NetLog::TYPE_PAC_JAVASCRIPT_DNS_RESOLVE));
+  EXPECT_TRUE(LogContainsEndEvent(
+      entries, 5, NetLog::TYPE_PAC_JAVASCRIPT_DNS_RESOLVE));
+
+  bindings->DnsResolveEx("foo", &ip_address);
+
+  log.GetEntries(&entries);
+  EXPECT_EQ(8u, entries.size());
+  EXPECT_TRUE(LogContainsBeginEvent(
+      entries, 6, NetLog::TYPE_PAC_JAVASCRIPT_DNS_RESOLVE_EX));
+  EXPECT_TRUE(LogContainsEndEvent(
+      entries, 7, NetLog::TYPE_PAC_JAVASCRIPT_DNS_RESOLVE_EX));
+
+  // Nothing has been emitted globally yet.
+  net::CapturingNetLog::CapturedEntryList global_log_entries;
+  global_log.GetEntries(&global_log_entries);
+  EXPECT_EQ(0u, global_log_entries.size());
+
+  bindings->OnError(30, string16());
+
+  log.GetEntries(&entries);
+  EXPECT_EQ(9u, entries.size());
+  EXPECT_TRUE(LogContainsEvent(
+      entries, 8, NetLog::TYPE_PAC_JAVASCRIPT_ERROR,
+      NetLog::PHASE_NONE));
+
+  // We also emit errors to the top-level log stream.
+  global_log.GetEntries(&global_log_entries);
+  EXPECT_EQ(1u, global_log_entries.size());
+  EXPECT_TRUE(LogContainsEvent(
+      global_log_entries, 0, NetLog::TYPE_PAC_JAVASCRIPT_ERROR,
+      NetLog::PHASE_NONE));
+
+  bindings->Alert(string16());
+
+  log.GetEntries(&entries);
+  EXPECT_EQ(10u, entries.size());
+  EXPECT_TRUE(LogContainsEvent(
+      entries, 9, NetLog::TYPE_PAC_JAVASCRIPT_ALERT,
+      NetLog::PHASE_NONE));
+
+  // We also emit javascript alerts to the top-level log stream.
+  global_log.GetEntries(&global_log_entries);
+  EXPECT_EQ(2u, global_log_entries.size());
+  EXPECT_TRUE(LogContainsEvent(
+      global_log_entries, 1, NetLog::TYPE_PAC_JAVASCRIPT_ALERT,
+      NetLog::PHASE_NONE));
+}
+
+}  // namespace
+
+}  // namespace net