1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/proxy/proxy_service_mojo.h"
10 #include "base/callback_helpers.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/values.h"
14 #include "net/base/load_flags.h"
15 #include "net/base/network_delegate_impl.h"
16 #include "net/base/test_completion_callback.h"
17 #include "net/dns/mock_host_resolver.h"
18 #include "net/log/net_log.h"
19 #include "net/log/test_net_log.h"
20 #include "net/log/test_net_log_entry.h"
21 #include "net/proxy/dhcp_proxy_script_fetcher.h"
22 #include "net/proxy/in_process_mojo_proxy_resolver_factory.h"
23 #include "net/proxy/mock_proxy_script_fetcher.h"
24 #include "net/proxy/mojo_proxy_resolver_factory.h"
25 #include "net/proxy/proxy_config_service_fixed.h"
26 #include "net/proxy/proxy_service.h"
27 #include "net/test/event_waiter.h"
28 #include "testing/gmock/include/gmock/gmock.h"
29 #include "testing/gtest/include/gtest/gtest.h"
36 const char kPacUrl
[] = "http://example.com/proxy.pac";
37 const char kSimplePacScript
[] =
38 "function FindProxyForURL(url, host) {\n"
39 " return 'PROXY foo:1234';\n"
41 const char kDnsResolvePacScript
[] =
42 "function FindProxyForURL(url, host) {\n"
43 " if (dnsResolveEx('example.com') != '1.2.3.4')\n"
45 " return 'QUIC bar:4321';\n"
47 const char kThrowingPacScript
[] =
48 "function FindProxyForURL(url, host) {\n"
49 " alert('alert: ' + host);\n"
50 " throw new Error('error: ' + url);\n"
52 const char kThrowingOnLoadPacScript
[] =
53 "function FindProxyForURL(url, host) {}\n"
54 "alert('alert: foo');\n"
55 "throw new Error('error: http://foo');";
57 class TestNetworkDelegate
: public NetworkDelegateImpl
{
63 EventWaiter
<Event
>& event_waiter() { return event_waiter_
; }
65 void OnPACScriptError(int line_number
, const base::string16
& error
) override
;
68 EventWaiter
<Event
> event_waiter_
;
71 void TestNetworkDelegate::OnPACScriptError(int line_number
,
72 const base::string16
& error
) {
73 event_waiter_
.NotifyEvent(PAC_SCRIPT_ERROR
);
74 EXPECT_EQ(3, line_number
);
75 EXPECT_TRUE(base::UTF16ToUTF8(error
).find("error: http://foo") !=
79 void CheckCapturedNetLogEntries(const TestNetLogEntry::List
& entries
) {
80 ASSERT_GT(entries
.size(), 2u);
82 // ProxyService records its own NetLog entries, so skip forward until the
83 // expected event type.
84 while (i
< entries
.size() &&
85 entries
[i
].type
!= NetLog::TYPE_PAC_JAVASCRIPT_ALERT
) {
88 ASSERT_LT(i
, entries
.size());
90 ASSERT_TRUE(entries
[i
].GetStringValue("message", &message
));
91 EXPECT_EQ("alert: foo", message
);
92 ASSERT_FALSE(entries
[i
].params
->HasKey("line_number"));
94 while (i
< entries
.size() &&
95 entries
[i
].type
!= NetLog::TYPE_PAC_JAVASCRIPT_ERROR
) {
99 ASSERT_TRUE(entries
[i
].GetStringValue("message", &message
));
100 EXPECT_THAT(message
, testing::HasSubstr("error: http://foo"));
102 ASSERT_TRUE(entries
[i
].GetIntegerValue("line_number", &line_number
));
103 EXPECT_EQ(3, line_number
);
106 class LoggingMockHostResolver
: public MockHostResolver
{
108 int Resolve(const RequestInfo
& info
,
109 RequestPriority priority
,
110 AddressList
* addresses
,
111 const CompletionCallback
& callback
,
112 RequestHandle
* out_req
,
113 const BoundNetLog
& net_log
) override
{
114 net_log
.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB
);
115 return MockHostResolver::Resolve(info
, priority
, addresses
, callback
,
122 class ProxyServiceMojoTest
: public testing::Test
,
123 public MojoProxyResolverFactory
{
125 void SetUp() override
{
126 mock_host_resolver_
.rules()->AddRule("example.com", "1.2.3.4");
128 fetcher_
= new MockProxyScriptFetcher
;
129 proxy_service_
.reset(CreateProxyServiceUsingMojoFactory(
130 this, new ProxyConfigServiceFixed(
131 ProxyConfig::CreateFromCustomPacURL(GURL(kPacUrl
))),
132 fetcher_
, new DoNothingDhcpProxyScriptFetcher(), &mock_host_resolver_
,
133 &net_log_
, &network_delegate_
));
136 scoped_ptr
<base::ScopedClosureRunner
> CreateResolver(
137 const mojo::String
& pac_script
,
138 mojo::InterfaceRequest
<interfaces::ProxyResolver
> req
,
139 interfaces::ProxyResolverFactoryRequestClientPtr client
) override
{
140 InProcessMojoProxyResolverFactory::GetInstance()->CreateResolver(
141 pac_script
, req
.Pass(), client
.Pass());
142 return make_scoped_ptr(
143 new base::ScopedClosureRunner(on_delete_closure_
.closure()));
146 TestNetworkDelegate network_delegate_
;
147 LoggingMockHostResolver mock_host_resolver_
;
148 MockProxyScriptFetcher
* fetcher_
; // Owned by |proxy_service_|.
150 scoped_ptr
<ProxyService
> proxy_service_
;
151 TestClosure on_delete_closure_
;
154 TEST_F(ProxyServiceMojoTest
, Basic
) {
156 TestCompletionCallback callback
;
157 EXPECT_EQ(ERR_IO_PENDING
,
158 proxy_service_
->ResolveProxy(GURL("http://foo"), LOAD_NORMAL
, &info
,
159 callback
.callback(), nullptr, nullptr,
162 // Proxy script fetcher should have a fetch triggered by the first
163 // |ResolveProxy()| request.
164 EXPECT_TRUE(fetcher_
->has_pending_request());
165 EXPECT_EQ(GURL(kPacUrl
), fetcher_
->pending_request_url());
166 fetcher_
->NotifyFetchCompletion(OK
, kSimplePacScript
);
168 EXPECT_EQ(OK
, callback
.WaitForResult());
169 EXPECT_EQ("PROXY foo:1234", info
.ToPacString());
170 EXPECT_EQ(0u, mock_host_resolver_
.num_resolve());
171 proxy_service_
.reset();
172 on_delete_closure_
.WaitForResult();
175 TEST_F(ProxyServiceMojoTest
, DnsResolution
) {
177 TestCompletionCallback callback
;
178 BoundTestNetLog bound_net_log
;
179 EXPECT_EQ(ERR_IO_PENDING
,
180 proxy_service_
->ResolveProxy(GURL("http://foo"), LOAD_NORMAL
, &info
,
181 callback
.callback(), nullptr, nullptr,
182 bound_net_log
.bound()));
184 // Proxy script fetcher should have a fetch triggered by the first
185 // |ResolveProxy()| request.
186 EXPECT_TRUE(fetcher_
->has_pending_request());
187 EXPECT_EQ(GURL(kPacUrl
), fetcher_
->pending_request_url());
188 fetcher_
->NotifyFetchCompletion(OK
, kDnsResolvePacScript
);
190 EXPECT_EQ(OK
, callback
.WaitForResult());
191 EXPECT_EQ("QUIC bar:4321", info
.ToPacString());
192 EXPECT_EQ(1u, mock_host_resolver_
.num_resolve());
193 proxy_service_
.reset();
194 on_delete_closure_
.WaitForResult();
196 TestNetLogEntry::List entries
;
197 bound_net_log
.GetEntries(&entries
);
198 // There should be one entry with type TYPE_HOST_RESOLVER_IMPL_JOB.
199 EXPECT_EQ(1, std::count_if(entries
.begin(), entries
.end(),
200 [](const TestNetLogEntry
& entry
) {
202 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB
;
206 TEST_F(ProxyServiceMojoTest
, Error
) {
208 TestCompletionCallback callback
;
209 BoundTestNetLog bound_net_log
;
210 EXPECT_EQ(ERR_IO_PENDING
,
211 proxy_service_
->ResolveProxy(GURL("http://foo"), LOAD_NORMAL
, &info
,
212 callback
.callback(), nullptr, nullptr,
213 bound_net_log
.bound()));
215 // Proxy script fetcher should have a fetch triggered by the first
216 // |ResolveProxy()| request.
217 EXPECT_TRUE(fetcher_
->has_pending_request());
218 EXPECT_EQ(GURL(kPacUrl
), fetcher_
->pending_request_url());
219 fetcher_
->NotifyFetchCompletion(OK
, kThrowingPacScript
);
221 network_delegate_
.event_waiter().WaitForEvent(
222 TestNetworkDelegate::PAC_SCRIPT_ERROR
);
224 EXPECT_EQ(OK
, callback
.WaitForResult());
225 EXPECT_EQ("DIRECT", info
.ToPacString());
226 EXPECT_EQ(0u, mock_host_resolver_
.num_resolve());
228 TestNetLogEntry::List entries
;
229 bound_net_log
.GetEntries(&entries
);
230 CheckCapturedNetLogEntries(entries
);
232 net_log_
.GetEntries(&entries
);
233 CheckCapturedNetLogEntries(entries
);
236 TEST_F(ProxyServiceMojoTest
, ErrorOnInitialization
) {
238 TestCompletionCallback callback
;
239 EXPECT_EQ(ERR_IO_PENDING
,
240 proxy_service_
->ResolveProxy(GURL("http://foo"), LOAD_NORMAL
, &info
,
241 callback
.callback(), nullptr, nullptr,
244 // Proxy script fetcher should have a fetch triggered by the first
245 // |ResolveProxy()| request.
246 EXPECT_TRUE(fetcher_
->has_pending_request());
247 EXPECT_EQ(GURL(kPacUrl
), fetcher_
->pending_request_url());
248 fetcher_
->NotifyFetchCompletion(OK
, kThrowingOnLoadPacScript
);
250 network_delegate_
.event_waiter().WaitForEvent(
251 TestNetworkDelegate::PAC_SCRIPT_ERROR
);
253 EXPECT_EQ(OK
, callback
.WaitForResult());
254 EXPECT_EQ("DIRECT", info
.ToPacString());
255 EXPECT_EQ(0u, mock_host_resolver_
.num_resolve());
257 TestNetLogEntry::List entries
;
258 net_log_
.GetEntries(&entries
);
259 CheckCapturedNetLogEntries(entries
);