summaryrefslogtreecommitdiff
path: root/chromium/net/proxy_resolution
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2019-02-13 15:05:36 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2019-02-14 10:33:47 +0000
commite684a3455bcc29a6e3e66a004e352dea4e1141e7 (patch)
treed55b4003bde34d7d05f558f02cfd82b2a66a7aac /chromium/net/proxy_resolution
parent2b94bfe47ccb6c08047959d1c26e392919550e86 (diff)
downloadqtwebengine-chromium-e684a3455bcc29a6e3e66a004e352dea4e1141e7.tar.gz
BASELINE: Update Chromium to 72.0.3626.110 and Ninja to 1.9.0
Change-Id: Ic57220b00ecc929a893c91f5cc552f5d3e99e922 Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/net/proxy_resolution')
-rw-r--r--chromium/net/proxy_resolution/dhcp_pac_file_adapter_fetcher_win.h6
-rw-r--r--chromium/net/proxy_resolution/dhcp_pac_file_fetcher.h6
-rw-r--r--chromium/net/proxy_resolution/dhcp_pac_file_fetcher_factory.h6
-rw-r--r--chromium/net/proxy_resolution/dhcp_pac_file_fetcher_win.h6
-rw-r--r--chromium/net/proxy_resolution/mock_pac_file_fetcher.h6
-rw-r--r--chromium/net/proxy_resolution/mojo_proxy_resolver_v8_tracing_bindings.h70
-rw-r--r--chromium/net/proxy_resolution/mojo_proxy_resolver_v8_tracing_bindings_unittest.cc61
-rw-r--r--chromium/net/proxy_resolution/pac_file_data.h6
-rw-r--r--chromium/net/proxy_resolution/pac_file_decider.h6
-rw-r--r--chromium/net/proxy_resolution/pac_file_fetcher.h6
-rw-r--r--chromium/net/proxy_resolution/pac_file_fetcher_impl.cc35
-rw-r--r--chromium/net/proxy_resolution/pac_file_fetcher_impl.h6
-rw-r--r--chromium/net/proxy_resolution/pac_file_fetcher_impl_unittest.cc12
-rw-r--r--chromium/net/proxy_resolution/pac_library.cc290
-rw-r--r--chromium/net/proxy_resolution/pac_library.h37
-rw-r--r--chromium/net/proxy_resolution/pac_library_unittest.cc618
-rw-r--r--chromium/net/proxy_resolution/parse_proxy_bypass_rules_fuzzer.cc11
-rw-r--r--chromium/net/proxy_resolution/proxy_bypass_rules.cc423
-rw-r--r--chromium/net/proxy_resolution/proxy_bypass_rules.h176
-rw-r--r--chromium/net/proxy_resolution/proxy_bypass_rules_unittest.cc305
-rw-r--r--chromium/net/proxy_resolution/proxy_config.cc14
-rw-r--r--chromium/net/proxy_resolution/proxy_config.h3
-rw-r--r--chromium/net/proxy_resolution/proxy_config_service_linux.cc24
-rw-r--r--chromium/net/proxy_resolution/proxy_config_service_linux.h5
-rw-r--r--chromium/net/proxy_resolution/proxy_config_service_linux_unittest.cc10
-rw-r--r--chromium/net/proxy_resolution/proxy_config_service_mac.cc3
-rw-r--r--chromium/net/proxy_resolution/proxy_resolution_service.cc4
-rw-r--r--chromium/net/proxy_resolution/proxy_resolution_service.h5
-rw-r--r--chromium/net/proxy_resolution/proxy_resolution_service_unittest.cc13
-rw-r--r--chromium/net/proxy_resolution/proxy_resolver_v8.cc7
-rw-r--r--chromium/net/proxy_resolution/proxy_resolver_v8_tracing.cc10
31 files changed, 1654 insertions, 536 deletions
diff --git a/chromium/net/proxy_resolution/dhcp_pac_file_adapter_fetcher_win.h b/chromium/net/proxy_resolution/dhcp_pac_file_adapter_fetcher_win.h
index 512f532ee4c..38492debfee 100644
--- a/chromium/net/proxy_resolution/dhcp_pac_file_adapter_fetcher_win.h
+++ b/chromium/net/proxy_resolution/dhcp_pac_file_adapter_fetcher_win.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef NET_PROXY_DHCP_PAC_FILE_ADAPTER_FETCHER_WIN_H_
-#define NET_PROXY_DHCP_PAC_FILE_ADAPTER_FETCHER_WIN_H_
+#ifndef NET_PROXY_RESOLUTION_DHCP_PAC_FILE_ADAPTER_FETCHER_WIN_H_
+#define NET_PROXY_RESOLUTION_DHCP_PAC_FILE_ADAPTER_FETCHER_WIN_H_
#include <stddef.h>
@@ -194,4 +194,4 @@ class NET_EXPORT_PRIVATE DhcpPacFileAdapterFetcher
} // namespace net
-#endif // NET_PROXY_DHCP_PAC_FILE_ADAPTER_FETCHER_WIN_H_
+#endif // NET_PROXY_RESOLUTION_DHCP_PAC_FILE_ADAPTER_FETCHER_WIN_H_
diff --git a/chromium/net/proxy_resolution/dhcp_pac_file_fetcher.h b/chromium/net/proxy_resolution/dhcp_pac_file_fetcher.h
index ee49706aa1b..433538458a1 100644
--- a/chromium/net/proxy_resolution/dhcp_pac_file_fetcher.h
+++ b/chromium/net/proxy_resolution/dhcp_pac_file_fetcher.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef NET_PROXY_DHCP_PAC_FILE_FETCHER_H_
-#define NET_PROXY_DHCP_PAC_FILE_FETCHER_H_
+#ifndef NET_PROXY_RESOLUTION_DHCP_PAC_FILE_FETCHER_H_
+#define NET_PROXY_RESOLUTION_DHCP_PAC_FILE_FETCHER_H_
#include "base/compiler_specific.h"
#include "base/macros.h"
@@ -111,4 +111,4 @@ class NET_EXPORT_PRIVATE DoNothingDhcpPacFileFetcher
} // namespace net
-#endif // NET_PROXY_DHCP_PAC_FILE_FETCHER_H_
+#endif // NET_PROXY_RESOLUTION_DHCP_PAC_FILE_FETCHER_H_
diff --git a/chromium/net/proxy_resolution/dhcp_pac_file_fetcher_factory.h b/chromium/net/proxy_resolution/dhcp_pac_file_fetcher_factory.h
index 832cea884be..79d8fae945f 100644
--- a/chromium/net/proxy_resolution/dhcp_pac_file_fetcher_factory.h
+++ b/chromium/net/proxy_resolution/dhcp_pac_file_fetcher_factory.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef NET_PROXY_DHCP_PAC_FILE_FETCHER_FACTORY_H_
-#define NET_PROXY_DHCP_PAC_FILE_FETCHER_FACTORY_H_
+#ifndef NET_PROXY_RESOLUTION_DHCP_PAC_FILE_FETCHER_FACTORY_H_
+#define NET_PROXY_RESOLUTION_DHCP_PAC_FILE_FETCHER_FACTORY_H_
#include <memory>
@@ -52,4 +52,4 @@ class NET_EXPORT DhcpPacFileFetcherFactory {
} // namespace net
-#endif // NET_PROXY_DHCP_PAC_FILE_FETCHER_FACTORY_H_
+#endif // NET_PROXY_RESOLUTION_DHCP_PAC_FILE_FETCHER_FACTORY_H_
diff --git a/chromium/net/proxy_resolution/dhcp_pac_file_fetcher_win.h b/chromium/net/proxy_resolution/dhcp_pac_file_fetcher_win.h
index f72fc6f3f81..1ad01e0cf7b 100644
--- a/chromium/net/proxy_resolution/dhcp_pac_file_fetcher_win.h
+++ b/chromium/net/proxy_resolution/dhcp_pac_file_fetcher_win.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef NET_PROXY_DHCP_PAC_FILE_FETCHER_WIN_H_
-#define NET_PROXY_DHCP_PAC_FILE_FETCHER_WIN_H_
+#ifndef NET_PROXY_RESOLUTION_DHCP_PAC_FILE_FETCHER_WIN_H_
+#define NET_PROXY_RESOLUTION_DHCP_PAC_FILE_FETCHER_WIN_H_
#include <memory>
#include <set>
@@ -198,4 +198,4 @@ class NET_EXPORT_PRIVATE DhcpPacFileFetcherWin
} // namespace net
-#endif // NET_PROXY_DHCP_PAC_FILE_FETCHER_WIN_H_
+#endif // NET_PROXY_RESOLUTION_DHCP_PAC_FILE_FETCHER_WIN_H_
diff --git a/chromium/net/proxy_resolution/mock_pac_file_fetcher.h b/chromium/net/proxy_resolution/mock_pac_file_fetcher.h
index fe44406d3fa..7213ad39a26 100644
--- a/chromium/net/proxy_resolution/mock_pac_file_fetcher.h
+++ b/chromium/net/proxy_resolution/mock_pac_file_fetcher.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef NET_PROXY_MOCK_PAC_FILE_FETCHER_H_
-#define NET_PROXY_MOCK_PAC_FILE_FETCHER_H_
+#ifndef NET_PROXY_RESOLUTION_MOCK_PAC_FILE_FETCHER_H_
+#define NET_PROXY_RESOLUTION_MOCK_PAC_FILE_FETCHER_H_
#include "base/compiler_specific.h"
#include "net/base/completion_once_callback.h"
@@ -50,4 +50,4 @@ class MockPacFileFetcher : public PacFileFetcher {
} // namespace net
-#endif // NET_PROXY_MOCK_PAC_FILE_FETCHER_H_
+#endif // NET_PROXY_RESOLUTION_MOCK_PAC_FILE_FETCHER_H_
diff --git a/chromium/net/proxy_resolution/mojo_proxy_resolver_v8_tracing_bindings.h b/chromium/net/proxy_resolution/mojo_proxy_resolver_v8_tracing_bindings.h
deleted file mode 100644
index 651c4f01940..00000000000
--- a/chromium/net/proxy_resolution/mojo_proxy_resolver_v8_tracing_bindings.h
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2015 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.
-
-#ifndef NET_PROXY_RESOLUTION_MOJO_PROXY_RESOLVER_V8_TRACING_BINDINGS_H_
-#define NET_PROXY_RESOLUTION_MOJO_PROXY_RESOLVER_V8_TRACING_BINDINGS_H_
-
-#include <utility>
-
-#include "base/strings/utf_string_conversions.h"
-#include "base/threading/thread_checker.h"
-#include "net/dns/host_resolver_mojo.h"
-#include "net/log/net_log_with_source.h"
-#include "net/proxy_resolution/proxy_resolver_v8_tracing.h"
-
-namespace net {
-
-// An implementation of ProxyResolverV8Tracing::Bindings that forwards requests
-// onto a Client mojo interface. Alert() and OnError() may be called from any
-// thread; when they are called from another thread, the calls are proxied to
-// the origin task runner. GetHostResolver() and GetNetLogWithSource() may only
-// be
-// called from the origin task runner.
-template <typename Client>
-class MojoProxyResolverV8TracingBindings
- : public ProxyResolverV8Tracing::Bindings,
- public HostResolverMojo::Impl {
- public:
- explicit MojoProxyResolverV8TracingBindings(Client* client)
- : client_(client), host_resolver_(this) {
- DCHECK(client_);
- }
-
- // ProxyResolverV8Tracing::Bindings overrides.
- void Alert(const base::string16& message) override {
- DCHECK(thread_checker_.CalledOnValidThread());
- client_->Alert(base::UTF16ToUTF8(message));
- }
-
- void OnError(int line_number, const base::string16& message) override {
- DCHECK(thread_checker_.CalledOnValidThread());
- client_->OnError(line_number, base::UTF16ToUTF8(message));
- }
-
- HostResolver* GetHostResolver() override {
- DCHECK(thread_checker_.CalledOnValidThread());
- return &host_resolver_;
- }
-
- NetLogWithSource GetNetLogWithSource() override {
- DCHECK(thread_checker_.CalledOnValidThread());
- return NetLogWithSource();
- }
-
- private:
- // HostResolverMojo::Impl override.
- void ResolveDns(std::unique_ptr<HostResolver::RequestInfo> request_info,
- interfaces::HostResolverRequestClientPtr client) override {
- DCHECK(thread_checker_.CalledOnValidThread());
- client_->ResolveDns(std::move(request_info), std::move(client));
- }
-
- base::ThreadChecker thread_checker_;
- Client* client_;
- HostResolverMojo host_resolver_;
-};
-
-} // namespace net
-
-#endif // NET_PROXY_RESOLUTION_MOJO_PROXY_RESOLVER_V8_TRACING_BINDINGS_H_
diff --git a/chromium/net/proxy_resolution/mojo_proxy_resolver_v8_tracing_bindings_unittest.cc b/chromium/net/proxy_resolution/mojo_proxy_resolver_v8_tracing_bindings_unittest.cc
deleted file mode 100644
index ffd37b145c4..00000000000
--- a/chromium/net/proxy_resolution/mojo_proxy_resolver_v8_tracing_bindings_unittest.cc
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2015 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_resolution/mojo_proxy_resolver_v8_tracing_bindings.h"
-
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/strings/utf_string_conversions.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-
-class MojoProxyResolverV8TracingBindingsTest : public testing::Test {
- public:
- MojoProxyResolverV8TracingBindingsTest() = default;
-
- void SetUp() override {
- bindings_.reset(new MojoProxyResolverV8TracingBindings<
- MojoProxyResolverV8TracingBindingsTest>(this));
- }
-
- void Alert(const std::string& message) { alerts_.push_back(message); }
-
- void OnError(int32_t line_number, const std::string& message) {
- errors_.push_back(std::make_pair(line_number, message));
- }
-
- void ResolveDns(std::unique_ptr<HostResolver::RequestInfo> request_info,
- interfaces::HostResolverRequestClientPtr client) {}
-
- protected:
- std::unique_ptr<MojoProxyResolverV8TracingBindings<
- MojoProxyResolverV8TracingBindingsTest>>
- bindings_;
-
- std::vector<std::string> alerts_;
- std::vector<std::pair<int, std::string>> errors_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(MojoProxyResolverV8TracingBindingsTest);
-};
-
-TEST_F(MojoProxyResolverV8TracingBindingsTest, Basic) {
- bindings_->Alert(base::ASCIIToUTF16("alert"));
- bindings_->OnError(-1, base::ASCIIToUTF16("error"));
-
- EXPECT_TRUE(bindings_->GetHostResolver());
- EXPECT_FALSE(bindings_->GetNetLogWithSource().net_log());
-
- ASSERT_EQ(1u, alerts_.size());
- EXPECT_EQ("alert", alerts_[0]);
- ASSERT_EQ(1u, errors_.size());
- EXPECT_EQ(-1, errors_[0].first);
- EXPECT_EQ("error", errors_[0].second);
-}
-
-} // namespace net
diff --git a/chromium/net/proxy_resolution/pac_file_data.h b/chromium/net/proxy_resolution/pac_file_data.h
index 5f75cf5b712..0a961fb3850 100644
--- a/chromium/net/proxy_resolution/pac_file_data.h
+++ b/chromium/net/proxy_resolution/pac_file_data.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef NET_PROXY_PAC_FILE_DATA_H_
-#define NET_PROXY_PAC_FILE_DATA_H_
+#ifndef NET_PROXY_RESOLUTION_PAC_FILE_DATA_H_
+#define NET_PROXY_RESOLUTION_PAC_FILE_DATA_H_
#include "base/memory/ref_counted.h"
#include "base/strings/string16.h"
@@ -64,4 +64,4 @@ class NET_EXPORT_PRIVATE PacFileData
} // namespace net
-#endif // NET_PROXY_PAC_FILE_DATA_H_
+#endif // NET_PROXY_RESOLUTION_PAC_FILE_DATA_H_
diff --git a/chromium/net/proxy_resolution/pac_file_decider.h b/chromium/net/proxy_resolution/pac_file_decider.h
index aaa0c25236b..af8438d414f 100644
--- a/chromium/net/proxy_resolution/pac_file_decider.h
+++ b/chromium/net/proxy_resolution/pac_file_decider.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef NET_PROXY_PAC_FILE_DECIDER_H_
-#define NET_PROXY_PAC_FILE_DECIDER_H_
+#ifndef NET_PROXY_RESOLUTION_PAC_FILE_DECIDER_H_
+#define NET_PROXY_RESOLUTION_PAC_FILE_DECIDER_H_
#include <stddef.h>
@@ -209,4 +209,4 @@ class NET_EXPORT_PRIVATE PacFileDecider {
} // namespace net
-#endif // NET_PROXY_PAC_FILE_DECIDER_H_
+#endif // NET_PROXY_RESOLUTION_PAC_FILE_DECIDER_H_
diff --git a/chromium/net/proxy_resolution/pac_file_fetcher.h b/chromium/net/proxy_resolution/pac_file_fetcher.h
index bd0ca21104d..f446e36a2d5 100644
--- a/chromium/net/proxy_resolution/pac_file_fetcher.h
+++ b/chromium/net/proxy_resolution/pac_file_fetcher.h
@@ -6,8 +6,8 @@
// script. It is specific to fetching a PAC script; enforces timeout, max-size,
// status code.
-#ifndef NET_PROXY_PAC_FILE_FETCHER_H_
-#define NET_PROXY_PAC_FILE_FETCHER_H_
+#ifndef NET_PROXY_RESOLUTION_PAC_FILE_FETCHER_H_
+#define NET_PROXY_RESOLUTION_PAC_FILE_FETCHER_H_
#include "base/strings/string16.h"
#include "net/base/completion_once_callback.h"
@@ -66,4 +66,4 @@ class NET_EXPORT_PRIVATE PacFileFetcher {
} // namespace net
-#endif // NET_PROXY_PAC_FILE_FETCHER_H_
+#endif // NET_PROXY_RESOLUTION_PAC_FILE_FETCHER_H_
diff --git a/chromium/net/proxy_resolution/pac_file_fetcher_impl.cc b/chromium/net/proxy_resolution/pac_file_fetcher_impl.cc
index 3b134a19e1b..41c67a80491 100644
--- a/chromium/net/proxy_resolution/pac_file_fetcher_impl.cc
+++ b/chromium/net/proxy_resolution/pac_file_fetcher_impl.cc
@@ -59,25 +59,44 @@ bool IsPacMimeType(const std::string& mime_type) {
return false;
}
+struct BomMapping {
+ base::StringPiece prefix;
+ const char* charset;
+};
+
+const BomMapping kBomMappings[] = {
+ {"\xFE\xFF", "utf-16be"},
+ {"\xFF\xFE", "utf-16le"},
+ {"\xEF\xBB\xBF", "utf-8"},
+};
+
// Converts |bytes| (which is encoded by |charset|) to UTF16, saving the resul
// to |*utf16|.
// If |charset| is empty, then we don't know what it was and guess.
void ConvertResponseToUTF16(const std::string& charset,
const std::string& bytes,
base::string16* utf16) {
- const char* codepage;
-
if (charset.empty()) {
- // Assume ISO-8859-1 if no charset was specified.
- codepage = kCharsetLatin1;
- } else {
- // Otherwise trust the charset that was provided.
- codepage = charset.c_str();
+ // Guess the charset by looking at the BOM.
+ base::StringPiece bytes_str(bytes);
+ for (const auto& bom : kBomMappings) {
+ if (bytes_str.starts_with(bom.prefix)) {
+ return ConvertResponseToUTF16(
+ bom.charset,
+ // Strip the BOM in the converted response.
+ bytes.substr(bom.prefix.size()), utf16);
+ }
+ }
+
+ // Otherwise assume ISO-8859-1 if no charset was specified.
+ return ConvertResponseToUTF16(kCharsetLatin1, bytes, utf16);
}
+ DCHECK(!charset.empty());
+
// Be generous in the conversion -- if any characters lie outside of |charset|
// (i.e. invalid), then substitute them with U+FFFD rather than failing.
- ConvertToUTF16WithSubstitutions(bytes, codepage, utf16);
+ ConvertToUTF16WithSubstitutions(bytes, charset.c_str(), utf16);
}
} // namespace
diff --git a/chromium/net/proxy_resolution/pac_file_fetcher_impl.h b/chromium/net/proxy_resolution/pac_file_fetcher_impl.h
index 448b0096eb2..a9e13db5196 100644
--- a/chromium/net/proxy_resolution/pac_file_fetcher_impl.h
+++ b/chromium/net/proxy_resolution/pac_file_fetcher_impl.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef NET_PROXY_PAC_FILE_FETCHER_IMPL_H_
-#define NET_PROXY_PAC_FILE_FETCHER_IMPL_H_
+#ifndef NET_PROXY_RESOLUTION_PAC_FILE_FETCHER_IMPL_H_
+#define NET_PROXY_RESOLUTION_PAC_FILE_FETCHER_IMPL_H_
#include <stddef.h>
@@ -167,4 +167,4 @@ class NET_EXPORT PacFileFetcherImpl : public PacFileFetcher,
} // namespace net
-#endif // NET_PROXY_PAC_FILE_FETCHER_IMPL_H_
+#endif // NET_PROXY_RESOLUTION_PAC_FILE_FETCHER_IMPL_H_
diff --git a/chromium/net/proxy_resolution/pac_file_fetcher_impl_unittest.cc b/chromium/net/proxy_resolution/pac_file_fetcher_impl_unittest.cc
index b658df80daa..9db5fce8c12 100644
--- a/chromium/net/proxy_resolution/pac_file_fetcher_impl_unittest.cc
+++ b/chromium/net/proxy_resolution/pac_file_fetcher_impl_unittest.cc
@@ -552,6 +552,18 @@ TEST_F(PacFileFetcherImplTest, Encodings) {
EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_EQ(ASCIIToUTF16("This was encoded as UTF-16BE.\n"), text);
}
+
+ // Test a response that lacks a charset, however starts with a UTF8 BOM.
+ {
+ GURL url(test_server_.GetURL("/utf8_bom"));
+ base::string16 text;
+ TestCompletionCallback callback;
+ int result = pac_fetcher->Fetch(url, &text, callback.callback(),
+ TRAFFIC_ANNOTATION_FOR_TESTS);
+ EXPECT_THAT(result, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
+ EXPECT_EQ(ASCIIToUTF16("/* UTF8 */\n"), text);
+ }
}
TEST_F(PacFileFetcherImplTest, DataURLs) {
diff --git a/chromium/net/proxy_resolution/pac_library.cc b/chromium/net/proxy_resolution/pac_library.cc
new file mode 100644
index 00000000000..69cb35fd06b
--- /dev/null
+++ b/chromium/net/proxy_resolution/pac_library.cc
@@ -0,0 +1,290 @@
+// Copyright 2018 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_resolution/pac_library.h"
+#include "net/base/address_list.h"
+#include "net/base/ip_address.h"
+#include "net/base/network_interfaces.h"
+#include "net/dns/host_resolver_proc.h"
+#include "net/socket/client_socket_factory.h"
+#include "net/socket/udp_client_socket.h"
+
+namespace net {
+
+namespace {
+
+enum class Mode {
+ kMyIpAddress,
+ kMyIpAddressEx,
+};
+
+// Helper used to accumulate and select the best candidate IP addresses.
+//
+// myIpAddress() is a broken API available to PAC scripts.
+// It has the problematic definition of:
+// "Returns the IP address of the host machine."
+//
+// This has ambiguity on what should happen for multi-homed hosts which may have
+// multiple IP addresses to choose from. To be unambiguous we would need to
+// know which hosts is going to be connected to, in order to use the outgoing
+// IP for that request.
+//
+// However at this point that is not known, as the proxy still hasn't been
+// decided.
+//
+// The strategy used here is to prioritize the IP address that would be used
+// for connecting to the public internet by testing which interface is used for
+// connecting to 8.8.8.8 and 2001:4860:4860::8888 (public IPs).
+//
+// If that fails, we will try resolving the machine's hostname, and also probing
+// for routes in the private IP space.
+//
+// Link-local IP addresses are not generally returned, however may be if no
+// other IP was found by the probes.
+class MyIpAddressImpl {
+ public:
+ MyIpAddressImpl() = default;
+
+ // Used for mocking the socket dependency.
+ void SetSocketFactoryForTest(ClientSocketFactory* socket_factory) {
+ override_socket_factory_ = socket_factory;
+ }
+
+ // Used for mocking the DNS dependency.
+ void SetDNSResultForTest(const AddressList& addrs) {
+ override_dns_result_ = std::make_unique<AddressList>(addrs);
+ }
+
+ IPAddressList Run(Mode mode) {
+ DCHECK(candidate_ips_.empty());
+ DCHECK(link_local_ips_.empty());
+ DCHECK(!done_);
+
+ mode_ = mode;
+
+ // Try several different methods to obtain IP addresses.
+ TestPublicInternetRoutes();
+ TestResolvingHostname();
+ TestPrivateIPRoutes();
+
+ return mode_ == Mode::kMyIpAddress ? GetResultForMyIpAddress()
+ : GetResultForMyIpAddressEx();
+ }
+
+ private:
+ // Adds |address| to the result.
+ void Add(const IPAddress& address) {
+ if (done_)
+ return;
+
+ // Don't consider loopback addresses (ex: 127.0.0.1). These can notably be
+ // returned when probing addresses associated with the hostname.
+ if (address.IsLoopback())
+ return;
+
+ if (!seen_ips_.insert(address).second)
+ return; // Duplicate IP address.
+
+ // Link-local addresses are only used as a last-resort if there are no
+ // better addresses.
+ if (address.IsLinkLocal()) {
+ link_local_ips_.push_back(address);
+ return;
+ }
+
+ // For legacy reasons IPv4 addresses are favored over IPv6 for myIpAddress()
+ // - https://crbug.com/905126 - so this only stops the search when a IPv4
+ // address is found.
+ if ((mode_ == Mode::kMyIpAddress) && address.IsIPv4())
+ done_ = true;
+
+ candidate_ips_.push_back(address);
+ }
+
+ IPAddressList GetResultForMyIpAddress() const {
+ DCHECK_EQ(Mode::kMyIpAddress, mode_);
+
+ if (!candidate_ips_.empty())
+ return GetSingleResultFavoringIPv4(candidate_ips_);
+
+ if (!link_local_ips_.empty())
+ return GetSingleResultFavoringIPv4(link_local_ips_);
+
+ return {};
+ }
+
+ IPAddressList GetResultForMyIpAddressEx() const {
+ DCHECK_EQ(Mode::kMyIpAddressEx, mode_);
+
+ if (!candidate_ips_.empty())
+ return candidate_ips_;
+
+ if (!link_local_ips_.empty()) {
+ // Note that only a single link-local address is returned here, even
+ // though multiple could be returned for this API. See
+ // http://crbug.com/905366 before expanding this.
+ return GetSingleResultFavoringIPv4(link_local_ips_);
+ }
+
+ return {};
+ }
+
+ // Tests what source IP address would be used for sending a UDP packet to the
+ // given destination IP. This does not hit the network and should be fast.
+ void TestRoute(const IPAddress& destination_ip) {
+ if (done_)
+ return;
+
+ ClientSocketFactory* socket_factory =
+ override_socket_factory_
+ ? override_socket_factory_
+ : net::ClientSocketFactory::GetDefaultFactory();
+
+ auto socket = socket_factory->CreateDatagramClientSocket(
+ net::DatagramSocket::DEFAULT_BIND, nullptr, net::NetLogSource());
+
+ IPEndPoint destination(destination_ip, /*port=*/80);
+
+ if (socket->Connect(destination) != OK)
+ return;
+
+ IPEndPoint source;
+ if (socket->GetLocalAddress(&source) != OK)
+ return;
+
+ Add(source.address());
+ }
+
+ void TestPublicInternetRoutes() {
+ if (done_)
+ return;
+
+ // 8.8.8.8 and 2001:4860:4860::8888 are Google DNS.
+ TestRoute(IPAddress(8, 8, 8, 8));
+ TestRoute(IPAddress(0x20, 0x01, 0x48, 0x60, 0x48, 0x60, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0x88, 0x88));
+
+ MarkAsDoneIfHaveCandidates();
+ }
+
+ // Marks the current search as done if candidate IPs have been found.
+ //
+ // This is used to stop exploring for IPs if any of the high-level tests find
+ // a match (i.e. either the public internet route test, or hostname test, or
+ // private route test found something).
+ //
+ // In the case of myIpAddressEx() this means it will be conservative in which
+ // IPs it returns and not enumerate the full set. See http://crbug.com/905366
+ // before expanding that policy.
+ void MarkAsDoneIfHaveCandidates() {
+ if (!candidate_ips_.empty())
+ done_ = true;
+ }
+
+ void TestPrivateIPRoutes() {
+ if (done_)
+ return;
+
+ // Representative IP from each range in RFC 1918.
+ TestRoute(IPAddress(10, 0, 0, 0));
+ TestRoute(IPAddress(172, 16, 0, 0));
+ TestRoute(IPAddress(192, 168, 0, 0));
+
+ // Representative IP for Unique Local Address (FC00::/7).
+ TestRoute(IPAddress(0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
+
+ MarkAsDoneIfHaveCandidates();
+ }
+
+ void TestResolvingHostname() {
+ if (done_)
+ return;
+
+ AddressList addrlist;
+
+ int resolver_error;
+
+ if (override_dns_result_) {
+ addrlist = *override_dns_result_;
+ resolver_error = addrlist.empty() ? ERR_NAME_NOT_RESOLVED : OK;
+ } else {
+ resolver_error = SystemHostResolverCall(
+ GetHostName(), AddressFamily::ADDRESS_FAMILY_UNSPECIFIED, 0,
+ &addrlist,
+ /*os_error=*/nullptr);
+ }
+
+ if (resolver_error != OK)
+ return;
+
+ for (const auto& e : addrlist.endpoints())
+ Add(e.address());
+
+ MarkAsDoneIfHaveCandidates();
+ }
+
+ static IPAddressList GetSingleResultFavoringIPv4(const IPAddressList& ips) {
+ for (const auto& ip : ips) {
+ if (ip.IsIPv4())
+ return {ip};
+ }
+
+ if (!ips.empty())
+ return {ips.front()};
+
+ return {};
+ }
+
+ std::set<IPAddress> seen_ips_;
+
+ // The preferred ordered candidate IPs so far.
+ IPAddressList candidate_ips_;
+
+ // The link-local IP addresses seen so far (not part of |candidate_ips_|).
+ IPAddressList link_local_ips_;
+
+ // The operation being carried out.
+ Mode mode_;
+
+ // Whether the search for results has completed.
+ //
+ // Once "done", calling Add() will not change the final result. This is used
+ // to short-circuit early.
+ bool done_ = false;
+
+ ClientSocketFactory* override_socket_factory_ = nullptr;
+ std::unique_ptr<AddressList> override_dns_result_;
+
+ DISALLOW_COPY_AND_ASSIGN(MyIpAddressImpl);
+};
+
+} // namespace
+
+IPAddressList PacMyIpAddress() {
+ MyIpAddressImpl impl;
+ return impl.Run(Mode::kMyIpAddress);
+}
+
+IPAddressList PacMyIpAddressEx() {
+ MyIpAddressImpl impl;
+ return impl.Run(Mode::kMyIpAddressEx);
+}
+
+IPAddressList PacMyIpAddressForTest(ClientSocketFactory* socket_factory,
+ const AddressList& dns_result) {
+ MyIpAddressImpl impl;
+ impl.SetSocketFactoryForTest(socket_factory);
+ impl.SetDNSResultForTest(dns_result);
+ return impl.Run(Mode::kMyIpAddress);
+}
+
+IPAddressList PacMyIpAddressExForTest(ClientSocketFactory* socket_factory,
+ const AddressList& dns_result) {
+ MyIpAddressImpl impl;
+ impl.SetSocketFactoryForTest(socket_factory);
+ impl.SetDNSResultForTest(dns_result);
+ return impl.Run(Mode::kMyIpAddressEx);
+}
+
+} // namespace net
diff --git a/chromium/net/proxy_resolution/pac_library.h b/chromium/net/proxy_resolution/pac_library.h
new file mode 100644
index 00000000000..8f58980bf5e
--- /dev/null
+++ b/chromium/net/proxy_resolution/pac_library.h
@@ -0,0 +1,37 @@
+// Copyright 2018 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.
+
+#ifndef NET_PROXY_RESOLUTION_PAC_LIBRARY_H_
+#define NET_PROXY_RESOLUTION_PAC_LIBRARY_H_
+
+#include "net/base/ip_address.h"
+#include "net/base/net_export.h"
+
+// TODO(eroman): Move other PAC library support functions into here.
+
+namespace net {
+
+class ClientSocketFactory;
+class AddressList;
+
+// Implementations for myIpAddress() and myIpAddressEx() function calls
+// available in the PAC environment. These are expected to be called on a worker
+// thread as they may block.
+//
+// Do not use these outside of PAC as they are broken APIs. See comments in the
+// implementation file for details.
+NET_EXPORT_PRIVATE IPAddressList PacMyIpAddress();
+NET_EXPORT_PRIVATE IPAddressList PacMyIpAddressEx();
+
+// Test exposed variants that allows mocking the UDP and DNS dependencies.
+NET_EXPORT_PRIVATE IPAddressList
+PacMyIpAddressForTest(ClientSocketFactory* socket_factory,
+ const AddressList& dns_result);
+NET_EXPORT_PRIVATE IPAddressList
+PacMyIpAddressExForTest(ClientSocketFactory* socket_factory,
+ const AddressList& dns_result);
+
+} // namespace net
+
+#endif // NET_PROXY_RESOLUTION_PAC_LIBRARY_H_
diff --git a/chromium/net/proxy_resolution/pac_library_unittest.cc b/chromium/net/proxy_resolution/pac_library_unittest.cc
new file mode 100644
index 00000000000..d4057830e50
--- /dev/null
+++ b/chromium/net/proxy_resolution/pac_library_unittest.cc
@@ -0,0 +1,618 @@
+// Copyright 2018 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_resolution/pac_library.h"
+
+#include "net/base/address_list.h"
+#include "net/base/net_errors.h"
+#include "net/base/network_interfaces.h"
+#include "net/log/net_log_with_source.h"
+#include "net/socket/client_socket_factory.h"
+#include "net/socket/client_socket_handle.h"
+#include "net/socket/datagram_client_socket.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace {
+
+// Helper for verifying whether the address list returned by myIpAddress() /
+// myIpAddressEx() looks correct.
+void VerifyActualMyIpAddresses(const IPAddressList& test_list) {
+ // Enumerate all of the IP addresses for the system (skipping loopback and
+ // link-local ones). This is used as a reference implementation to check
+ // whether |test_list| (which was obtained using a different strategy) looks
+ // correct.
+ std::set<IPAddress> candidates;
+ NetworkInterfaceList networks;
+ GetNetworkList(&networks, EXCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES);
+ for (const auto& network : networks) {
+ if (network.address.IsLinkLocal() || network.address.IsLoopback())
+ continue;
+ candidates.insert(network.address);
+ }
+
+ // Ordinarily the machine running this test will have an IP address. However
+ // for some bot configurations (notably Android) that may not be the case.
+ EXPECT_EQ(candidates.empty(), test_list.empty());
+
+ // |test_list| should be a subset of |candidates|.
+ for (const auto& ip : test_list)
+ EXPECT_EQ(1u, candidates.count(ip));
+}
+
+// Tests for PacMyIpAddress() and PacMyIpAddressEx().
+TEST(PacLibraryTest, ActualPacMyIpAddress) {
+ auto my_ip_addresses = PacMyIpAddress();
+
+ VerifyActualMyIpAddresses(my_ip_addresses);
+}
+
+TEST(PacLibraryTest, ActualPacMyIpAddressEx) {
+ VerifyActualMyIpAddresses(PacMyIpAddressEx());
+}
+
+IPAddress CreateIPAddress(base::StringPiece literal) {
+ IPAddress result;
+ if (!result.AssignFromIPLiteral(literal)) {
+ ADD_FAILURE() << "Failed parsing IP: " << literal;
+ return IPAddress();
+ }
+ return result;
+}
+
+AddressList CreateAddressList(
+ const std::vector<base::StringPiece>& ip_literals) {
+ AddressList result;
+ for (const auto& ip : ip_literals)
+ result.push_back(IPEndPoint(CreateIPAddress(ip), 8080));
+ return result;
+}
+
+class MockUDPSocket : public DatagramClientSocket {
+ public:
+ MockUDPSocket(const IPAddress& peer_ip,
+ const IPAddress& local_ip,
+ Error connect_error)
+ : peer_ip_(peer_ip), local_ip_(local_ip), connect_error_(connect_error) {}
+
+ ~MockUDPSocket() override = default;
+
+ // Socket implementation.
+ int Read(IOBuffer* buf,
+ int buf_len,
+ CompletionOnceCallback callback) override {
+ ADD_FAILURE() << "Called Read()";
+ return ERR_UNEXPECTED;
+ }
+ int Write(IOBuffer* buf,
+ int buf_len,
+ CompletionOnceCallback callback,
+ const NetworkTrafficAnnotationTag& traffic_annotation) override {
+ ADD_FAILURE() << "Called Read()";
+ return ERR_UNEXPECTED;
+ }
+ int WriteAsync(
+ DatagramBuffers buffers,
+ CompletionOnceCallback callback,
+ const NetworkTrafficAnnotationTag& traffic_annotation) override {
+ ADD_FAILURE() << "Called WriteAsync()";
+ return ERR_UNEXPECTED;
+ }
+ int WriteAsync(
+ const char* buffer,
+ size_t buf_len,
+ CompletionOnceCallback callback,
+ const NetworkTrafficAnnotationTag& traffic_annotation) override {
+ ADD_FAILURE() << "Called WriteAsync()";
+ return ERR_UNEXPECTED;
+ }
+ DatagramBuffers GetUnwrittenBuffers() override {
+ ADD_FAILURE() << "Called GetUnwrittenBuffers()";
+ return DatagramBuffers();
+ }
+ int SetReceiveBufferSize(int32_t size) override {
+ ADD_FAILURE() << "Called SetReceiveBufferSize()";
+ return ERR_UNEXPECTED;
+ }
+ int SetSendBufferSize(int32_t size) override {
+ ADD_FAILURE() << "Called SetSendBufferSize()";
+ return ERR_UNEXPECTED;
+ }
+ int SetDoNotFragment() override {
+ ADD_FAILURE() << "Called SetDoNotFragment()";
+ return ERR_UNEXPECTED;
+ }
+ // DatagramSocket implementation.
+ void Close() override { ADD_FAILURE() << "Called Close()"; }
+ int GetPeerAddress(IPEndPoint* address) const override {
+ ADD_FAILURE() << "Called GetPeerAddress()";
+ return ERR_UNEXPECTED;
+ }
+ int GetLocalAddress(IPEndPoint* address) const override {
+ if (connect_error_ != OK)
+ return connect_error_;
+
+ *address = IPEndPoint(local_ip_, 8080);
+ return OK;
+ }
+ void UseNonBlockingIO() override {
+ ADD_FAILURE() << "Called UseNonBlockingIO()";
+ }
+ void SetWriteAsyncEnabled(bool enabled) override {
+ ADD_FAILURE() << "Called SetWriteAsyncEnabled()";
+ }
+ void SetMaxPacketSize(size_t max_packet_size) override {
+ ADD_FAILURE() << "Called SetWriteAsyncEnabled()";
+ }
+ bool WriteAsyncEnabled() override {
+ ADD_FAILURE() << "Called WriteAsyncEnabled()";
+ return false;
+ }
+ void SetWriteMultiCoreEnabled(bool enabled) override {
+ ADD_FAILURE() << "Called SetWriteMultiCoreEnabled()";
+ }
+ void SetSendmmsgEnabled(bool enabled) override {
+ ADD_FAILURE() << "Called SetSendmmsgEnabled()";
+ }
+ void SetWriteBatchingActive(bool active) override {
+ ADD_FAILURE() << "Called SetWriteBatchingActive()";
+ }
+ const NetLogWithSource& NetLog() const override {
+ ADD_FAILURE() << "Called NetLog()";
+ return net_log_;
+ }
+
+ // DatagramClientSocket implementation.
+ int Connect(const IPEndPoint& address) override {
+ EXPECT_EQ(peer_ip_.ToString(), address.address().ToString());
+ return connect_error_;
+ }
+ int ConnectUsingNetwork(NetworkChangeNotifier::NetworkHandle network,
+ const IPEndPoint& address) override {
+ ADD_FAILURE() << "Called ConnectUsingNetwork()";
+ return ERR_UNEXPECTED;
+ }
+ int ConnectUsingDefaultNetwork(const IPEndPoint& address) override {
+ ADD_FAILURE() << "Called ConnectUsingDefaultNetwork()";
+ return ERR_UNEXPECTED;
+ }
+ NetworkChangeNotifier::NetworkHandle GetBoundNetwork() const override {
+ ADD_FAILURE() << "Called GetBoundNetwork()";
+ return network_;
+ }
+ void ApplySocketTag(const SocketTag& tag) override {
+ ADD_FAILURE() << "Called ApplySocketTag()";
+ }
+ void SetMsgConfirm(bool confirm) override {
+ ADD_FAILURE() << "Called SetMsgConfirm()";
+ }
+
+ private:
+ NetLogWithSource net_log_;
+ NetworkChangeNotifier::NetworkHandle network_;
+
+ IPAddress peer_ip_;
+ IPAddress local_ip_;
+ Error connect_error_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockUDPSocket);
+};
+
+class MockSocketFactory : public ClientSocketFactory {
+ public:
+ MockSocketFactory() = default;
+
+ void AddUDPConnectSuccess(base::StringPiece peer_ip_literal,
+ base::StringPiece local_ip_literal) {
+ auto peer_ip = CreateIPAddress(peer_ip_literal);
+ auto local_ip = CreateIPAddress(local_ip_literal);
+
+ // The address family of local and peer IP must match.
+ ASSERT_EQ(peer_ip.size(), local_ip.size());
+
+ udp_sockets_.push_back(std::make_unique<MockUDPSocket>(
+ peer_ip, local_ip, OK));
+ }
+
+ void AddUDPConnectFailure(base::StringPiece peer_ip) {
+ udp_sockets_.push_back(std::make_unique<MockUDPSocket>(
+ CreateIPAddress(peer_ip), IPAddress(), ERR_ADDRESS_UNREACHABLE));
+ }
+
+ ~MockSocketFactory() override {
+ EXPECT_EQ(0u, udp_sockets_.size())
+ << "Not all of the mock sockets were consumed.";
+ }
+
+ // ClientSocketFactory
+ std::unique_ptr<DatagramClientSocket> CreateDatagramClientSocket(
+ DatagramSocket::BindType bind_type,
+ NetLog* net_log,
+ const NetLogSource& source) override {
+ if (udp_sockets_.empty()) {
+ ADD_FAILURE() << "Not enough mock UDP sockets";
+ return nullptr;
+ }
+
+ auto result = std::move(udp_sockets_.front());
+ udp_sockets_.erase(udp_sockets_.begin());
+ return result;
+ }
+ std::unique_ptr<TransportClientSocket> CreateTransportClientSocket(
+ const AddressList& addresses,
+ std::unique_ptr<SocketPerformanceWatcher> socket_performance_watcher,
+ NetLog* net_log,
+ const NetLogSource& source) override {
+ ADD_FAILURE() << "Called CreateTransportClientSocket()";
+ return nullptr;
+ }
+ std::unique_ptr<SSLClientSocket> CreateSSLClientSocket(
+ std::unique_ptr<ClientSocketHandle> transport_socket,
+ const HostPortPair& host_and_port,
+ const SSLConfig& ssl_config,
+ const SSLClientSocketContext& context) override {
+ ADD_FAILURE() << "Called CreateSSLClientSocket()";
+ return nullptr;
+ }
+ std::unique_ptr<ProxyClientSocket> CreateProxyClientSocket(
+ std::unique_ptr<ClientSocketHandle> transport_socket,
+ const std::string& user_agent,
+ const HostPortPair& endpoint,
+ HttpAuthController* http_auth_controller,
+ bool tunnel,
+ bool using_spdy,
+ NextProto negotiated_protocol,
+ bool is_https_proxy,
+ const NetworkTrafficAnnotationTag& traffic_annotation) override {
+ ADD_FAILURE() << "Called CreateProxyClientSocket()";
+ return nullptr;
+ }
+ void ClearSSLSessionCache() override {
+ ADD_FAILURE() << "Called ClearSSLSessionCache()";
+ }
+
+ private:
+ std::vector<std::unique_ptr<MockUDPSocket>> udp_sockets_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockSocketFactory);
+};
+
+// Tests myIpAddress() when there is a route to 8.8.8.8.
+TEST(PacLibraryTest, PacMyIpAddress8888) {
+ MockSocketFactory factory;
+ factory.AddUDPConnectSuccess("8.8.8.8", "192.168.1.1");
+
+ auto result = PacMyIpAddressForTest(&factory, {});
+ ASSERT_EQ(1u, result.size());
+ EXPECT_EQ("192.168.1.1", result.front().ToString());
+}
+
+// Tests myIpAddress() when there is no route to 8.8.8.8, but there is one to
+// 2001:4860:4860::8888.
+TEST(PacLibraryTest, PacMyIpAddress2001) {
+ MockSocketFactory factory;
+ factory.AddUDPConnectFailure("8.8.8.8");
+ factory.AddUDPConnectSuccess("2001:4860:4860::8888", "2001::beef");
+
+ AddressList dns_result;
+
+ auto result = PacMyIpAddressForTest(&factory, dns_result);
+ ASSERT_EQ(1u, result.size());
+ EXPECT_EQ("2001::beef", result.front().ToString());
+}
+
+// Tests myIpAddress() when there is no route to 8.8.8.8, no route to
+// 2001:4860:4860::8888, however getaddrinfo(gethostname()) finds results. Most
+// of those results are skipped over, and the IPv4 one is favored.
+TEST(PacLibraryTest, PacMyIpAddressHostname) {
+ MockSocketFactory factory;
+ factory.AddUDPConnectFailure("8.8.8.8");
+ factory.AddUDPConnectFailure("2001:4860:4860::8888");
+
+ AddressList dns_result = CreateAddressList({
+ "169.254.13.16", "127.0.0.1", "::1", "fe89::beef", "2001::f001",
+ "178.1.99.3", "192.168.1.3",
+ });
+
+ auto result = PacMyIpAddressForTest(&factory, dns_result);
+ ASSERT_EQ(1u, result.size());
+ EXPECT_EQ("178.1.99.3", result.front().ToString());
+}
+
+// Tests myIpAddress() when there is no route to 8.8.8.8, no route to
+// 2001:4860:4860::8888, however getaddrinfo(gethostname()) finds multiple IPv6
+// results.
+TEST(PacLibraryTest, PacMyIpAddressHostnameAllIPv6) {
+ MockSocketFactory factory;
+ factory.AddUDPConnectFailure("8.8.8.8");
+ factory.AddUDPConnectFailure("2001:4860:4860::8888");
+
+ AddressList dns_result =
+ CreateAddressList({"::1", "2001::f001", "2001::f00d", "169.254.0.6"});
+
+ auto result = PacMyIpAddressForTest(&factory, dns_result);
+ ASSERT_EQ(1u, result.size());
+ EXPECT_EQ("2001::f001", result.front().ToString());
+}
+
+// Tests myIpAddress() when there is no route to 8.8.8.8, no route to
+// 2001:4860:4860::8888, no acceptable result in getaddrinfo(gethostname()),
+// however there is a route for private address.
+TEST(PacLibraryTest, PacMyIpAddressPrivateIPv4) {
+ MockSocketFactory factory;
+ factory.AddUDPConnectFailure("8.8.8.8");
+ factory.AddUDPConnectFailure("2001:4860:4860::8888");
+
+ AddressList dns_result = CreateAddressList({
+ "169.254.13.16", "127.0.0.1", "::1", "fe89::beef",
+ });
+
+ factory.AddUDPConnectSuccess("10.0.0.0", "127.0.0.1");
+ factory.AddUDPConnectFailure("172.16.0.0");
+ factory.AddUDPConnectSuccess("192.168.0.0", "63.31.9.8");
+
+ auto result = PacMyIpAddressForTest(&factory, dns_result);
+ ASSERT_EQ(1u, result.size());
+ EXPECT_EQ("63.31.9.8", result.front().ToString());
+}
+
+// Tests myIpAddress() when there is no route to 8.8.8.8, no route to
+// 2001:4860:4860::8888, no acceptable result in getaddrinfo(gethostname()),
+// however there is a route for private address.
+TEST(PacLibraryTest, PacMyIpAddressPrivateIPv6) {
+ MockSocketFactory factory;
+ factory.AddUDPConnectFailure("8.8.8.8");
+ factory.AddUDPConnectFailure("2001:4860:4860::8888");
+
+ AddressList dns_result;
+
+ factory.AddUDPConnectSuccess("10.0.0.0", "127.0.0.1");
+ factory.AddUDPConnectFailure("172.16.0.0");
+ factory.AddUDPConnectFailure("192.168.0.0");
+ factory.AddUDPConnectSuccess("FC00::", "2001::7777");
+
+ auto result = PacMyIpAddressForTest(&factory, dns_result);
+ ASSERT_EQ(1u, result.size());
+ EXPECT_EQ("2001::7777", result.front().ToString());
+}
+
+// Tests myIpAddress() when there are no routes, and getaddrinfo(gethostname())
+// fails.
+TEST(PacLibraryTest, PacMyIpAddressAllFail) {
+ MockSocketFactory factory;
+ factory.AddUDPConnectFailure("8.8.8.8");
+ factory.AddUDPConnectFailure("2001:4860:4860::8888");
+
+ AddressList dns_result;
+
+ factory.AddUDPConnectFailure("10.0.0.0");
+ factory.AddUDPConnectFailure("172.16.0.0");
+ factory.AddUDPConnectFailure("192.168.0.0");
+ factory.AddUDPConnectFailure("FC00::");
+
+ auto result = PacMyIpAddressForTest(&factory, dns_result);
+ EXPECT_EQ(0u, result.size());
+}
+
+// Tests myIpAddress() when there are no routes, and
+// getaddrinfo(gethostname()) only returns loopback.
+TEST(PacLibraryTest, PacMyIpAddressAllFailOrLoopback) {
+ MockSocketFactory factory;
+ factory.AddUDPConnectFailure("8.8.8.8");
+ factory.AddUDPConnectFailure("2001:4860:4860::8888");
+
+ AddressList dns_result = CreateAddressList({"127.0.0.1", "::1"});
+
+ factory.AddUDPConnectFailure("10.0.0.0");
+ factory.AddUDPConnectFailure("172.16.0.0");
+ factory.AddUDPConnectFailure("192.168.0.0");
+ factory.AddUDPConnectFailure("FC00::");
+
+ auto result = PacMyIpAddressForTest(&factory, dns_result);
+ EXPECT_EQ(0u, result.size());
+}
+
+// Tests myIpAddress() when there is only an IPv6 link-local address.
+TEST(PacLibraryTest, PacMyIpAddressAllFailHasLinkLocal) {
+ MockSocketFactory factory;
+ factory.AddUDPConnectFailure("8.8.8.8");
+ factory.AddUDPConnectFailure("2001:4860:4860::8888");
+
+ AddressList dns_result =
+ CreateAddressList({"127.0.0.1", "::1", "fe81::8881"});
+
+ factory.AddUDPConnectFailure("10.0.0.0");
+ factory.AddUDPConnectFailure("172.16.0.0");
+ factory.AddUDPConnectFailure("192.168.0.0");
+ factory.AddUDPConnectFailure("FC00::");
+
+ auto result = PacMyIpAddressForTest(&factory, dns_result);
+ ASSERT_EQ(1u, result.size());
+ EXPECT_EQ("fe81::8881", result.front().ToString());
+}
+
+// Tests myIpAddress() when there are only link-local addresses. The IPv4
+// link-local address is favored.
+TEST(PacLibraryTest, PacMyIpAddressAllFailHasLinkLocalFavorIPv4) {
+ MockSocketFactory factory;
+ factory.AddUDPConnectFailure("8.8.8.8");
+ factory.AddUDPConnectFailure("2001:4860:4860::8888");
+
+ AddressList dns_result =
+ CreateAddressList({"127.0.0.1", "::1", "fe81::8881", "169.254.89.133"});
+
+ factory.AddUDPConnectFailure("10.0.0.0");
+ factory.AddUDPConnectFailure("172.16.0.0");
+ factory.AddUDPConnectFailure("192.168.0.0");
+ factory.AddUDPConnectFailure("FC00::");
+
+ auto result = PacMyIpAddressForTest(&factory, dns_result);
+ ASSERT_EQ(1u, result.size());
+ EXPECT_EQ("169.254.89.133", result.front().ToString());
+}
+
+// Tests myIpAddressEx() when there is a route to 8.8.8.8 but not one to
+// 2001:4860:4860::8888
+TEST(PacLibraryTest, PacMyIpAddressEx8888) {
+ MockSocketFactory factory;
+ factory.AddUDPConnectSuccess("8.8.8.8", "192.168.1.1");
+ factory.AddUDPConnectFailure("2001:4860:4860::8888");
+
+ auto result = PacMyIpAddressExForTest(&factory, {});
+ ASSERT_EQ(1u, result.size());
+ EXPECT_EQ("192.168.1.1", result.front().ToString());
+}
+
+// Tests myIpAddressEx() when there is a route to 2001:4860:4860::8888 but
+// not 8.8.8.8.
+TEST(PacLibraryTest, PacMyIpAddressEx2001) {
+ MockSocketFactory factory;
+ factory.AddUDPConnectFailure("8.8.8.8");
+ factory.AddUDPConnectSuccess("2001:4860:4860::8888", "2001::3333");
+
+ AddressList dns_result;
+
+ auto result = PacMyIpAddressExForTest(&factory, dns_result);
+ ASSERT_EQ(1u, result.size());
+ EXPECT_EQ("2001::3333", result.front().ToString());
+}
+
+// Tests myIpAddressEx() when there is a route to both 8.8.8.8 and
+// 2001:4860:4860::8888.
+TEST(PacLibraryTest, PacMyIpAddressEx8888And2001) {
+ MockSocketFactory factory;
+ factory.AddUDPConnectSuccess("8.8.8.8", "192.168.17.8");
+ factory.AddUDPConnectSuccess("2001:4860:4860::8888", "2001::8333");
+
+ AddressList dns_result;
+
+ auto result = PacMyIpAddressExForTest(&factory, dns_result);
+ ASSERT_EQ(2u, result.size());
+ EXPECT_EQ("192.168.17.8", result.front().ToString());
+ EXPECT_EQ("2001::8333", result.back().ToString());
+}
+
+// Tests myIpAddressEx() when there is no route to 8.8.8.8, no route to
+// 2001:4860:4860::8888, however getaddrinfo(gethostname()) finds results. Some
+// of those results are skipped due to being link-local and loopback.
+TEST(PacLibraryTest, PacMyIpAddressExHostname) {
+ MockSocketFactory factory;
+ factory.AddUDPConnectFailure("8.8.8.8");
+ factory.AddUDPConnectFailure("2001:4860:4860::8888");
+
+ AddressList dns_result = CreateAddressList({
+ "169.254.13.16", "::1", "fe89::beef", "2001::bebe", "178.1.99.3",
+ "127.0.0.1", "192.168.1.3",
+ });
+
+ auto result = PacMyIpAddressExForTest(&factory, dns_result);
+ ASSERT_EQ(3u, result.size());
+ EXPECT_EQ("2001::bebe", result[0].ToString());
+ EXPECT_EQ("178.1.99.3", result[1].ToString());
+ EXPECT_EQ("192.168.1.3", result[2].ToString());
+}
+
+// Tests myIpAddressEx() when routes are found for private IP space.
+TEST(PacLibraryTest, PacMyIpAddressExPrivateDuplicates) {
+ MockSocketFactory factory;
+ factory.AddUDPConnectFailure("8.8.8.8");
+ factory.AddUDPConnectFailure("2001:4860:4860::8888");
+
+ AddressList dns_result;
+
+ factory.AddUDPConnectSuccess("10.0.0.0", "192.168.3.3");
+ factory.AddUDPConnectSuccess("172.16.0.0", "192.168.3.4");
+ factory.AddUDPConnectSuccess("192.168.0.0", "192.168.3.3");
+ factory.AddUDPConnectSuccess("FC00::", "2001::beef");
+
+ auto result = PacMyIpAddressExForTest(&factory, dns_result);
+
+ // Note that 192.168.3.3. was probed twice, but only added once to the final
+ // result.
+ ASSERT_EQ(3u, result.size());
+ EXPECT_EQ("192.168.3.3", result[0].ToString());
+ EXPECT_EQ("192.168.3.4", result[1].ToString());
+ EXPECT_EQ("2001::beef", result[2].ToString());
+}
+
+// Tests myIpAddressEx() when there are no routes, and
+// getaddrinfo(gethostname()) fails.
+TEST(PacLibraryTest, PacMyIpAddressExAllFail) {
+ MockSocketFactory factory;
+ factory.AddUDPConnectFailure("8.8.8.8");
+ factory.AddUDPConnectFailure("2001:4860:4860::8888");
+
+ AddressList dns_result;
+
+ factory.AddUDPConnectFailure("10.0.0.0");
+ factory.AddUDPConnectFailure("172.16.0.0");
+ factory.AddUDPConnectFailure("192.168.0.0");
+ factory.AddUDPConnectFailure("FC00::");
+
+ auto result = PacMyIpAddressExForTest(&factory, dns_result);
+ EXPECT_EQ(0u, result.size());
+}
+
+// Tests myIpAddressEx() when there are only IPv6 link-local address.
+TEST(PacLibraryTest, PacMyIpAddressExAllFailHasLinkLocal) {
+ MockSocketFactory factory;
+ factory.AddUDPConnectFailure("8.8.8.8");
+ factory.AddUDPConnectFailure("2001:4860:4860::8888");
+
+ AddressList dns_result =
+ CreateAddressList({"127.0.0.1", "::1", "fe81::8881", "fe80::8899"});
+
+ factory.AddUDPConnectFailure("10.0.0.0");
+ factory.AddUDPConnectFailure("172.16.0.0");
+ factory.AddUDPConnectFailure("192.168.0.0");
+ factory.AddUDPConnectSuccess("FC00::", "fe80::1");
+
+ auto result = PacMyIpAddressExForTest(&factory, dns_result);
+ // There were four link-local addresses found, but only the first one is
+ // returned.
+ ASSERT_EQ(1u, result.size());
+ EXPECT_EQ("fe81::8881", result.front().ToString());
+}
+
+// Tests myIpAddressEx() when there are only link-local addresses. The IPv4
+// link-local address is favored.
+TEST(PacLibraryTest, PacMyIpAddressExAllFailHasLinkLocalFavorIPv4) {
+ MockSocketFactory factory;
+ factory.AddUDPConnectFailure("8.8.8.8");
+ factory.AddUDPConnectFailure("2001:4860:4860::8888");
+
+ AddressList dns_result =
+ CreateAddressList({"127.0.0.1", "::1", "fe81::8881", "169.254.89.133"});
+
+ factory.AddUDPConnectFailure("10.0.0.0");
+ factory.AddUDPConnectFailure("172.16.0.0");
+ factory.AddUDPConnectFailure("192.168.0.0");
+ factory.AddUDPConnectFailure("FC00::");
+
+ auto result = PacMyIpAddressExForTest(&factory, dns_result);
+ ASSERT_EQ(1u, result.size());
+ EXPECT_EQ("169.254.89.133", result.front().ToString());
+}
+
+// Tests myIpAddressEx() when there are no routes, and
+// getaddrinfo(gethostname()) only returns loopback.
+TEST(PacLibraryTest, PacMyIpAddressExAllFailOrLoopback) {
+ MockSocketFactory factory;
+ factory.AddUDPConnectFailure("8.8.8.8");
+ factory.AddUDPConnectFailure("2001:4860:4860::8888");
+
+ AddressList dns_result = CreateAddressList({"127.0.0.1", "::1"});
+
+ factory.AddUDPConnectFailure("10.0.0.0");
+ factory.AddUDPConnectFailure("172.16.0.0");
+ factory.AddUDPConnectFailure("192.168.0.0");
+ factory.AddUDPConnectFailure("FC00::");
+
+ auto result = PacMyIpAddressExForTest(&factory, dns_result);
+ EXPECT_EQ(0u, result.size());
+}
+
+} // namespace
+} // namespace net
diff --git a/chromium/net/proxy_resolution/parse_proxy_bypass_rules_fuzzer.cc b/chromium/net/proxy_resolution/parse_proxy_bypass_rules_fuzzer.cc
index 100e818b702..d6821f38eee 100644
--- a/chromium/net/proxy_resolution/parse_proxy_bypass_rules_fuzzer.cc
+++ b/chromium/net/proxy_resolution/parse_proxy_bypass_rules_fuzzer.cc
@@ -18,7 +18,14 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
net::ProxyBypassRules rules;
std::string input(data, data + size);
- rules.ParseFromString(input);
- rules.ParseFromStringUsingSuffixMatching(input);
+
+ const net::ProxyBypassRules::ParseFormat kFormats[] = {
+ net::ProxyBypassRules::ParseFormat::kDefault,
+ net::ProxyBypassRules::ParseFormat::kHostnameSuffixMatching,
+ };
+
+ for (auto format : kFormats)
+ rules.ParseFromString(input, format);
+
return 0;
}
diff --git a/chromium/net/proxy_resolution/proxy_bypass_rules.cc b/chromium/net/proxy_resolution/proxy_bypass_rules.cc
index 2462f9aa058..a26f352aa91 100644
--- a/chromium/net/proxy_resolution/proxy_bypass_rules.cc
+++ b/chromium/net/proxy_resolution/proxy_bypass_rules.cc
@@ -9,6 +9,7 @@
#include "base/strings/string_tokenizer.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
+#include "build/build_config.h"
#include "net/base/host_port_pair.h"
#include "net/base/ip_address.h"
#include "net/base/parse_number.h"
@@ -18,16 +19,23 @@ namespace net {
namespace {
-bool IsIPv4LinkLocal(const IPAddress& addr) {
- // 169.254.0.0/16
- return addr.IsIPv4() && (addr.bytes()[0] == 169) && (addr.bytes()[1] == 254);
-}
-
-bool IsIPv6LinkLocal(const IPAddress& addr) {
- // [fe80::]/10
- return addr.IsIPv6() && (addr.bytes()[0] == 0xFE) &&
- ((addr.bytes()[1] & 0xC0) == 0x80);
-}
+// The <-loopback> rule corresponds with "remove the implicitly added bypass
+// rules".
+//
+// The name <-loopback> is not a very precise name (as the implicit rules cover
+// more than strictly loopback addresses), however this is the name that is
+// used on Windows so re-used here.
+//
+// For platform-differences between implicit rules see
+// ProxyResolverRules::MatchesImplicitRules().
+const char kSubtractImplicitBypasses[] = "<-loopback>";
+
+// The <local> rule bypasses any hostname that has no dots (and is not
+// an IP literal). The name is misleading as it has nothing to do with
+// localhost/loopback addresses, and would have better been called
+// something like "simple hostnames". However this is the name used on
+// Windows so is matched here.
+const char kBypassSimpleHostnames[] = "<local>";
bool IsLinkLocalIP(const GURL& url) {
// Quick fail if definitely not link-local, to avoid doing unnecessary work in
@@ -38,12 +46,11 @@ bool IsLinkLocalIP(const GURL& url) {
return false;
}
- base::StringPiece host(url.host());
IPAddress ip_address;
if (!ip_address.AssignFromIPLiteral(url.HostNoBracketsPiece()))
return false;
- return IsIPv4LinkLocal(ip_address) || IsIPv6LinkLocal(ip_address);
+ return ip_address.IsLinkLocal();
}
class HostnamePatternRule : public ProxyBypassRules::Rule {
@@ -55,16 +62,17 @@ class HostnamePatternRule : public ProxyBypassRules::Rule {
hostname_pattern_(base::ToLowerASCII(hostname_pattern)),
optional_port_(optional_port) {}
- bool Matches(const GURL& url) const override {
+ Result Evaluate(const GURL& url) const override {
if (optional_port_ != -1 && url.EffectiveIntPort() != optional_port_)
- return false; // Didn't match port expectation.
+ return Result::kNoMatch; // Didn't match port expectation.
if (!optional_scheme_.empty() && url.scheme() != optional_scheme_)
- return false; // Didn't match scheme expectation.
+ return Result::kNoMatch; // Didn't match scheme expectation.
// Note it is necessary to lower-case the host, since GURL uses capital
// letters for percent-escaped characters.
- return base::MatchPattern(url.host(), hostname_pattern_);
+ return base::MatchPattern(url.host(), hostname_pattern_) ? Result::kBypass
+ : Result::kNoMatch;
}
std::string ToString() const override {
@@ -77,77 +85,89 @@ class HostnamePatternRule : public ProxyBypassRules::Rule {
return str;
}
- std::unique_ptr<Rule> Clone() const override {
- return std::make_unique<HostnamePatternRule>(
- optional_scheme_, hostname_pattern_, optional_port_);
- }
-
private:
const std::string optional_scheme_;
const std::string hostname_pattern_;
const int optional_port_;
+
+ DISALLOW_COPY_AND_ASSIGN(HostnamePatternRule);
};
-class BypassLocalRule : public ProxyBypassRules::Rule {
+class BypassSimpleHostnamesRule : public ProxyBypassRules::Rule {
public:
- bool Matches(const GURL& url) const override {
- const std::string& host = url.host();
- if (host == "127.0.0.1" || host == "[::1]")
- return true;
- return host.find('.') == std::string::npos;
+ BypassSimpleHostnamesRule() = default;
+
+ Result Evaluate(const GURL& url) const override {
+ return ((url.host_piece().find('.') == std::string::npos) &&
+ !url.HostIsIPAddress())
+ ? Result::kBypass
+ : Result::kNoMatch;
}
- std::string ToString() const override { return "<local>"; }
+ std::string ToString() const override { return kBypassSimpleHostnames; }
- std::unique_ptr<Rule> Clone() const override {
- return std::make_unique<BypassLocalRule>();
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BypassSimpleHostnamesRule);
+};
+
+class SubtractImplicitBypassesRule : public ProxyBypassRules::Rule {
+ public:
+ SubtractImplicitBypassesRule() = default;
+
+ Result Evaluate(const GURL& url) const override {
+ return ProxyBypassRules::MatchesImplicitRules(url) ? Result::kDontBypass
+ : Result::kNoMatch;
}
+
+ std::string ToString() const override { return kSubtractImplicitBypasses; }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SubtractImplicitBypassesRule);
};
// Rule for matching a URL that is an IP address, if that IP address falls
// within a certain numeric range. For example, you could use this rule to
// match all the IPs in the CIDR block 10.10.3.4/24.
-class BypassIPBlockRule : public ProxyBypassRules::Rule {
+class IPBlockRule : public ProxyBypassRules::Rule {
public:
// |ip_prefix| + |prefix_length| define the IP block to match.
- BypassIPBlockRule(const std::string& description,
- const std::string& optional_scheme,
- const IPAddress& ip_prefix,
- size_t prefix_length_in_bits)
+ IPBlockRule(const std::string& description,
+ const std::string& optional_scheme,
+ const IPAddress& ip_prefix,
+ size_t prefix_length_in_bits)
: description_(description),
optional_scheme_(optional_scheme),
ip_prefix_(ip_prefix),
prefix_length_in_bits_(prefix_length_in_bits) {}
- bool Matches(const GURL& url) const override {
+ Result Evaluate(const GURL& url) const override {
if (!url.HostIsIPAddress())
- return false;
+ return Result::kNoMatch;
if (!optional_scheme_.empty() && url.scheme() != optional_scheme_)
- return false; // Didn't match scheme expectation.
+ return Result::kNoMatch; // Didn't match scheme expectation.
// Parse the input IP literal to a number.
IPAddress ip_address;
if (!ip_address.AssignFromIPLiteral(url.HostNoBracketsPiece()))
- return false;
+ return Result::kNoMatch;
// Test if it has the expected prefix.
return IPAddressMatchesPrefix(ip_address, ip_prefix_,
- prefix_length_in_bits_);
+ prefix_length_in_bits_)
+ ? Result::kBypass
+ : Result::kNoMatch;
}
std::string ToString() const override { return description_; }
- std::unique_ptr<Rule> Clone() const override {
- return std::make_unique<BypassIPBlockRule>(
- description_, optional_scheme_, ip_prefix_, prefix_length_in_bits_);
- }
-
private:
const std::string description_;
const std::string optional_scheme_;
const IPAddress ip_prefix_;
const size_t prefix_length_in_bits_;
+
+ DISALLOW_COPY_AND_ASSIGN(IPBlockRule);
};
// Returns true if the given string represents an IP address.
@@ -162,6 +182,92 @@ bool IsIPAddress(const std::string& domain) {
return host_info.IsIPAddress();
}
+std::unique_ptr<ProxyBypassRules::Rule> ParseRule(
+ const std::string& raw_untrimmed,
+ ProxyBypassRules::ParseFormat format) {
+ std::string raw;
+ base::TrimWhitespaceASCII(raw_untrimmed, base::TRIM_ALL, &raw);
+
+ // <local> and <-loopback> are special syntax used by WinInet's bypass list
+ // -- we allow it on all platforms and interpret it the same way.
+ if (base::LowerCaseEqualsASCII(raw, kBypassSimpleHostnames))
+ return std::make_unique<BypassSimpleHostnamesRule>();
+ if (base::LowerCaseEqualsASCII(raw, kSubtractImplicitBypasses))
+ return std::make_unique<SubtractImplicitBypassesRule>();
+
+ // Extract any scheme-restriction.
+ std::string::size_type scheme_pos = raw.find("://");
+ std::string scheme;
+ if (scheme_pos != std::string::npos) {
+ scheme = raw.substr(0, scheme_pos);
+ raw = raw.substr(scheme_pos + 3);
+ if (scheme.empty())
+ return nullptr;
+ }
+
+ if (raw.empty())
+ return nullptr;
+
+ // If there is a forward slash in the input, it is probably a CIDR style
+ // mask.
+ if (raw.find('/') != std::string::npos) {
+ IPAddress ip_prefix;
+ size_t prefix_length_in_bits;
+
+ if (!ParseCIDRBlock(raw, &ip_prefix, &prefix_length_in_bits))
+ return nullptr;
+
+ return std::make_unique<IPBlockRule>(raw, scheme, ip_prefix,
+ prefix_length_in_bits);
+ }
+
+ // Check if we have an <ip-address>[:port] input. We need to treat this
+ // separately since the IP literal may not be in a canonical form.
+ std::string host;
+ int port;
+ if (ParseHostAndPort(raw, &host, &port)) {
+ // TODO(eroman): HostForURL() below DCHECKs() when |host| contains an
+ // embedded NULL.
+ if (host.find('\0') != std::string::npos)
+ return nullptr;
+
+ // Note that HostPortPair is used to merely to convert any IPv6 literals to
+ // a URL-safe format that can be used by canonicalization below.
+ std::string bracketed_host = HostPortPair(host, 80).HostForURL();
+ if (IsIPAddress(bracketed_host)) {
+ // Canonicalize the IP literal before adding it as a string pattern.
+ GURL tmp_url("http://" + bracketed_host);
+ return std::make_unique<HostnamePatternRule>(scheme, tmp_url.host(),
+ port);
+ }
+ }
+
+ // Otherwise assume we have <hostname-pattern>[:port].
+ std::string::size_type pos_colon = raw.rfind(':');
+ port = -1;
+ if (pos_colon != std::string::npos) {
+ if (!ParseInt32(base::StringPiece(raw.begin() + pos_colon + 1, raw.end()),
+ ParseIntFormat::NON_NEGATIVE, &port) ||
+ port > 0xFFFF) {
+ return nullptr; // Port was invalid.
+ }
+ raw = raw.substr(0, pos_colon);
+ }
+
+ // Special-case hostnames that begin with a period.
+ // For example, we remap ".google.com" --> "*.google.com".
+ if (base::StartsWith(raw, ".", base::CompareCase::SENSITIVE))
+ raw = "*" + raw;
+
+ // If suffix matching was asked for, make sure the pattern starts with a
+ // wildcard.
+ if (format == ProxyBypassRules::ParseFormat::kHostnameSuffixMatching &&
+ !base::StartsWith(raw, "*", base::CompareCase::SENSITIVE))
+ raw = "*" + raw;
+
+ return std::make_unique<HostnamePatternRule>(scheme, raw, port);
+}
+
} // namespace
ProxyBypassRules::Rule::Rule() = default;
@@ -175,27 +281,67 @@ bool ProxyBypassRules::Rule::Equals(const Rule& rule) const {
ProxyBypassRules::ProxyBypassRules() = default;
ProxyBypassRules::ProxyBypassRules(const ProxyBypassRules& rhs) {
- AssignFrom(rhs);
+ *this = rhs;
}
-ProxyBypassRules::~ProxyBypassRules() {
- Clear();
+ProxyBypassRules::ProxyBypassRules(ProxyBypassRules&& rhs) {
+ *this = std::move(rhs);
}
+ProxyBypassRules::~ProxyBypassRules() = default;
+
ProxyBypassRules& ProxyBypassRules::operator=(const ProxyBypassRules& rhs) {
- AssignFrom(rhs);
+ ParseFromString(rhs.ToString());
return *this;
}
-bool ProxyBypassRules::Matches(const GURL& url) const {
- for (auto it = rules_.begin(); it != rules_.end(); ++it) {
- if ((*it)->Matches(url))
- return true;
+ProxyBypassRules& ProxyBypassRules::operator=(ProxyBypassRules&& rhs) {
+ rules_ = std::move(rhs.rules_);
+ return *this;
+}
+
+bool ProxyBypassRules::Matches(const GURL& url, bool reverse) const {
+ // Later rules override earlier rules, so evaluating the rule list can be
+ // done by iterating over it in reverse and short-circuiting when a match is
+ // found. If no matches are found then the implicit rules are consulted.
+ //
+ // The order of evaluation generally doesn't matter, since the common
+ // case is to have a set of (positive) bypass rules.
+ //
+ // However when mixing positive and negative bypass rules evaluation
+ // order makes a difference. The chosen evaluation order here matches
+ // WinInet (which supports <-loopback> as a negative rule).
+ //
+ // Consider these two rule lists:
+ // (a) "localhost; <-loopback>"
+ // (b) "<-loopback>; localhost"
+ //
+ // The expectation is that Matches("http://localhost/") returns false
+ // for (a) since the final rule <-loopback> unbypasses it. Whereas it is
+ // expected to return true for (b), since the final rule "localhost"
+ // bypasses it again.
+ for (auto it = rules_.rbegin(); it != rules_.rend(); ++it) {
+ const std::unique_ptr<Rule>& rule = *it;
+
+ switch (rule->Evaluate(url)) {
+ case Rule::Result::kBypass:
+ return !reverse;
+ case Rule::Result::kDontBypass:
+ return reverse;
+ case Rule::Result::kNoMatch:
+ continue;
+ }
}
- return false;
+
+ // If none of the explicit rules matched, fall back to the implicit rules.
+ bool matches_implicit = MatchesImplicitRules(url);
+ if (matches_implicit)
+ return matches_implicit;
+
+ return reverse;
}
-bool ProxyBypassRules::Equals(const ProxyBypassRules& other) const {
+bool ProxyBypassRules::operator==(const ProxyBypassRules& other) const {
if (rules_.size() != other.rules_.size())
return false;
@@ -206,13 +352,14 @@ bool ProxyBypassRules::Equals(const ProxyBypassRules& other) const {
return true;
}
-void ProxyBypassRules::ParseFromString(const std::string& raw) {
- ParseFromStringInternal(raw, false);
-}
+void ProxyBypassRules::ParseFromString(const std::string& raw,
+ ParseFormat format) {
+ Clear();
-void ProxyBypassRules::ParseFromStringUsingSuffixMatching(
- const std::string& raw) {
- ParseFromStringInternal(raw, true);
+ base::StringTokenizer entries(raw, ",;");
+ while (entries.GetNext()) {
+ AddRuleFromString(entries.token(), format);
+ }
}
bool ProxyBypassRules::AddRuleForHostname(const std::string& optional_scheme,
@@ -226,17 +373,30 @@ bool ProxyBypassRules::AddRuleForHostname(const std::string& optional_scheme,
return true;
}
-void ProxyBypassRules::AddRuleToBypassLocal() {
- rules_.push_back(std::make_unique<BypassLocalRule>());
+void ProxyBypassRules::PrependRuleToBypassSimpleHostnames() {
+ rules_.insert(rules_.begin(), std::make_unique<BypassSimpleHostnamesRule>());
}
-bool ProxyBypassRules::AddRuleFromString(const std::string& raw) {
- return AddRuleFromStringInternalWithLogging(raw, false);
+bool ProxyBypassRules::AddRuleFromString(const std::string& raw_untrimmed,
+ ParseFormat format) {
+ auto rule = ParseRule(raw_untrimmed, format);
+
+ if (rule) {
+ rules_.push_back(std::move(rule));
+ return true;
+ }
+
+ return false;
+}
+
+void ProxyBypassRules::AddRulesToSubtractImplicit() {
+ rules_.push_back(std::make_unique<SubtractImplicitBypassesRule>());
}
-bool ProxyBypassRules::AddRuleFromStringUsingSuffixMatching(
- const std::string& raw) {
- return AddRuleFromStringInternalWithLogging(raw, true);
+std::string ProxyBypassRules::GetRulesToSubtractImplicit() {
+ ProxyBypassRules rules;
+ rules.AddRulesToSubtractImplicit();
+ return rules.ToString();
}
std::string ProxyBypassRules::ToString() const {
@@ -252,15 +412,6 @@ void ProxyBypassRules::Clear() {
rules_.clear();
}
-void ProxyBypassRules::AssignFrom(const ProxyBypassRules& other) {
- Clear();
-
- // Make a copy of the rules list.
- for (auto it = other.rules_.begin(); it != other.rules_.end(); ++it) {
- rules_.push_back((*it)->Clone());
- }
-}
-
bool ProxyBypassRules::MatchesImplicitRules(const GURL& url) {
// On Windows the implict rules are:
//
@@ -285,118 +436,20 @@ bool ProxyBypassRules::MatchesImplicitRules(const GURL& url) {
// *.localhost
// localhost6
// localhost6.localdomain6
+ // loopback [Windows only]
+ // loopback. [Windows only]
// [::1]
// 127.0.0.1/8
// 169.254/16
// [FE80::]/10
- //
- // TODO(eroman): Does "loopback" need special treatment on Windows?
- return net::IsLocalhost(url) || IsLinkLocalIP(url);
-}
-
-void ProxyBypassRules::ParseFromStringInternal(
- const std::string& raw,
- bool use_hostname_suffix_matching) {
- Clear();
-
- base::StringTokenizer entries(raw, ",;");
- while (entries.GetNext()) {
- AddRuleFromStringInternalWithLogging(entries.token(),
- use_hostname_suffix_matching);
- }
-}
-
-bool ProxyBypassRules::AddRuleFromStringInternal(
- const std::string& raw_untrimmed,
- bool use_hostname_suffix_matching) {
- std::string raw;
- base::TrimWhitespaceASCII(raw_untrimmed, base::TRIM_ALL, &raw);
-
- // This is the special syntax used by WinInet's bypass list -- we allow it
- // on all platforms and interpret it the same way.
- if (base::LowerCaseEqualsASCII(raw, "<local>")) {
- AddRuleToBypassLocal();
- return true;
- }
-
- // Extract any scheme-restriction.
- std::string::size_type scheme_pos = raw.find("://");
- std::string scheme;
- if (scheme_pos != std::string::npos) {
- scheme = raw.substr(0, scheme_pos);
- raw = raw.substr(scheme_pos + 3);
- if (scheme.empty())
- return false;
- }
-
- if (raw.empty())
- return false;
-
- // If there is a forward slash in the input, it is probably a CIDR style
- // mask.
- if (raw.find('/') != std::string::npos) {
- IPAddress ip_prefix;
- size_t prefix_length_in_bits;
-
- if (!ParseCIDRBlock(raw, &ip_prefix, &prefix_length_in_bits))
- return false;
-
- rules_.push_back(std::make_unique<BypassIPBlockRule>(
- raw, scheme, ip_prefix, prefix_length_in_bits));
-
- return true;
- }
-
- // Check if we have an <ip-address>[:port] input. We need to treat this
- // separately since the IP literal may not be in a canonical form.
- std::string host;
- int port;
- if (ParseHostAndPort(raw, &host, &port)) {
- // TODO(eroman): HostForURL() below DCHECKs() when |host| contains an
- // embedded NULL.
- if (host.find('\0') != std::string::npos)
- return false;
-
- // Note that HostPortPair is used to merely to convert any IPv6 literals to
- // a URL-safe format that can be used by canonicalization below.
- std::string bracketed_host = HostPortPair(host, 80).HostForURL();
- if (IsIPAddress(bracketed_host)) {
- // Canonicalize the IP literal before adding it as a string pattern.
- GURL tmp_url("http://" + bracketed_host);
- return AddRuleForHostname(scheme, tmp_url.host(), port);
- }
- }
-
- // Otherwise assume we have <hostname-pattern>[:port].
- std::string::size_type pos_colon = raw.rfind(':');
- port = -1;
- if (pos_colon != std::string::npos) {
- if (!ParseInt32(base::StringPiece(raw.begin() + pos_colon + 1, raw.end()),
- ParseIntFormat::NON_NEGATIVE, &port) ||
- port > 0xFFFF) {
- return false; // Port was invalid.
- }
- raw = raw.substr(0, pos_colon);
- }
-
- // Special-case hostnames that begin with a period.
- // For example, we remap ".google.com" --> "*.google.com".
- if (base::StartsWith(raw, ".", base::CompareCase::SENSITIVE))
- raw = "*" + raw;
-
- // If suffix matching was asked for, make sure the pattern starts with a
- // wildcard.
- if (use_hostname_suffix_matching &&
- !base::StartsWith(raw, "*", base::CompareCase::SENSITIVE))
- raw = "*" + raw;
-
- return AddRuleForHostname(scheme, raw, port);
-}
-
-bool ProxyBypassRules::AddRuleFromStringInternalWithLogging(
- const std::string& raw,
- bool use_hostname_suffix_matching) {
- return AddRuleFromStringInternal(raw, use_hostname_suffix_matching);
+ return net::IsLocalhost(url) ||
+ IsLinkLocalIP(url)
+#if defined(OS_WIN)
+ // See http://crbug.com/904889
+ || (url.host_piece() == "loopback") ||
+ (url.host_piece() == "loopback.")
+#endif
+ ;
}
} // namespace net
diff --git a/chromium/net/proxy_resolution/proxy_bypass_rules.h b/chromium/net/proxy_resolution/proxy_bypass_rules.h
index 41ef6df3867..36ad6a2e19e 100644
--- a/chromium/net/proxy_resolution/proxy_bypass_rules.h
+++ b/chromium/net/proxy_resolution/proxy_bypass_rules.h
@@ -15,65 +15,101 @@
namespace net {
-// ProxyBypassRules describes the set of URLs that should bypass the proxy
-// settings, as a list of rules. A URL is said to match the bypass rules
-// if it matches any one of these rules.
+// ProxyBypassRules describes the set of URLs that should bypass the use of a
+// proxy.
+//
+// The rules are expressed as an ordered list of rules, which can be thought of
+// as being evaluated left-to-right. Order only matters when mixing "negative
+// rules" with "positive rules". For more details see the comments in
+// ProxyBypassRules::Matches().
+//
+// This rule list is serializable to a string (either comma or semi-colon
+// separated), which has similar semantics across platforms.
+//
+// When evalutating ProxyBypassRules there are some implicitly applied rules
+// when the URL does not match any of the explicit rules. See
+// MatchesImplicitRules() for details.
class NET_EXPORT ProxyBypassRules {
public:
// Interface for an individual proxy bypass rule.
class NET_EXPORT Rule {
public:
+ // Describes the result of calling Rule::Evaluate() for a particular URL.
+ enum class Result {
+ // The URL does not match this rule.
+ kNoMatch,
+
+ // The URL matches this rule, and should bypass the proxy.
+ kBypass,
+
+ // The URL matches this rule, and should NOT bypass the proxy.
+ kDontBypass,
+ };
+
Rule();
virtual ~Rule();
- // Returns true if |url| matches the rule.
- virtual bool Matches(const GURL& url) const = 0;
+ // Evaluates the rule against |url|.
+ virtual Result Evaluate(const GURL& url) const = 0;
- // Returns a string representation of this rule. This is used both for
- // visualizing the rules, and also to test equality of a rules list.
+ // Returns a string representation of this rule (using
+ // ParseFormat::kDefault).
virtual std::string ToString() const = 0;
- // Creates a copy of this rule.
- virtual std::unique_ptr<Rule> Clone() const = 0;
-
bool Equals(const Rule& rule) const;
private:
DISALLOW_COPY_AND_ASSIGN(Rule);
};
+ // The input format to use when parsing proxy bypass rules. This format
+ // only applies when parsing, since once parsed any serialization will be in
+ // terms of ParseFormat::kDefault.
+ enum class ParseFormat {
+ kDefault,
+
+ // Variation of kDefault that interprets hostname patterns as being suffix
+ // tests rather than hostname tests. For example, "google.com" would be
+ // interpreted as "*google.com" when parsed with this format, and
+ // match "foogoogle.com".
+ //
+ // Only use this format if needed for compatibility when parsing Linux
+ // bypass strings.
+ kHostnameSuffixMatching,
+ };
+
typedef std::vector<std::unique_ptr<Rule>> RuleList;
// Note: This class supports copy constructor and assignment.
ProxyBypassRules();
ProxyBypassRules(const ProxyBypassRules& rhs);
+ ProxyBypassRules(ProxyBypassRules&& rhs);
~ProxyBypassRules();
ProxyBypassRules& operator=(const ProxyBypassRules& rhs);
+ ProxyBypassRules& operator=(ProxyBypassRules&& rhs);
// Returns the current list of rules. The rules list contains pointers
// which are owned by this class, callers should NOT keep references
// or delete them.
const RuleList& rules() const { return rules_; }
- // Returns true if |url| matches any of the proxy bypass rules.
- bool Matches(const GURL& url) const;
+ // Returns true if the bypass rules indicate that |url| should bypass the
+ // proxy. Matching is done using both the explicit rules, as well as a
+ // set of global implicit rules.
+ //
+ // If |reverse| is set to true then the bypass
+ // rule list is inverted (this is almost equivalent to negating the result of
+ // Matches(), except for implicit matches).
+ bool Matches(const GURL& url, bool reverse = false) const;
- // Returns true if |*this| is equal to |other|; in other words, whether they
- // describe the same set of rules.
- bool Equals(const ProxyBypassRules& other) const;
+ // Returns true if |*this| has the same serialized list of rules as |other|.
+ bool operator==(const ProxyBypassRules& other) const;
// Initializes the list of rules by parsing the string |raw|. |raw| is a
- // comma separated list of rules. See AddRuleFromString() to see the list
- // of supported formats.
- void ParseFromString(const std::string& raw);
-
- // This is a variant of ParseFromString, which interprets hostname patterns
- // as suffix tests rather than hostname tests (so "google.com" would actually
- // match "*google.com"). This is only currently used for the linux no_proxy
- // environment variable. It is less flexible, since with the suffix matching
- // format you can't match an individual host.
- // NOTE: Use ParseFromString() unless you truly need this behavior.
- void ParseFromStringUsingSuffixMatching(const std::string& raw);
+ // comma separated or semi-colon separated list of rules. See
+ // AddRuleFromString() to see the specific rule grammar.
+ void ParseFromString(const std::string& raw,
+ ParseFormat format = ParseFormat::kDefault);
// Adds a rule that matches a URL when all of the following are true:
// (a) The URL's scheme matches |optional_scheme|, if
@@ -86,12 +122,14 @@ class NET_EXPORT ProxyBypassRules {
const std::string& hostname_pattern,
int optional_port);
- // Adds a rule that bypasses all "local" hostnames.
- // This matches IE's interpretation of the
- // "Bypass proxy server for local addresses" settings checkbox. Fully
- // qualified domain names or IP addresses are considered non-local,
- // regardless of what they map to (except for the loopback addresses).
- void AddRuleToBypassLocal();
+ // Adds a rule to the front of thelist that bypasses hostnames without a dot
+ // in them (and is not an IP literal), which can be indicative of intranet
+ // websites.
+ //
+ // On Windows this corresponds to the "Bypass proxy server for local
+ // addresses" settings checkbox, and on macOS the "Exclude simple hostnames"
+ // checkbox.
+ void PrependRuleToBypassSimpleHostnames();
// Adds a rule given by the string |raw|. The format of |raw| can be any of
// the following:
@@ -123,60 +161,72 @@ class NET_EXPORT ProxyBypassRules {
// Examples:
// "127.0.1", "[0:0::1]", "[::1]", "http://[::1]:99"
//
- // (4) IP_LITERAL "/" PREFIX_LENGTH_IN_BITS
+ // (4) IPV4_LITERAL "/" PREFIX_LENGTH_IN_BITS
//
- // Match any URL that is to an IP literal that falls between the
- // given range. IP range is specified using CIDR notation.
+ // Match any URL that is an IPv4 literal that falls between the
+ // given range.
//
// Examples:
- // "192.168.1.1/16", "fefe:13::abc/33".
+ // "192.168.1.1/16"
+ //
+ // (5) IPV6_LITERAL "/" PREFIX_LENGTH_IN_BITS
//
- // (5) "<local>"
+ // Match any URL that is an IPv6 literal that falls between the given
+ // range.
//
- // Match local addresses. The meaning of "<local>" is whether the
- // host matches one of: "127.0.0.1", "::1", "localhost".
+ // Note that IPV6_LITERAL must *not* be bracketed. "[fefe::/40]" for
+ // instance is not valid, but "fefe::/40" is. This notation comes from
+ // macOS's proxy bypass rules which supports IPv6 (Windows bypass rules do
+ // not).
+ //
+ // Examples:
+ // "fefe:13::abc/33".
+ //
+ // (6) "<local>"
+ //
+ // Matches hostnames without a period in them (and are not IP
+ // literals).
+ //
+ // This is equivalent to the same named bypass rule on Windows.
+ //
+ // (7) "<-loopback>"
+ //
+ // Subtracts the implicit proxy bypass rules (localhost and link local
+ // addresses), so they are no longer bypassed.
+ //
+ // This is equivalent to the same named bypass rule on Windows.
//
// See the unit-tests for more examples.
//
// Returns true if the rule was successfully added.
- bool AddRuleFromString(const std::string& raw);
+ bool AddRuleFromString(const std::string& raw,
+ ParseFormat format = ParseFormat::kDefault);
+
+ // Appends rules that "cancels out" the implicit bypass rules. See
+ // GetRulesToSubtractImplicit() for details.
+ void AddRulesToSubtractImplicit();
- // This is a variant of AddFromString, which interprets hostname patterns as
- // suffix tests rather than hostname tests (so "google.com" would actually
- // match "*google.com"). This is used for KDE which interprets every rule as
- // a suffix test. It is less flexible, since with the suffix matching format
- // you can't match an individual host.
+ // Returns a list of bypass rules that "cancels out" the implicit bypass
+ // rules.
//
- // Returns true if the rule was successfully added.
+ // The current set of implicit bypass rules are localhost and link-local
+ // addresses, and are subtracted using <-loopback> (an idiom from Windows),
+ // however this could change.
//
- // NOTE: Use AddRuleFromString() unless you truly need this behavior.
- bool AddRuleFromStringUsingSuffixMatching(const std::string& raw);
+ // If using this for tests, see https://crbug.com/901896.
+ static std::string GetRulesToSubtractImplicit();
- // Converts the rules to string representation. Inverse operation to
- // ParseFromString().
+ // Converts the rules to a string representation (ParseFormat::kDefault).
std::string ToString() const;
// Removes all the rules.
void Clear();
- // Sets |*this| to |other|.
- void AssignFrom(const ProxyBypassRules& other);
-
// Returns true if |url| matches one of the implicit proxy bypass rules
// (localhost or link local).
static bool MatchesImplicitRules(const GURL& url);
private:
- // The following are variants of ParseFromString() and AddRuleFromString(),
- // which additionally prefix hostname patterns with a wildcard if
- // |use_hostname_suffix_matching| was true.
- void ParseFromStringInternal(const std::string& raw,
- bool use_hostname_suffix_matching);
- bool AddRuleFromStringInternal(const std::string& raw,
- bool use_hostname_suffix_matching);
- bool AddRuleFromStringInternalWithLogging(const std::string& raw,
- bool use_hostname_suffix_matching);
-
RuleList rules_;
};
diff --git a/chromium/net/proxy_resolution/proxy_bypass_rules_unittest.cc b/chromium/net/proxy_resolution/proxy_bypass_rules_unittest.cc
index 6cd111fd576..55e2877b5d6 100644
--- a/chromium/net/proxy_resolution/proxy_bypass_rules_unittest.cc
+++ b/chromium/net/proxy_resolution/proxy_bypass_rules_unittest.cc
@@ -4,36 +4,110 @@
#include "net/proxy_resolution/proxy_bypass_rules.h"
+#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
+#include "build/build_config.h"
#include "net/proxy_resolution/proxy_config_service_common_unittest.h"
#include "testing/gtest/include/gtest/gtest.h"
+#if defined(OS_WIN)
+// On Windows, "loopback" resolves to localhost and is implicitly bypassed to
+// match WinInet.
+#define BYPASS_LOOPBACK
+#endif
+
namespace net {
namespace {
-// Calls |MatchesImplicitRules()| for each name in |hosts| (for various URL
-// schemes), and checks that the result is |bypasses|.
-template <size_t N>
-void ExpectMatchesImplicitRules(const char* (&hosts)[N], bool bypasses) {
+// Calls |rules.Matches()| for each name in |hosts| (for various URL schemes),
+// and checks that the result is |bypasses|. If the host is in |inverted_hosts|
+// then the expectation is reversed.
+void ExpectRulesMatch(const ProxyBypassRules& rules,
+ const char* hosts[],
+ size_t num_hosts,
+ bool bypasses,
+ const std::set<std::string>& inverted_hosts) {
// The scheme of the URL shouldn't matter.
const char* kUrlSchemes[] = {"http://", "https://", "ftp://"};
for (auto* scheme : kUrlSchemes) {
- for (size_t i = 0; i < N; ++i) {
+ for (size_t i = 0; i < num_hosts; ++i) {
const char* host = hosts[i];
+
+ bool expectation = bypasses;
+
+ if (inverted_hosts.count(std::string(host)) != 0)
+ expectation = !expectation;
+
std::string url = std::string(scheme) + std::string(host);
- EXPECT_EQ(bypasses, ProxyBypassRules::MatchesImplicitRules(GURL(url)))
- << url;
+
+ EXPECT_EQ(expectation, rules.Matches(GURL(url))) << url;
}
}
}
+// Tests calling |rules.Matches()| for localhost URLs returns |bypasses|.
+void ExpectBypassLocalhost(
+ const ProxyBypassRules& rules,
+ bool bypasses,
+ const std::set<std::string>& inverted_hosts = std::set<std::string>()) {
+ const char* kHosts[] = {
+ "localhost",
+ "localhost.",
+ "foo.localhost",
+ "localhost6",
+ "localhost6.localdomain6",
+ "127.0.0.1",
+ "127.100.0.2",
+ "[::1]",
+#if defined(BYPASS_LOOPBACK)
+ "loopback",
+ "loopback.",
+#endif
+ };
+
+ ExpectRulesMatch(rules, kHosts, base::size(kHosts), bypasses, inverted_hosts);
+}
+
+// Tests calling |rules.Matches()| for link-local URLs returns |bypasses|.
+void ExpectBypassLinkLocal(const ProxyBypassRules& rules, bool bypasses) {
+ const char* kHosts[] = {
+ "169.254.3.2", "169.254.100.1", "[FE80::8]", "[fe91::1]",
+ };
+
+ ExpectRulesMatch(rules, kHosts, base::size(kHosts), bypasses, {});
+}
+
+// Tests calling |rules.Matches()| with miscelaneous URLs that are neither
+// localhost or link local IPs, returns |bypasses|.
+void ExpectBypassMisc(
+ const ProxyBypassRules& rules,
+ bool bypasses,
+ const std::set<std::string>& inverted_hosts = std::set<std::string>()) {
+ const char* kHosts[] = {
+ "192.168.0.1",
+ "170.254.0.0",
+ "128.0.0.1",
+ "[::2]",
+ "[FD80::1]",
+ "foo",
+ "www.example3.com",
+#if !defined(BYPASS_LOOPBACK)
+ "loopback",
+ "loopback.",
+#endif
+ };
+
+ ExpectRulesMatch(rules, kHosts, base::size(kHosts), bypasses, inverted_hosts);
+}
+
TEST(ProxyBypassRulesTest, ParseAndMatchBasicHost) {
ProxyBypassRules rules;
rules.ParseFromString("wWw.gOogle.com");
ASSERT_EQ(1u, rules.rules().size());
+ // Hostname rules are normalized to lower-case.
EXPECT_EQ("www.google.com", rules.rules()[0]->ToString());
// All of these match; port, scheme, and non-hostname components don't
@@ -53,6 +127,7 @@ TEST(ProxyBypassRulesTest, ParseAndMatchBasicDomain) {
ProxyBypassRules rules;
rules.ParseFromString(".gOOgle.com");
ASSERT_EQ(1u, rules.rules().size());
+ // Hostname rules are normalized to lower-case.
// Note that we inferred this was an "ends with" test.
EXPECT_EQ("*.google.com", rules.rules()[0]->ToString());
@@ -73,6 +148,7 @@ TEST(ProxyBypassRulesTest, ParseAndMatchBasicDomainWithPort) {
ProxyBypassRules rules;
rules.ParseFromString("*.GOOGLE.com:80");
ASSERT_EQ(1u, rules.rules().size());
+ // Hostname rules are normalized to lower-case.
EXPECT_EQ("*.google.com:80", rules.rules()[0]->ToString());
// All of these match; scheme, and non-hostname components don't matter.
@@ -209,9 +285,10 @@ TEST(ProxyBypassRulesTest, HTTPOnlyWithWildcard) {
TEST(ProxyBypassRulesTest, UseSuffixMatching) {
ProxyBypassRules rules;
- rules.ParseFromStringUsingSuffixMatching(
+ rules.ParseFromString(
"foo1.com, .foo2.com, 192.168.1.1, "
- "*foobar.com:80, *.foo, http://baz, <local>");
+ "*foobar.com:80, *.foo, http://baz, <local>",
+ ProxyBypassRules::ParseFormat::kHostnameSuffixMatching);
ASSERT_EQ(7u, rules.rules().size());
EXPECT_EQ("*foo1.com", rules.rules()[0]->ToString());
EXPECT_EQ("*.foo2.com", rules.rules()[1]->ToString());
@@ -254,58 +331,43 @@ TEST(ProxyBypassRulesTest, Equals) {
rules1.ParseFromString("foo1.com, .foo2.com");
rules2.ParseFromString("foo1.com,.FOo2.com");
- EXPECT_TRUE(rules1.Equals(rules2));
- EXPECT_TRUE(rules2.Equals(rules1));
+ EXPECT_EQ(rules1, rules2);
+ EXPECT_EQ(rules2, rules1);
rules1.ParseFromString(".foo2.com");
rules2.ParseFromString("foo1.com,.FOo2.com");
- EXPECT_FALSE(rules1.Equals(rules2));
- EXPECT_FALSE(rules2.Equals(rules1));
+ EXPECT_FALSE(rules1 == rules2);
+ EXPECT_FALSE(rules2 == rules1);
}
-TEST(ProxyBypassRulesTest, BypassLocalNames) {
- const struct {
- const char* url;
- bool expected_is_local;
- } tests[] = {
- // Single-component hostnames are considered local.
- {"http://localhost/x", true},
- {"http://www", true},
-
- // IPv4 loopback interface.
- {"http://127.0.0.1/x", true},
- {"http://127.0.0.1:80/x", true},
-
- // IPv6 loopback interface.
- {"http://[::1]:80/x", true},
- {"http://[0:0::1]:6233/x", true},
- {"http://[0:0:0:0:0:0:0:1]/x", true},
-
- // Non-local URLs.
- {"http://foo.com/", false},
- {"http://localhost.i/", false},
- {"http://www.google.com/", false},
- {"http://192.168.0.1/", false},
-
- // Try with different protocols.
- {"ftp://127.0.0.1/x", true},
- {"ftp://foobar.com/x", false},
-
- // This is a bit of a gray-area, but GURL does not strip trailing dots
- // in host-names, so the following are considered non-local.
- {"http://www./x", false},
- {"http://localhost./x", false},
- };
-
+TEST(ProxyBypassRulesTest, BypassSimpleHostnames) {
+ // Test the simple hostnames rule in isolation, by first removing the
+ // implicit rules.
ProxyBypassRules rules;
- rules.ParseFromString("<local>");
+ rules.ParseFromString("<-loopback>; <local>");
- for (size_t i = 0; i < arraysize(tests); ++i) {
- SCOPED_TRACE(base::StringPrintf(
- "Test[%d]: %s", static_cast<int>(i), tests[i].url));
- EXPECT_EQ(tests[i].expected_is_local, rules.Matches(GURL(tests[i].url)));
- }
+ ASSERT_EQ(2u, rules.rules().size());
+ EXPECT_EQ("<-loopback>", rules.rules()[0]->ToString());
+ EXPECT_EQ("<local>", rules.rules()[1]->ToString());
+
+ EXPECT_TRUE(rules.Matches(GURL("http://example/")));
+
+ EXPECT_FALSE(rules.Matches(GURL("http://example./")));
+ EXPECT_FALSE(rules.Matches(GURL("http://example.com/")));
+ EXPECT_FALSE(rules.Matches(GURL("http://[dead::beef]/")));
+ EXPECT_FALSE(rules.Matches(GURL("http://192.168.1.1/")));
+
+ // Confusingly, <local> rule is NOT about localhost names. There is however
+ // overlap on "localhost6?" as it is both a simple hostname and a localhost
+ // name
+ ExpectBypassLocalhost(rules, false, {"localhost", "localhost6", "loopback"});
+
+ // Should NOT bypass link-local addresses.
+ ExpectBypassLinkLocal(rules, false);
+
+ // Should not bypass other names either (except for the ones with no dot).
+ ExpectBypassMisc(rules, false, {"foo", "loopback"});
}
TEST(ProxyBypassRulesTest, ParseAndMatchCIDR_IPv4) {
@@ -336,32 +398,123 @@ TEST(ProxyBypassRulesTest, ParseAndMatchCIDR_IPv6) {
EXPECT_FALSE(rules.Matches(GURL("http://192.169.1.1")));
}
-// Check that ProxyBypassRules::MatchesImplicitRules() matches all localhost
-// names, and link-local IPs, but nothing else.
-TEST(ProxyBypassRulesTest, MatchesImplicitRules) {
- const char* kLocalhosts[] = {
- "localhost",
- "localhost.",
- "foo.localhost",
- "localhost6",
- "localhost6.localdomain6",
- "127.0.0.1",
- "127.100.0.2",
- "[::1]",
- };
+// Test that parsing an IPv6 range given a bracketed literal is not supported.
+// Whether IPv6 literals need to be bracketed or not is pretty much a coin toss
+// depending on the context, and here it is expected to be unbracketed to match
+// macOS. It would be fine to support bracketed too, however none of the
+// grammars we parse need that.
+TEST(ProxyBypassRulesTest, ParseBracketedIPv6Range) {
+ ProxyBypassRules rules;
+ rules.ParseFromString("[a:b:c:d::]/48");
+ ASSERT_EQ(0u, rules.rules().size());
+}
- const char* kLinkLocalHosts[] = {
- "169.254.3.2", "169.254.100.1", "[FE80::8]", "[fe91::1]",
- };
+// Check which URLs an empty ProxyBypassRules matches.
+TEST(ProxyBypassRulesTest, DefaultImplicitRules) {
+ ProxyBypassRules rules;
- const char* kOtherHosts[] = {
- "192.168.0.1", "170.254.0.0", "128.0.0.1", "[::2]",
- "[FD80::1]", "foo", "www.example3.com", "loopback",
- };
+ EXPECT_EQ("", rules.ToString());
+
+ // Should bypass all localhost and loopback names.
+ ExpectBypassLocalhost(rules, true);
+
+ // Should bypass all link-local addresses.
+ ExpectBypassLinkLocal(rules, true);
+
+ // Should not bypass other names.
+ ExpectBypassMisc(rules, false);
+}
+
+// Test use of the <-loopback> bypass rule.
+TEST(ProxyBypassRulesTest, NegativeWinLoopback) {
+ ProxyBypassRules rules;
+
+ rules.ParseFromString("www.example.com;<-loopback>");
+ ASSERT_EQ(2u, rules.rules().size());
+ EXPECT_EQ("www.example.com", rules.rules()[0]->ToString());
+ EXPECT_EQ("<-loopback>", rules.rules()[1]->ToString());
+
+ // Should NOT bypass localhost and loopback names.
+ ExpectBypassLocalhost(rules, false);
+
+ // Should NOT bypass link-local addresses.
+ ExpectBypassLinkLocal(rules, false);
+
+ // Should not bypass other names either.
+ ExpectBypassMisc(rules, false);
+
+ // Only www.example.com should be bypassed.
+ EXPECT_TRUE(rules.Matches(GURL("http://www.example.com/")));
+}
+
+// Verifies the evaluation order of mixing negative and positive rules. This
+// expectation comes from WinInet (which is where <-loopback> comes from).
+TEST(ProxyBypassRulesTest, RemoveImplicitAndAddLocalhost) {
+ ProxyBypassRules rules;
+
+ rules.ParseFromString("<-loopback>; localhost");
+ ASSERT_EQ(2u, rules.rules().size());
+ EXPECT_EQ("<-loopback>", rules.rules()[0]->ToString());
+ EXPECT_EQ("localhost", rules.rules()[1]->ToString());
+
+ // Should not bypass localhost names because of <-loopback>. Except for
+ // "localhost" which was added at the end.
+ ExpectBypassLocalhost(rules, false, {"localhost"});
+
+ // Should NOT bypass link-local addresses.
+ ExpectBypassLinkLocal(rules, false);
+
+ // Should not bypass other names either.
+ ExpectBypassMisc(rules, false);
+}
+
+// Verifies the evaluation order of mixing negative and positive rules. This
+// expectation comes from WinInet (which is where <-loopback> comes from).
+TEST(ProxyBypassRulesTest, AddLocalhostThenRemoveImplicit) {
+ ProxyBypassRules rules;
+
+ rules.ParseFromString("localhost; <-loopback>");
+ ASSERT_EQ(2u, rules.rules().size());
+ EXPECT_EQ("localhost", rules.rules()[0]->ToString());
+ EXPECT_EQ("<-loopback>", rules.rules()[1]->ToString());
+
+ // Because of the ordering, localhost is not bypassed, because <-loopback>
+ // "unbypasses" it.
+ ExpectBypassLocalhost(rules, false);
+
+ // Should NOT bypass link-local addresses.
+ ExpectBypassLinkLocal(rules, false);
+
+ // Should not bypass other names either.
+ ExpectBypassMisc(rules, false);
+}
+
+TEST(ProxyBypassRulesTest, AddRulesToSubtractImplicit) {
+ ProxyBypassRules rules;
+ rules.ParseFromString("foo");
+
+ rules.AddRulesToSubtractImplicit();
+
+ ASSERT_EQ(2u, rules.rules().size());
+ EXPECT_EQ("foo", rules.rules()[0]->ToString());
+ EXPECT_EQ("<-loopback>", rules.rules()[1]->ToString());
+}
+
+TEST(ProxyBypassRulesTest, GetRulesToSubtractImplicit) {
+ EXPECT_EQ("<-loopback>;", ProxyBypassRules::GetRulesToSubtractImplicit());
+}
+
+// Verifies that the <local> and <-loopback> rules can be specified in any
+// case. This matches how WinInet's parses them.
+TEST(ProxyBypassRulesTest, LoopbackAndLocalCaseInsensitive) {
+ ProxyBypassRules rules;
- ExpectMatchesImplicitRules(kLocalhosts, true);
- ExpectMatchesImplicitRules(kLinkLocalHosts, true);
- ExpectMatchesImplicitRules(kOtherHosts, false);
+ rules.ParseFromString("<Local>; <-LoopBacK>; <LoCaL>; <-LoOpBack>");
+ ASSERT_EQ(4u, rules.rules().size());
+ EXPECT_EQ("<local>", rules.rules()[0]->ToString());
+ EXPECT_EQ("<-loopback>", rules.rules()[1]->ToString());
+ EXPECT_EQ("<local>", rules.rules()[2]->ToString());
+ EXPECT_EQ("<-loopback>", rules.rules()[3]->ToString());
}
} // namespace
diff --git a/chromium/net/proxy_resolution/proxy_config.cc b/chromium/net/proxy_resolution/proxy_config.cc
index 0f46b0092d2..9cfe6d1c0c0 100644
--- a/chromium/net/proxy_resolution/proxy_config.cc
+++ b/chromium/net/proxy_resolution/proxy_config.cc
@@ -53,10 +53,7 @@ void ProxyConfig::ProxyRules::Apply(const GURL& url, ProxyInfo* result) const {
return;
}
- bool bypass_proxy = bypass_rules.Matches(url);
- if (reverse_bypass)
- bypass_proxy = !bypass_proxy;
- if (bypass_proxy) {
+ if (bypass_rules.Matches(url, reverse_bypass)) {
result->UseDirectWithBypassedProxy();
return;
}
@@ -157,13 +154,12 @@ const ProxyList* ProxyConfig::ProxyRules::MapUrlSchemeToProxyList(
}
bool ProxyConfig::ProxyRules::Equals(const ProxyRules& other) const {
- return type == other.type &&
- single_proxies.Equals(other.single_proxies) &&
+ return type == other.type && single_proxies.Equals(other.single_proxies) &&
proxies_for_http.Equals(other.proxies_for_http) &&
proxies_for_https.Equals(other.proxies_for_https) &&
proxies_for_ftp.Equals(other.proxies_for_ftp) &&
fallback_proxies.Equals(other.fallback_proxies) &&
- bypass_rules.Equals(other.bypass_rules) &&
+ bypass_rules == other.bypass_rules &&
reverse_bypass == other.reverse_bypass;
}
@@ -199,8 +195,6 @@ ProxyConfig::~ProxyConfig() = default;
ProxyConfig& ProxyConfig::operator=(const ProxyConfig& config) = default;
bool ProxyConfig::Equals(const ProxyConfig& other) const {
- // The two configs can have different IDs and sources. We are just interested
- // in if they have the same settings.
return auto_detect_ == other.auto_detect_ &&
pac_url_ == other.pac_url_ &&
pac_mandatory_ == other.pac_mandatory_ &&
@@ -270,4 +264,4 @@ std::unique_ptr<base::DictionaryValue> ProxyConfig::ToValue() const {
return dict;
}
-} // namespace net \ No newline at end of file
+} // namespace net
diff --git a/chromium/net/proxy_resolution/proxy_config.h b/chromium/net/proxy_resolution/proxy_config.h
index 02d12a3376c..5b7798e3d6c 100644
--- a/chromium/net/proxy_resolution/proxy_config.h
+++ b/chromium/net/proxy_resolution/proxy_config.h
@@ -152,8 +152,7 @@ class NET_EXPORT ProxyConfig {
~ProxyConfig();
ProxyConfig& operator=(const ProxyConfig& config);
- // Returns true if the given config is equivalent to this config. The
- // comparison ignores differences in |source()|.
+ // Returns true if the given config is equivalent to this config.
bool Equals(const ProxyConfig& other) const;
// Returns true if this config contains any "automatic" settings. See the
diff --git a/chromium/net/proxy_resolution/proxy_config_service_linux.cc b/chromium/net/proxy_resolution/proxy_config_service_linux.cc
index 239b86c1b07..e8e16a7c5b6 100644
--- a/chromium/net/proxy_resolution/proxy_config_service_linux.cc
+++ b/chromium/net/proxy_resolution/proxy_config_service_linux.cc
@@ -199,8 +199,8 @@ ProxyConfigServiceLinux::Delegate::GetConfigFromEnv() {
}
// Note that this uses "suffix" matching. So a bypass of "google.com"
// is understood to mean a bypass of "*google.com".
- config.proxy_rules().bypass_rules.ParseFromStringUsingSuffixMatching(
- no_proxy);
+ config.proxy_rules().bypass_rules.ParseFromString(
+ no_proxy, ProxyBypassRules::ParseFormat::kHostnameSuffixMatching);
return ProxyConfigWithAnnotation(
config, NetworkTrafficAnnotationTag(traffic_annotation_));
}
@@ -381,7 +381,9 @@ class SettingGetterImplGSettings
return false;
}
- bool MatchHostsUsingSuffixMatching() override { return false; }
+ ProxyBypassRules::ParseFormat GetBypassListFormat() override {
+ return ProxyBypassRules::ParseFormat::kDefault;
+ }
private:
bool GetStringByPath(GSettings* client,
@@ -671,7 +673,9 @@ class SettingGetterImplKDE : public ProxyConfigServiceLinux::SettingGetter {
bool BypassListIsReversed() override { return reversed_bypass_list_; }
- bool MatchHostsUsingSuffixMatching() override { return true; }
+ ProxyBypassRules::ParseFormat GetBypassListFormat() override {
+ return ProxyBypassRules::ParseFormat::kHostnameSuffixMatching;
+ }
private:
void ResetCachedSettings() {
@@ -1137,18 +1141,14 @@ ProxyConfigServiceLinux::Delegate::GetConfigFromSettings() {
}
// Now the bypass list.
+ auto format = setting_getter_->GetBypassListFormat();
+
std::vector<std::string> ignore_hosts_list;
config.proxy_rules().bypass_rules.Clear();
if (setting_getter_->GetStringList(SettingGetter::PROXY_IGNORE_HOSTS,
&ignore_hosts_list)) {
- std::vector<std::string>::const_iterator it(ignore_hosts_list.begin());
- for (; it != ignore_hosts_list.end(); ++it) {
- if (setting_getter_->MatchHostsUsingSuffixMatching()) {
- config.proxy_rules().bypass_rules.AddRuleFromStringUsingSuffixMatching(
- *it);
- } else {
- config.proxy_rules().bypass_rules.AddRuleFromString(*it);
- }
+ for (const auto& rule : ignore_hosts_list) {
+ config.proxy_rules().bypass_rules.AddRuleFromString(rule, format);
}
}
// Note that there are no settings with semantics corresponding to
diff --git a/chromium/net/proxy_resolution/proxy_config_service_linux.h b/chromium/net/proxy_resolution/proxy_config_service_linux.h
index 95762b85db7..963b1bcfd90 100644
--- a/chromium/net/proxy_resolution/proxy_config_service_linux.h
+++ b/chromium/net/proxy_resolution/proxy_config_service_linux.h
@@ -132,9 +132,8 @@ class NET_EXPORT_PRIVATE ProxyConfigServiceLinux : public ProxyConfigService {
// whitelist rather than blacklist. (This is KDE-specific.)
virtual bool BypassListIsReversed() = 0;
- // Returns true if the bypass rules should be interpreted as
- // suffix-matching rules.
- virtual bool MatchHostsUsingSuffixMatching() = 0;
+ // Returns the format to use when parsing the bypass rules list.
+ virtual ProxyBypassRules::ParseFormat GetBypassListFormat() = 0;
private:
DISALLOW_COPY_AND_ASSIGN(SettingGetter);
diff --git a/chromium/net/proxy_resolution/proxy_config_service_linux_unittest.cc b/chromium/net/proxy_resolution/proxy_config_service_linux_unittest.cc
index 6dd7bd245b4..d22b825bcd3 100644
--- a/chromium/net/proxy_resolution/proxy_config_service_linux_unittest.cc
+++ b/chromium/net/proxy_resolution/proxy_config_service_linux_unittest.cc
@@ -22,6 +22,7 @@
#include "base/strings/stringprintf.h"
#include "base/synchronization/lock.h"
#include "base/synchronization/waitable_event.h"
+#include "base/task/task_scheduler/task_scheduler.h"
#include "base/threading/thread.h"
#include "base/threading/thread_task_runner_handle.h"
#include "net/proxy_resolution/proxy_config.h"
@@ -254,7 +255,9 @@ class MockSettingGetter : public ProxyConfigServiceLinux::SettingGetter {
bool BypassListIsReversed() override { return false; }
- bool MatchHostsUsingSuffixMatching() override { return false; }
+ ProxyBypassRules::ParseFormat GetBypassListFormat() override {
+ return ProxyBypassRules::ParseFormat::kDefault;
+ }
// Intentionally public, for convenience when setting up a test.
GSettingsValues values;
@@ -1877,6 +1880,11 @@ TEST_F(ProxyConfigServiceLinuxTest, KDEFileChanged) {
// observed.
sync_config_getter.SetExpectedPacUrl("http://version2/wpad.dat");
+ // Initialization posts a task to start watching kioslaverc file. Ensure that
+ // registration has happened before modifying it or the file change won't be
+ // observed.
+ base::TaskScheduler::GetInstance()->FlushForTesting();
+
WriteFile(kioslaverc_,
"[Proxy Settings]\nProxyType=2\n"
"Proxy Config Script=http://version2/wpad.dat\n");
diff --git a/chromium/net/proxy_resolution/proxy_config_service_mac.cc b/chromium/net/proxy_resolution/proxy_config_service_mac.cc
index 824978b9ae5..3409321beb0 100644
--- a/chromium/net/proxy_resolution/proxy_config_service_mac.cc
+++ b/chromium/net/proxy_resolution/proxy_config_service_mac.cc
@@ -153,7 +153,8 @@ void GetCurrentProxyConfig(const NetworkTrafficAnnotationTag traffic_annotation,
if (GetBoolFromDictionary(config_dict.get(),
kSCPropNetProxiesExcludeSimpleHostnames,
false)) {
- proxy_config.proxy_rules().bypass_rules.AddRuleToBypassLocal();
+ proxy_config.proxy_rules()
+ .bypass_rules.PrependRuleToBypassSimpleHostnames();
}
*config = ProxyConfigWithAnnotation(proxy_config, traffic_annotation);
diff --git a/chromium/net/proxy_resolution/proxy_resolution_service.cc b/chromium/net/proxy_resolution/proxy_resolution_service.cc
index 77787b65d17..cf2a9621221 100644
--- a/chromium/net/proxy_resolution/proxy_resolution_service.cc
+++ b/chromium/net/proxy_resolution/proxy_resolution_service.cc
@@ -21,6 +21,7 @@
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "base/values.h"
+#include "build/build_config.h"
#include "net/base/net_errors.h"
#include "net/base/proxy_delegate.h"
#include "net/base/url_util.h"
@@ -1561,6 +1562,9 @@ ProxyResolutionService::CreateSystemProxyConfigService(
#elif defined(OS_ANDROID)
return std::make_unique<ProxyConfigServiceAndroid>(
main_task_runner, base::ThreadTaskRunnerHandle::Get());
+#elif defined(OS_FUCHSIA)
+ // TODO(crbug.com/889195): Implement a system proxy service for Fuchsia.
+ return std::make_unique<ProxyConfigServiceDirect>();
#else
LOG(WARNING) << "Failed to choose a system proxy settings fetcher "
"for this platform.";
diff --git a/chromium/net/proxy_resolution/proxy_resolution_service.h b/chromium/net/proxy_resolution/proxy_resolution_service.h
index 119c48a0184..6d7f7ed301a 100644
--- a/chromium/net/proxy_resolution/proxy_resolution_service.h
+++ b/chromium/net/proxy_resolution/proxy_resolution_service.h
@@ -390,7 +390,10 @@ class NET_EXPORT ProxyResolutionService
const ProxyConfigWithAnnotation& config,
ProxyConfigService::ConfigAvailability availability) override;
- // When using a PAC script, don't let it decide the proxy for localhost URLs.
+ // When using a PAC script there isn't a user-configurable ProxyBypassRules to
+ // check, as the one from manual settings doesn't apply. However we
+ // still check for matches against the implicit bypass rules, to prevent PAC
+ // scripts from being able to proxy localhost.
bool ApplyPacBypassRules(const GURL& url, ProxyInfo* results);
std::unique_ptr<ProxyConfigService> config_service_;
diff --git a/chromium/net/proxy_resolution/proxy_resolution_service_unittest.cc b/chromium/net/proxy_resolution/proxy_resolution_service_unittest.cc
index 4759a8be888..8bf71e461a8 100644
--- a/chromium/net/proxy_resolution/proxy_resolution_service_unittest.cc
+++ b/chromium/net/proxy_resolution/proxy_resolution_service_unittest.cc
@@ -4025,9 +4025,7 @@ const char* kImplicityBypassedHosts[] = {
const char* kUrlSchemes[] = {"http://", "https://", "ftp://"};
-// Tests that the implicit bypass rules do not affect when configured with
-// manual proxy settings.
-TEST_F(ProxyResolutionServiceTest, DontBypassWithManualSettings) {
+TEST_F(ProxyResolutionServiceTest, ImplicitlyBypassWithManualSettings) {
// Use manual proxy settings that specify a single proxy for all traffic.
ProxyConfig config;
config.proxy_rules().ParseFromString("foopy1:8080");
@@ -4046,8 +4044,8 @@ TEST_F(ProxyResolutionServiceTest, DontBypassWithManualSettings) {
EXPECT_THAT(rv, IsOk());
EXPECT_EQ("foopy1:8080", info1.proxy_server().ToURI());
- // Test that localhost and link-local URLs do not bypass the proxy
- // (independent of the URL scheme).
+ // Test that localhost and link-local URLs bypass the proxy (independent of
+ // the URL scheme).
for (auto* host : kImplicityBypassedHosts) {
for (auto* scheme : kUrlSchemes) {
auto url = GURL(std::string(scheme) + std::string(host));
@@ -4059,13 +4057,12 @@ TEST_F(ProxyResolutionServiceTest, DontBypassWithManualSettings) {
service->ResolveProxy(url, std::string(), &info, callback.callback(),
&request, NetLogWithSource());
EXPECT_THAT(rv, IsOk());
- EXPECT_FALSE(info.is_direct());
- EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI());
+ EXPECT_TRUE(info.is_direct());
}
}
}
-// Test that the when using a PAC script (sourced via auto-detect),
+// Test that the when using a PAC script (sourced via auto-detect) certain
// localhost names are implicitly bypassed.
TEST_F(ProxyResolutionServiceTest, ImplicitlyBypassWithPac) {
ProxyConfig config;
diff --git a/chromium/net/proxy_resolution/proxy_resolver_v8.cc b/chromium/net/proxy_resolution/proxy_resolver_v8.cc
index c77fcc8dbdd..7a426d1b6c6 100644
--- a/chromium/net/proxy_resolution/proxy_resolver_v8.cc
+++ b/chromium/net/proxy_resolution/proxy_resolver_v8.cc
@@ -69,7 +69,7 @@
// --------------------+-------------+-------------------+--------------
// | Firefox3 | InternetExplorer8 | --> Us <---
// --------------------+-------------+-------------------+--------------
-// myIpAddress() | IPv4/IPv6 | IPv4 | IPv4
+// myIpAddress() | IPv4/IPv6 | IPv4 | IPv4/IPv6
// dnsResolve() | IPv4/IPv6 | IPv4 | IPv4
// isResolvable() | IPv4/IPv6 | IPv4 | IPv4
// myIpAddressEx() | N/A | IPv4/IPv6 | IPv4/IPv6
@@ -385,6 +385,11 @@ class SharedIsolateFactory {
static const char kNoOpt[] = "--noopt";
v8::V8::SetFlagsFromString(kNoOpt, strlen(kNoOpt));
+ // WebAssembly isn't encountered during resolution, so reduce the
+ // potential attack surface.
+ static const char kNoExposeWasm[] = "--no-expose-wasm";
+ v8::V8::SetFlagsFromString(kNoExposeWasm, strlen(kNoExposeWasm));
+
gin::IsolateHolder::Initialize(
gin::IsolateHolder::kNonStrictMode,
gin::IsolateHolder::kStableV8Extras,
diff --git a/chromium/net/proxy_resolution/proxy_resolver_v8_tracing.cc b/chromium/net/proxy_resolution/proxy_resolver_v8_tracing.cc
index 844f3c598fa..9a751c23d88 100644
--- a/chromium/net/proxy_resolution/proxy_resolver_v8_tracing.cc
+++ b/chromium/net/proxy_resolution/proxy_resolver_v8_tracing.cc
@@ -560,7 +560,7 @@ void Job::ExecuteNonBlocking() {
}
int Job::ExecuteProxyResolver() {
- TRACE_EVENT0(kNetTracingCategory, "Job::ExecuteProxyResolver");
+ TRACE_EVENT0(NetTracingCategory(), "Job::ExecuteProxyResolver");
int result = ERR_UNEXPECTED; // Initialized to silence warnings.
switch (operation_) {
@@ -830,16 +830,16 @@ HostResolver::RequestInfo Job::MakeDnsRequestInfo(const std::string& host,
ResolveDnsOperation op) {
HostPortPair host_port = HostPortPair(host, 80);
if (op == MY_IP_ADDRESS || op == MY_IP_ADDRESS_EX) {
+ // TODO(eroman): Remove the need for hostname. This is currently relied on
+ // for the cache key (is_my_ip_address isn't part of it).
host_port.set_host(GetHostName());
}
HostResolver::RequestInfo info(host_port);
// Flag myIpAddress requests.
- if (op == MY_IP_ADDRESS || op == MY_IP_ADDRESS_EX) {
- // TODO: Provide a RequestInfo construction mechanism that does not
- // require a hostname and sets is_my_ip_address to true instead of this.
+ if (op == MY_IP_ADDRESS || op == MY_IP_ADDRESS_EX)
info.set_is_my_ip_address(true);
- }
+
// The non-ex flavors are limited to IPv4 results.
if (op == MY_IP_ADDRESS || op == DNS_RESOLVE) {
info.set_address_family(ADDRESS_FAMILY_IPV4);