Upload upstream chromium 108.0.5359.1
[platform/framework/web/chromium-efl.git] / services / proxy_resolver / proxy_resolver_v8_unittest.cc
1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "services/proxy_resolver/proxy_resolver_v8.h"
6
7 #include "base/compiler_specific.h"
8 #include "base/files/file_util.h"
9 #include "base/path_service.h"
10 #include "base/strings/string_util.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/test/task_environment.h"
14 #include "net/base/net_errors.h"
15 #include "net/base/proxy_string_util.h"
16 #include "net/proxy_resolution/pac_file_data.h"
17 #include "net/proxy_resolution/proxy_info.h"
18 #include "net/test/gtest_util.h"
19 #include "testing/gmock/include/gmock/gmock.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21 #include "url/gurl.h"
22
23 using net::test::IsError;
24 using net::test::IsOk;
25 using ::testing::IsEmpty;
26
27 namespace proxy_resolver {
28 namespace {
29
30 // Javascript bindings for ProxyResolverV8, which returns mock values.
31 // Each time one of the bindings is called into, we push the input into a
32 // list, for later verification.
33 class MockJSBindings : public ProxyResolverV8::JSBindings {
34  public:
35   MockJSBindings()
36       : my_ip_address_count(0),
37         my_ip_address_ex_count(0),
38         should_terminate(false) {}
39
40   void Alert(const std::u16string& message) override {
41     VLOG(1) << "PAC-alert: " << message;  // Helpful when debugging.
42     alerts.push_back(base::UTF16ToUTF8(message));
43   }
44
45   bool ResolveDns(const std::string& host,
46                   net::ProxyResolveDnsOperation op,
47                   std::string* output,
48                   bool* terminate) override {
49     *terminate = should_terminate;
50
51     if (op == net::ProxyResolveDnsOperation::MY_IP_ADDRESS) {
52       my_ip_address_count++;
53       *output = my_ip_address_result;
54       return !my_ip_address_result.empty();
55     }
56
57     if (op == net::ProxyResolveDnsOperation::MY_IP_ADDRESS_EX) {
58       my_ip_address_ex_count++;
59       *output = my_ip_address_ex_result;
60       return !my_ip_address_ex_result.empty();
61     }
62
63     if (op == net::ProxyResolveDnsOperation::DNS_RESOLVE) {
64       dns_resolves.push_back(host);
65       *output = dns_resolve_result;
66       return !dns_resolve_result.empty();
67     }
68
69     if (op == net::ProxyResolveDnsOperation::DNS_RESOLVE_EX) {
70       dns_resolves_ex.push_back(host);
71       *output = dns_resolve_ex_result;
72       return !dns_resolve_ex_result.empty();
73     }
74
75     CHECK(false);
76     return false;
77   }
78
79   void OnError(int line_number, const std::u16string& message) override {
80     // Helpful when debugging.
81     VLOG(1) << "PAC-error: [" << line_number << "] " << message;
82
83     errors.push_back(base::UTF16ToUTF8(message));
84     errors_line_number.push_back(line_number);
85   }
86
87   // Mock values to return.
88   std::string my_ip_address_result;
89   std::string my_ip_address_ex_result;
90   std::string dns_resolve_result;
91   std::string dns_resolve_ex_result;
92
93   // Inputs we got called with.
94   std::vector<std::string> alerts;
95   std::vector<std::string> errors;
96   std::vector<int> errors_line_number;
97   std::vector<std::string> dns_resolves;
98   std::vector<std::string> dns_resolves_ex;
99   int my_ip_address_count;
100   int my_ip_address_ex_count;
101
102   // Whether ResolveDns() should terminate script execution.
103   bool should_terminate;
104 };
105
106 class ProxyResolverV8Test : public testing::Test {
107  public:
108   // Creates a ProxyResolverV8 using the PAC script contained in |filename|. If
109   // called more than once, the previous ProxyResolverV8 is deleted.
110   int CreateResolver(const char* filename) {
111     base::FilePath path;
112     base::PathService::Get(base::DIR_SOURCE_ROOT, &path);
113     path = path.AppendASCII("services");
114     path = path.AppendASCII("proxy_resolver");
115     path = path.AppendASCII("test");
116     path = path.AppendASCII("data");
117     path = path.AppendASCII("proxy_resolver_v8_unittest");
118     path = path.AppendASCII(filename);
119
120     // Try to read the file from disk.
121     std::string file_contents;
122     bool ok = base::ReadFileToString(path, &file_contents);
123
124     // If we can't load the file from disk, something is misconfigured.
125     if (!ok) {
126       LOG(ERROR) << "Failed to read file: " << path.value();
127       return net::ERR_FAILED;
128     }
129
130     // Create the ProxyResolver using the PAC script.
131     return ProxyResolverV8::Create(net::PacFileData::FromUTF8(file_contents),
132                                    bindings(), &resolver_);
133   }
134
135   ProxyResolverV8& resolver() {
136     DCHECK(resolver_);
137     return *resolver_;
138   }
139
140   MockJSBindings* bindings() { return &js_bindings_; }
141
142  private:
143   base::test::TaskEnvironment task_environment_;
144   MockJSBindings js_bindings_;
145   std::unique_ptr<ProxyResolverV8> resolver_;
146 };
147
148 TEST_F(ProxyResolverV8Test, Direct) {
149   ASSERT_THAT(CreateResolver("direct.js"), IsOk());
150
151   net::ProxyInfo proxy_info;
152   int result = resolver().GetProxyForURL(GURL("http://www.google.com"),
153                                          &proxy_info, bindings());
154
155   EXPECT_THAT(result, IsOk());
156   EXPECT_TRUE(proxy_info.is_direct());
157
158   EXPECT_EQ(0U, bindings()->alerts.size());
159   EXPECT_EQ(0U, bindings()->errors.size());
160 }
161
162 TEST_F(ProxyResolverV8Test, ReturnEmptyString) {
163   ASSERT_THAT(CreateResolver("return_empty_string.js"), IsOk());
164
165   net::ProxyInfo proxy_info;
166   int result = resolver().GetProxyForURL(GURL("http://www.google.com"),
167                                          &proxy_info, bindings());
168
169   EXPECT_THAT(result, IsOk());
170   EXPECT_TRUE(proxy_info.is_direct());
171
172   EXPECT_EQ(0U, bindings()->alerts.size());
173   EXPECT_EQ(0U, bindings()->errors.size());
174 }
175
176 TEST_F(ProxyResolverV8Test, Basic) {
177   ASSERT_THAT(CreateResolver("passthrough.js"), IsOk());
178
179   // The "FindProxyForURL" of this PAC script simply concatenates all of the
180   // arguments into a pseudo-host. The purpose of this test is to verify that
181   // the correct arguments are being passed to FindProxyForURL().
182   {
183     net::ProxyInfo proxy_info;
184     int result = resolver().GetProxyForURL(GURL("http://query.com/path"),
185                                            &proxy_info, bindings());
186     EXPECT_THAT(result, IsOk());
187     EXPECT_EQ("http.query.com.path.query.com:80",
188               ProxyServerToProxyUri(proxy_info.proxy_server()));
189   }
190   {
191     net::ProxyInfo proxy_info;
192     int result = resolver().GetProxyForURL(GURL("ftp://query.com:90/path"),
193                                            &proxy_info, bindings());
194     EXPECT_THAT(result, IsOk());
195     // Note that FindProxyForURL(url, host) does not expect |host| to contain
196     // the port number.
197     EXPECT_EQ("ftp.query.com.90.path.query.com:80",
198               ProxyServerToProxyUri(proxy_info.proxy_server()));
199
200     EXPECT_EQ(0U, bindings()->alerts.size());
201     EXPECT_EQ(0U, bindings()->errors.size());
202   }
203 }
204
205 TEST_F(ProxyResolverV8Test, BadReturnType) {
206   // These are the filenames of PAC scripts which each return a non-string
207   // types for FindProxyForURL(). They should all fail with
208   // net::ERR_PAC_SCRIPT_FAILED.
209   static const char* const filenames[] = {
210       "return_undefined.js", "return_integer.js", "return_function.js",
211       "return_object.js",
212       // TODO(eroman): Should 'null' be considered equivalent to "DIRECT" ?
213       "return_null.js"};
214
215   for (size_t i = 0; i < std::size(filenames); ++i) {
216     ASSERT_THAT(CreateResolver(filenames[i]), IsOk());
217
218     MockJSBindings bindings;
219     net::ProxyInfo proxy_info;
220     int result = resolver().GetProxyForURL(GURL("http://www.google.com"),
221                                            &proxy_info, &bindings);
222
223     EXPECT_THAT(result, IsError(net::ERR_PAC_SCRIPT_FAILED));
224
225     EXPECT_EQ(0U, bindings.alerts.size());
226     ASSERT_EQ(1U, bindings.errors.size());
227     EXPECT_EQ("FindProxyForURL() did not return a string.", bindings.errors[0]);
228     EXPECT_EQ(-1, bindings.errors_line_number[0]);
229   }
230 }
231
232 // Try using a PAC script which defines no "FindProxyForURL" function.
233 TEST_F(ProxyResolverV8Test, NoEntryPoint) {
234   EXPECT_THAT(CreateResolver("no_entrypoint.js"),
235               IsError(net::ERR_PAC_SCRIPT_FAILED));
236
237   ASSERT_EQ(1U, bindings()->errors.size());
238   EXPECT_EQ("FindProxyForURL is undefined or not a function.",
239             bindings()->errors[0]);
240   EXPECT_EQ(-1, bindings()->errors_line_number[0]);
241 }
242
243 // Try loading a malformed PAC script.
244 TEST_F(ProxyResolverV8Test, ParseError) {
245   EXPECT_THAT(CreateResolver("missing_close_brace.js"),
246               IsError(net::ERR_PAC_SCRIPT_FAILED));
247
248   EXPECT_EQ(0U, bindings()->alerts.size());
249
250   // We get one error during compilation.
251   ASSERT_EQ(1U, bindings()->errors.size());
252
253   EXPECT_EQ("Uncaught SyntaxError: Unexpected end of input",
254             bindings()->errors[0]);
255   EXPECT_EQ(7, bindings()->errors_line_number[0]);
256 }
257
258 // Run a PAC script several times, which has side-effects.
259 TEST_F(ProxyResolverV8Test, SideEffects) {
260   ASSERT_THAT(CreateResolver("side_effects.js"), IsOk());
261
262   // The PAC script increments a counter each time we invoke it.
263   for (int i = 0; i < 3; ++i) {
264     net::ProxyInfo proxy_info;
265     int result = resolver().GetProxyForURL(GURL("http://www.google.com"),
266                                            &proxy_info, bindings());
267     EXPECT_THAT(result, IsOk());
268     EXPECT_EQ(base::StringPrintf("sideffect_%d:80", i),
269               ProxyServerToProxyUri(proxy_info.proxy_server()));
270   }
271
272   // Reload the script -- the javascript environment should be reset, hence
273   // the counter starts over.
274   ASSERT_THAT(CreateResolver("side_effects.js"), IsOk());
275
276   for (int i = 0; i < 3; ++i) {
277     net::ProxyInfo proxy_info;
278     int result = resolver().GetProxyForURL(GURL("http://www.google.com"),
279                                            &proxy_info, bindings());
280     EXPECT_THAT(result, IsOk());
281     EXPECT_EQ(base::StringPrintf("sideffect_%d:80", i),
282               ProxyServerToProxyUri(proxy_info.proxy_server()));
283   }
284 }
285
286 // Execute a PAC script which throws an exception in FindProxyForURL.
287 TEST_F(ProxyResolverV8Test, UnhandledException) {
288   ASSERT_THAT(CreateResolver("unhandled_exception.js"), IsOk());
289
290   net::ProxyInfo proxy_info;
291   int result = resolver().GetProxyForURL(GURL("http://www.google.com"),
292                                          &proxy_info, bindings());
293
294   EXPECT_THAT(result, IsError(net::ERR_PAC_SCRIPT_FAILED));
295
296   EXPECT_EQ(0U, bindings()->alerts.size());
297   ASSERT_EQ(1U, bindings()->errors.size());
298   EXPECT_EQ("Uncaught ReferenceError: undefined_variable is not defined",
299             bindings()->errors[0]);
300   EXPECT_EQ(3, bindings()->errors_line_number[0]);
301 }
302
303 // Execute a PAC script which throws an exception when first accessing
304 // FindProxyForURL
305 TEST_F(ProxyResolverV8Test, ExceptionAccessingFindProxyForURLDuringInit) {
306   EXPECT_EQ(net::ERR_PAC_SCRIPT_FAILED,
307             CreateResolver("exception_findproxyforurl_during_init.js"));
308
309   ASSERT_EQ(2U, bindings()->errors.size());
310   EXPECT_EQ("Uncaught crash!", bindings()->errors[0]);
311   EXPECT_EQ(9, bindings()->errors_line_number[0]);
312   EXPECT_EQ("Accessing FindProxyForURL threw an exception.",
313             bindings()->errors[1]);
314   EXPECT_EQ(-1, bindings()->errors_line_number[1]);
315 }
316
317 // Execute a PAC script which throws an exception during the second access to
318 // FindProxyForURL
319 TEST_F(ProxyResolverV8Test, ExceptionAccessingFindProxyForURLDuringResolve) {
320   ASSERT_THAT(CreateResolver("exception_findproxyforurl_during_resolve.js"),
321               IsOk());
322
323   net::ProxyInfo proxy_info;
324   int result = resolver().GetProxyForURL(GURL("http://www.google.com"),
325                                          &proxy_info, bindings());
326
327   EXPECT_THAT(result, IsError(net::ERR_PAC_SCRIPT_FAILED));
328
329   ASSERT_EQ(2U, bindings()->errors.size());
330   EXPECT_EQ("Uncaught crash!", bindings()->errors[0]);
331   EXPECT_EQ(17, bindings()->errors_line_number[0]);
332   EXPECT_EQ("Accessing FindProxyForURL threw an exception.",
333             bindings()->errors[1]);
334   EXPECT_EQ(-1, bindings()->errors_line_number[1]);
335 }
336
337 TEST_F(ProxyResolverV8Test, ReturnUnicode) {
338   ASSERT_THAT(CreateResolver("return_unicode.js"), IsOk());
339
340   net::ProxyInfo proxy_info;
341   int result = resolver().GetProxyForURL(GURL("http://www.google.com"),
342                                          &proxy_info, bindings());
343
344   // The result from this resolve was unparseable, because it
345   // wasn't ASCII.
346   EXPECT_THAT(result, IsError(net::ERR_PAC_SCRIPT_FAILED));
347 }
348
349 // Test the PAC library functions that we expose in the JS environment.
350 TEST_F(ProxyResolverV8Test, JavascriptLibrary) {
351   ASSERT_THAT(CreateResolver("pac_library_unittest.js"), IsOk());
352
353   net::ProxyInfo proxy_info;
354   int result = resolver().GetProxyForURL(GURL("http://www.google.com"),
355                                          &proxy_info, bindings());
356
357   // If the javascript side of this unit-test fails, it will throw a javascript
358   // exception. Otherwise it will return "PROXY success:80".
359   EXPECT_THAT(bindings()->alerts, IsEmpty());
360   EXPECT_THAT(bindings()->errors, IsEmpty());
361
362   ASSERT_THAT(result, IsOk());
363   EXPECT_EQ("success:80", ProxyServerToProxyUri(proxy_info.proxy_server()));
364 }
365
366 // Test marshalling/un-marshalling of values between C++/V8.
367 TEST_F(ProxyResolverV8Test, V8Bindings) {
368   ASSERT_THAT(CreateResolver("bindings.js"), IsOk());
369   bindings()->dns_resolve_result = "127.0.0.1";
370
371   net::ProxyInfo proxy_info;
372   int result = resolver().GetProxyForURL(GURL("http://www.google.com"),
373                                          &proxy_info, bindings());
374
375   EXPECT_THAT(result, IsOk());
376   EXPECT_TRUE(proxy_info.is_direct());
377
378   EXPECT_EQ(0U, bindings()->errors.size());
379
380   // Alert was called 5 times.
381   ASSERT_EQ(5U, bindings()->alerts.size());
382   EXPECT_EQ("undefined", bindings()->alerts[0]);
383   EXPECT_EQ("null", bindings()->alerts[1]);
384   EXPECT_EQ("undefined", bindings()->alerts[2]);
385   EXPECT_EQ("[object Object]", bindings()->alerts[3]);
386   EXPECT_EQ("exception from calling toString()", bindings()->alerts[4]);
387
388   // DnsResolve was called 8 times, however only 2 of those were string
389   // parameters. (so 6 of them failed immediately).
390   ASSERT_EQ(2U, bindings()->dns_resolves.size());
391   EXPECT_EQ("", bindings()->dns_resolves[0]);
392   EXPECT_EQ("arg1", bindings()->dns_resolves[1]);
393
394   // MyIpAddress was called two times.
395   EXPECT_EQ(2, bindings()->my_ip_address_count);
396
397   // MyIpAddressEx was called once.
398   EXPECT_EQ(1, bindings()->my_ip_address_ex_count);
399
400   // DnsResolveEx was called 2 times.
401   ASSERT_EQ(2U, bindings()->dns_resolves_ex.size());
402   EXPECT_EQ("is_resolvable", bindings()->dns_resolves_ex[0]);
403   EXPECT_EQ("foobar", bindings()->dns_resolves_ex[1]);
404 }
405
406 // Test calling a binding (myIpAddress()) from the script's global scope.
407 // http://crbug.com/40026
408 TEST_F(ProxyResolverV8Test, BindingCalledDuringInitialization) {
409   ASSERT_THAT(CreateResolver("binding_from_global.js"), IsOk());
410
411   // myIpAddress() got called during initialization of the script.
412   EXPECT_EQ(1, bindings()->my_ip_address_count);
413
414   net::ProxyInfo proxy_info;
415   int result = resolver().GetProxyForURL(GURL("http://www.google.com"),
416                                          &proxy_info, bindings());
417
418   EXPECT_THAT(result, IsOk());
419   EXPECT_FALSE(proxy_info.is_direct());
420   EXPECT_EQ("127.0.0.1:80", ProxyServerToProxyUri(proxy_info.proxy_server()));
421
422   // Check that no other bindings were called.
423   EXPECT_EQ(0U, bindings()->errors.size());
424   ASSERT_EQ(0U, bindings()->alerts.size());
425   ASSERT_EQ(0U, bindings()->dns_resolves.size());
426   EXPECT_EQ(0, bindings()->my_ip_address_ex_count);
427   ASSERT_EQ(0U, bindings()->dns_resolves_ex.size());
428 }
429
430 // Try loading a PAC script that ends with a comment and has no terminal
431 // newline. This should not cause problems with the PAC utility functions
432 // that we add to the script's environment.
433 // http://crbug.com/22864
434 TEST_F(ProxyResolverV8Test, EndsWithCommentNoNewline) {
435   ASSERT_THAT(CreateResolver("ends_with_comment.js"), IsOk());
436
437   net::ProxyInfo proxy_info;
438   int result = resolver().GetProxyForURL(GURL("http://www.google.com"),
439                                          &proxy_info, bindings());
440
441   EXPECT_THAT(result, IsOk());
442   EXPECT_FALSE(proxy_info.is_direct());
443   EXPECT_EQ("success:80", ProxyServerToProxyUri(proxy_info.proxy_server()));
444 }
445
446 // Try loading a PAC script that ends with a statement and has no terminal
447 // newline. This should not cause problems with the PAC utility functions
448 // that we add to the script's environment.
449 // http://crbug.com/22864
450 TEST_F(ProxyResolverV8Test, EndsWithStatementNoNewline) {
451   ASSERT_THAT(CreateResolver("ends_with_statement_no_semicolon.js"), IsOk());
452
453   net::ProxyInfo proxy_info;
454   int result = resolver().GetProxyForURL(GURL("http://www.google.com"),
455                                          &proxy_info, bindings());
456
457   EXPECT_THAT(result, IsOk());
458   EXPECT_FALSE(proxy_info.is_direct());
459   EXPECT_EQ("success:3", ProxyServerToProxyUri(proxy_info.proxy_server()));
460 }
461
462 // Test the return values from myIpAddress(), myIpAddressEx(), dnsResolve(),
463 // dnsResolveEx(), isResolvable(), isResolvableEx(), when the the binding
464 // returns empty string (failure). This simulates the return values from
465 // those functions when the underlying DNS resolution fails.
466 TEST_F(ProxyResolverV8Test, DNSResolutionFailure) {
467   ASSERT_THAT(CreateResolver("dns_fail.js"), IsOk());
468
469   net::ProxyInfo proxy_info;
470   int result = resolver().GetProxyForURL(GURL("http://www.google.com"),
471                                          &proxy_info, bindings());
472
473   EXPECT_THAT(result, IsOk());
474   EXPECT_FALSE(proxy_info.is_direct());
475   EXPECT_EQ("success:80", ProxyServerToProxyUri(proxy_info.proxy_server()));
476 }
477
478 TEST_F(ProxyResolverV8Test, DNSResolutionOfInternationDomainName) {
479   ASSERT_THAT(CreateResolver("international_domain_names.js"), IsOk());
480
481   // Execute FindProxyForURL().
482   net::ProxyInfo proxy_info;
483   int result = resolver().GetProxyForURL(GURL("http://www.google.com"),
484                                          &proxy_info, bindings());
485
486   EXPECT_THAT(result, IsOk());
487   EXPECT_TRUE(proxy_info.is_direct());
488
489   // Check that the international domain name was converted to punycode
490   // before passing it onto the bindings layer.
491   ASSERT_EQ(1u, bindings()->dns_resolves.size());
492   EXPECT_EQ("xn--bcher-kva.ch", bindings()->dns_resolves[0]);
493
494   ASSERT_EQ(1u, bindings()->dns_resolves_ex.size());
495   EXPECT_EQ("xn--bcher-kva.ch", bindings()->dns_resolves_ex[0]);
496 }
497
498 // Test that when resolving a URL which contains an IPv6 string literal, the
499 // brackets are removed from the host before passing it down to the PAC script.
500 // If we don't do this, then subsequent calls to dnsResolveEx(host) will be
501 // doomed to fail since it won't correspond with a valid name.
502 TEST_F(ProxyResolverV8Test, IPv6HostnamesNotBracketed) {
503   ASSERT_THAT(CreateResolver("resolve_host.js"), IsOk());
504
505   net::ProxyInfo proxy_info;
506   int result = resolver().GetProxyForURL(
507       GURL("http://[abcd::efff]:99/watsupdawg"), &proxy_info, bindings());
508
509   EXPECT_THAT(result, IsOk());
510   EXPECT_TRUE(proxy_info.is_direct());
511
512   // We called dnsResolveEx() exactly once, by passing through the "host"
513   // argument to FindProxyForURL(). The brackets should have been stripped.
514   ASSERT_EQ(1U, bindings()->dns_resolves_ex.size());
515   EXPECT_EQ("abcd::efff", bindings()->dns_resolves_ex[0]);
516 }
517
518 // Test that terminating a script within DnsResolve() leads to eventual
519 // termination of the script. Also test that repeatedly calling terminate is
520 // safe, and running the script again after termination still works.
521 TEST_F(ProxyResolverV8Test, Terminate) {
522   ASSERT_THAT(CreateResolver("terminate.js"), IsOk());
523
524   // Terminate script execution upon reaching dnsResolve(). Note that
525   // termination may not take effect right away (so the subsequent dnsResolve()
526   // and alert() may be run).
527   bindings()->should_terminate = true;
528
529   net::ProxyInfo proxy_info;
530   int result =
531       resolver().GetProxyForURL(GURL("http://hang/"), &proxy_info, bindings());
532
533   // The script execution was terminated.
534   EXPECT_THAT(result, IsError(net::ERR_PAC_SCRIPT_FAILED));
535
536   EXPECT_EQ(1U, bindings()->dns_resolves.size());
537   EXPECT_GE(2U, bindings()->dns_resolves_ex.size());
538   EXPECT_GE(1U, bindings()->alerts.size());
539
540   EXPECT_EQ(1U, bindings()->errors.size());
541
542   // Termination shows up as an uncaught exception without any message.
543   EXPECT_EQ("", bindings()->errors[0]);
544
545   bindings()->errors.clear();
546
547   // Try running the script again, this time with a different input which won't
548   // cause a termination+hang.
549   result = resolver().GetProxyForURL(GURL("http://kittens/"), &proxy_info,
550                                      bindings());
551
552   EXPECT_THAT(result, IsOk());
553   EXPECT_EQ(0u, bindings()->errors.size());
554   EXPECT_EQ("kittens:88", ProxyServerToProxyUri(proxy_info.proxy_server()));
555 }
556
557 }  // namespace
558 }  // namespace proxy_resolver