Home | History | Annotate | Download | only in proxy
      1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "net/proxy/proxy_resolver_v8_tracing.h"
      6 
      7 #include "base/file_util.h"
      8 #include "base/message_loop/message_loop.h"
      9 #include "base/path_service.h"
     10 #include "base/stl_util.h"
     11 #include "base/strings/string_util.h"
     12 #include "base/strings/stringprintf.h"
     13 #include "base/strings/utf_string_conversions.h"
     14 #include "base/synchronization/waitable_event.h"
     15 #include "base/threading/platform_thread.h"
     16 #include "base/values.h"
     17 #include "net/base/net_errors.h"
     18 #include "net/base/net_log.h"
     19 #include "net/base/net_log_unittest.h"
     20 #include "net/base/test_completion_callback.h"
     21 #include "net/dns/host_cache.h"
     22 #include "net/dns/mock_host_resolver.h"
     23 #include "net/proxy/proxy_info.h"
     24 #include "net/proxy/proxy_resolver_error_observer.h"
     25 #include "testing/gtest/include/gtest/gtest.h"
     26 #include "url/gurl.h"
     27 
     28 namespace net {
     29 
     30 namespace {
     31 
     32 class ProxyResolverV8TracingTest : public testing::Test {
     33  public:
     34   virtual void TearDown() OVERRIDE {
     35     // Drain any pending messages, which may be left over from cancellation.
     36     // This way they get reliably run as part of the current test, rather than
     37     // spilling into the next test's execution.
     38     base::MessageLoop::current()->RunUntilIdle();
     39   }
     40 };
     41 
     42 scoped_refptr<ProxyResolverScriptData> LoadScriptData(const char* filename) {
     43   base::FilePath path;
     44   PathService::Get(base::DIR_SOURCE_ROOT, &path);
     45   path = path.AppendASCII("net");
     46   path = path.AppendASCII("data");
     47   path = path.AppendASCII("proxy_resolver_v8_tracing_unittest");
     48   path = path.AppendASCII(filename);
     49 
     50   // Try to read the file from disk.
     51   std::string file_contents;
     52   bool ok = base::ReadFileToString(path, &file_contents);
     53 
     54   // If we can't load the file from disk, something is misconfigured.
     55   EXPECT_TRUE(ok) << "Failed to read file: " << path.value();
     56 
     57   // Load the PAC script into the ProxyResolver.
     58   return ProxyResolverScriptData::FromUTF8(file_contents);
     59 }
     60 
     61 void InitResolver(ProxyResolverV8Tracing* resolver, const char* filename) {
     62   TestCompletionCallback callback;
     63   int rv =
     64       resolver->SetPacScript(LoadScriptData(filename), callback.callback());
     65   EXPECT_EQ(ERR_IO_PENDING, rv);
     66   EXPECT_EQ(OK, callback.WaitForResult());
     67 }
     68 
     69 class MockErrorObserver : public ProxyResolverErrorObserver {
     70  public:
     71   MockErrorObserver() : event_(true, false) {}
     72 
     73   virtual void OnPACScriptError(int line_number,
     74                                 const base::string16& error) OVERRIDE {
     75     {
     76       base::AutoLock l(lock_);
     77       output += base::StringPrintf("Error: line %d: %s\n", line_number,
     78                                    base::UTF16ToASCII(error).c_str());
     79     }
     80     event_.Signal();
     81   }
     82 
     83   std::string GetOutput() {
     84     base::AutoLock l(lock_);
     85     return output;
     86   }
     87 
     88   void WaitForOutput() {
     89     event_.Wait();
     90   }
     91 
     92  private:
     93   base::Lock lock_;
     94   std::string output;
     95 
     96   base::WaitableEvent event_;
     97 };
     98 
     99 TEST_F(ProxyResolverV8TracingTest, Simple) {
    100   CapturingNetLog log;
    101   CapturingBoundNetLog request_log;
    102   MockCachingHostResolver host_resolver;
    103   MockErrorObserver* error_observer = new MockErrorObserver;
    104   ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
    105 
    106   InitResolver(&resolver, "simple.js");
    107 
    108   TestCompletionCallback callback;
    109   ProxyInfo proxy_info;
    110 
    111   int rv = resolver.GetProxyForURL(
    112       GURL("http://foo/"), &proxy_info, callback.callback(),
    113       NULL, request_log.bound());
    114 
    115   EXPECT_EQ(ERR_IO_PENDING, rv);
    116   EXPECT_EQ(OK, callback.WaitForResult());
    117 
    118   EXPECT_EQ("foo:99", proxy_info.proxy_server().ToURI());
    119 
    120   EXPECT_EQ(0u, host_resolver.num_resolve());
    121 
    122   // There were no errors.
    123   EXPECT_EQ("", error_observer->GetOutput());
    124 
    125   // Check the NetLogs -- nothing was logged.
    126   EXPECT_EQ(0u, log.GetSize());
    127   EXPECT_EQ(0u, request_log.GetSize());
    128 }
    129 
    130 TEST_F(ProxyResolverV8TracingTest, JavascriptError) {
    131   CapturingNetLog log;
    132   CapturingBoundNetLog request_log;
    133   MockCachingHostResolver host_resolver;
    134   MockErrorObserver* error_observer = new MockErrorObserver;
    135   ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
    136 
    137   InitResolver(&resolver, "error.js");
    138 
    139   TestCompletionCallback callback;
    140   ProxyInfo proxy_info;
    141 
    142   int rv = resolver.GetProxyForURL(
    143       GURL("http://throw-an-error/"), &proxy_info, callback.callback(), NULL,
    144       request_log.bound());
    145 
    146   EXPECT_EQ(ERR_IO_PENDING, rv);
    147   EXPECT_EQ(ERR_PAC_SCRIPT_FAILED, callback.WaitForResult());
    148 
    149   EXPECT_EQ(0u, host_resolver.num_resolve());
    150 
    151   EXPECT_EQ("Error: line 5: Uncaught TypeError: Cannot read property 'split' "
    152             "of null\n", error_observer->GetOutput());
    153 
    154   // Check the NetLogs -- there was 1 alert and 1 javascript error, and they
    155   // were output to both the global log, and per-request log.
    156   CapturingNetLog::CapturedEntryList entries_list[2];
    157   log.GetEntries(&entries_list[0]);
    158   request_log.GetEntries(&entries_list[1]);
    159 
    160   for (size_t list_i = 0; list_i < arraysize(entries_list); list_i++) {
    161     const CapturingNetLog::CapturedEntryList& entries = entries_list[list_i];
    162     EXPECT_EQ(2u, entries.size());
    163     EXPECT_TRUE(
    164         LogContainsEvent(entries, 0, NetLog::TYPE_PAC_JAVASCRIPT_ALERT,
    165                          NetLog::PHASE_NONE));
    166     EXPECT_TRUE(
    167         LogContainsEvent(entries, 1, NetLog::TYPE_PAC_JAVASCRIPT_ERROR,
    168                          NetLog::PHASE_NONE));
    169 
    170     EXPECT_EQ("{\"message\":\"Prepare to DIE!\"}", entries[0].GetParamsJson());
    171     EXPECT_EQ("{\"line_number\":5,\"message\":\"Uncaught TypeError: Cannot "
    172               "read property 'split' of null\"}", entries[1].GetParamsJson());
    173   }
    174 }
    175 
    176 TEST_F(ProxyResolverV8TracingTest, TooManyAlerts) {
    177   CapturingNetLog log;
    178   CapturingBoundNetLog request_log;
    179   MockCachingHostResolver host_resolver;
    180   MockErrorObserver* error_observer = new MockErrorObserver;
    181   ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
    182 
    183   InitResolver(&resolver, "too_many_alerts.js");
    184 
    185   TestCompletionCallback callback;
    186   ProxyInfo proxy_info;
    187 
    188   int rv = resolver.GetProxyForURL(
    189       GURL("http://foo/"),
    190       &proxy_info,
    191       callback.callback(),
    192       NULL,
    193       request_log.bound());
    194 
    195   EXPECT_EQ(ERR_IO_PENDING, rv);
    196   EXPECT_EQ(OK, callback.WaitForResult());
    197 
    198   // Iteration1 does a DNS resolve
    199   // Iteration2 exceeds the alert buffer
    200   // Iteration3 runs in blocking mode and completes
    201   EXPECT_EQ("foo:3", proxy_info.proxy_server().ToURI());
    202 
    203   EXPECT_EQ(1u, host_resolver.num_resolve());
    204 
    205   // No errors.
    206   EXPECT_EQ("", error_observer->GetOutput());
    207 
    208   // Check the NetLogs -- the script generated 50 alerts, which were mirrored
    209   // to both the global and per-request logs.
    210   CapturingNetLog::CapturedEntryList entries_list[2];
    211   log.GetEntries(&entries_list[0]);
    212   request_log.GetEntries(&entries_list[1]);
    213 
    214   for (size_t list_i = 0; list_i < arraysize(entries_list); list_i++) {
    215     const CapturingNetLog::CapturedEntryList& entries = entries_list[list_i];
    216     EXPECT_EQ(50u, entries.size());
    217     for (size_t i = 0; i < entries.size(); ++i) {
    218       ASSERT_TRUE(
    219           LogContainsEvent(entries, i, NetLog::TYPE_PAC_JAVASCRIPT_ALERT,
    220                            NetLog::PHASE_NONE));
    221     }
    222   }
    223 }
    224 
    225 // Verify that buffered alerts cannot grow unboundedly, even when the message is
    226 // empty string.
    227 TEST_F(ProxyResolverV8TracingTest, TooManyEmptyAlerts) {
    228   CapturingNetLog log;
    229   CapturingBoundNetLog request_log;
    230   MockCachingHostResolver host_resolver;
    231   MockErrorObserver* error_observer = new MockErrorObserver;
    232   ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
    233 
    234   InitResolver(&resolver, "too_many_empty_alerts.js");
    235 
    236   TestCompletionCallback callback;
    237   ProxyInfo proxy_info;
    238 
    239   int rv = resolver.GetProxyForURL(
    240       GURL("http://foo/"),
    241       &proxy_info,
    242       callback.callback(),
    243       NULL,
    244       request_log.bound());
    245 
    246   EXPECT_EQ(ERR_IO_PENDING, rv);
    247   EXPECT_EQ(OK, callback.WaitForResult());
    248 
    249   EXPECT_EQ("foo:3", proxy_info.proxy_server().ToURI());
    250 
    251   EXPECT_EQ(1u, host_resolver.num_resolve());
    252 
    253   // No errors.
    254   EXPECT_EQ("", error_observer->GetOutput());
    255 
    256   // Check the NetLogs -- the script generated 50 alerts, which were mirrored
    257   // to both the global and per-request logs.
    258   CapturingNetLog::CapturedEntryList entries_list[2];
    259   log.GetEntries(&entries_list[0]);
    260   request_log.GetEntries(&entries_list[1]);
    261 
    262   for (size_t list_i = 0; list_i < arraysize(entries_list); list_i++) {
    263     const CapturingNetLog::CapturedEntryList& entries = entries_list[list_i];
    264     EXPECT_EQ(1000u, entries.size());
    265     for (size_t i = 0; i < entries.size(); ++i) {
    266       ASSERT_TRUE(
    267           LogContainsEvent(entries, i, NetLog::TYPE_PAC_JAVASCRIPT_ALERT,
    268                            NetLog::PHASE_NONE));
    269     }
    270   }
    271 }
    272 
    273 // This test runs a PAC script that issues a sequence of DNS resolves. The test
    274 // verifies the final result, and that the underlying DNS resolver received
    275 // the correct set of queries.
    276 TEST_F(ProxyResolverV8TracingTest, Dns) {
    277   CapturingNetLog log;
    278   CapturingBoundNetLog request_log;
    279   MockCachingHostResolver host_resolver;
    280   MockErrorObserver* error_observer = new MockErrorObserver;
    281   ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
    282 
    283   host_resolver.rules()->AddRuleForAddressFamily(
    284       "host1", ADDRESS_FAMILY_IPV4, "166.155.144.44");
    285   host_resolver.rules()
    286       ->AddIPLiteralRule("host1", "::1,192.168.1.1", std::string());
    287   host_resolver.rules()->AddSimulatedFailure("host2");
    288   host_resolver.rules()->AddRule("host3", "166.155.144.33");
    289   host_resolver.rules()->AddRule("host5", "166.155.144.55");
    290   host_resolver.rules()->AddSimulatedFailure("host6");
    291   host_resolver.rules()->AddRuleForAddressFamily(
    292       "*", ADDRESS_FAMILY_IPV4, "122.133.144.155");
    293   host_resolver.rules()->AddRule("*", "133.122.100.200");
    294 
    295   InitResolver(&resolver, "dns.js");
    296 
    297   TestCompletionCallback callback;
    298   ProxyInfo proxy_info;
    299 
    300   int rv = resolver.GetProxyForURL(
    301       GURL("http://foo/"),
    302       &proxy_info,
    303       callback.callback(),
    304       NULL,
    305       request_log.bound());
    306 
    307   EXPECT_EQ(ERR_IO_PENDING, rv);
    308   EXPECT_EQ(OK, callback.WaitForResult());
    309 
    310   // The test does 13 DNS resolution, however only 7 of them are unique.
    311   EXPECT_EQ(7u, host_resolver.num_resolve());
    312 
    313   const char* kExpectedResult =
    314     "122.133.144.155-"  // myIpAddress()
    315     "null-"  // dnsResolve('')
    316     "__1_192.168.1.1-"  // dnsResolveEx('host1')
    317     "null-"  // dnsResolve('host2')
    318     "166.155.144.33-"  // dnsResolve('host3')
    319     "122.133.144.155-"  // myIpAddress()
    320     "166.155.144.33-"  // dnsResolve('host3')
    321     "__1_192.168.1.1-"  // dnsResolveEx('host1')
    322     "122.133.144.155-"  // myIpAddress()
    323     "null-"  // dnsResolve('host2')
    324     "-"  // dnsResolveEx('host6')
    325     "133.122.100.200-"  // myIpAddressEx()
    326     "166.155.144.44"  // dnsResolve('host1')
    327     ":99";
    328 
    329   EXPECT_EQ(kExpectedResult, proxy_info.proxy_server().ToURI());
    330 
    331   // No errors.
    332   EXPECT_EQ("", error_observer->GetOutput());
    333 
    334   // Check the NetLogs -- the script generated 1 alert, mirrored to both
    335   // the per-request and global logs.
    336   CapturingNetLog::CapturedEntryList entries_list[2];
    337   log.GetEntries(&entries_list[0]);
    338   request_log.GetEntries(&entries_list[1]);
    339 
    340   for (size_t list_i = 0; list_i < arraysize(entries_list); list_i++) {
    341     const CapturingNetLog::CapturedEntryList& entries = entries_list[list_i];
    342     EXPECT_EQ(1u, entries.size());
    343     EXPECT_TRUE(
    344         LogContainsEvent(entries, 0, NetLog::TYPE_PAC_JAVASCRIPT_ALERT,
    345                          NetLog::PHASE_NONE));
    346     EXPECT_EQ("{\"message\":\"iteration: 7\"}", entries[0].GetParamsJson());
    347   }
    348 }
    349 
    350 // This test runs a PAC script that does "myIpAddress()" followed by
    351 // "dnsResolve()". This requires 2 restarts. However once the HostResolver's
    352 // cache is warmed, subsequent calls should take 0 restarts.
    353 TEST_F(ProxyResolverV8TracingTest, DnsChecksCache) {
    354   CapturingNetLog log;
    355   CapturingBoundNetLog request_log;
    356   MockCachingHostResolver host_resolver;
    357   MockErrorObserver* error_observer = new MockErrorObserver;
    358   ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
    359 
    360   host_resolver.rules()->AddRule("foopy", "166.155.144.11");
    361   host_resolver.rules()->AddRule("*", "122.133.144.155");
    362 
    363   InitResolver(&resolver, "simple_dns.js");
    364 
    365   TestCompletionCallback callback1;
    366   TestCompletionCallback callback2;
    367   ProxyInfo proxy_info;
    368 
    369   int rv = resolver.GetProxyForURL(
    370       GURL("http://foopy/req1"),
    371       &proxy_info,
    372       callback1.callback(),
    373       NULL,
    374       request_log.bound());
    375 
    376   EXPECT_EQ(ERR_IO_PENDING, rv);
    377   EXPECT_EQ(OK, callback1.WaitForResult());
    378 
    379   // The test does 2 DNS resolutions.
    380   EXPECT_EQ(2u, host_resolver.num_resolve());
    381 
    382   // The first request took 2 restarts, hence on g_iteration=3.
    383   EXPECT_EQ("166.155.144.11:3", proxy_info.proxy_server().ToURI());
    384 
    385   rv = resolver.GetProxyForURL(
    386       GURL("http://foopy/req2"),
    387       &proxy_info,
    388       callback2.callback(),
    389       NULL,
    390       request_log.bound());
    391 
    392   EXPECT_EQ(ERR_IO_PENDING, rv);
    393   EXPECT_EQ(OK, callback2.WaitForResult());
    394 
    395   EXPECT_EQ(4u, host_resolver.num_resolve());
    396 
    397   // This time no restarts were required, so g_iteration incremented by 1.
    398   EXPECT_EQ("166.155.144.11:4", proxy_info.proxy_server().ToURI());
    399 
    400   // No errors.
    401   EXPECT_EQ("", error_observer->GetOutput());
    402 
    403   EXPECT_EQ(0u, log.GetSize());
    404   EXPECT_EQ(0u, request_log.GetSize());
    405 }
    406 
    407 // This test runs a weird PAC script that was designed to defeat the DNS tracing
    408 // optimization. The proxy resolver should detect the inconsistency and
    409 // fall-back to synchronous mode execution.
    410 TEST_F(ProxyResolverV8TracingTest, FallBackToSynchronous1) {
    411   CapturingNetLog log;
    412   CapturingBoundNetLog request_log;
    413   MockCachingHostResolver host_resolver;
    414   MockErrorObserver* error_observer = new MockErrorObserver;
    415   ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
    416 
    417   host_resolver.rules()->AddRule("host1", "166.155.144.11");
    418   host_resolver.rules()->AddRule("crazy4", "133.199.111.4");
    419   host_resolver.rules()->AddRule("*", "122.133.144.155");
    420 
    421   InitResolver(&resolver, "global_sideffects1.js");
    422 
    423   TestCompletionCallback callback;
    424   ProxyInfo proxy_info;
    425 
    426   int rv = resolver.GetProxyForURL(
    427       GURL("http://foo/"), &proxy_info, callback.callback(), NULL,
    428       request_log.bound());
    429   EXPECT_EQ(ERR_IO_PENDING, rv);
    430   EXPECT_EQ(OK, callback.WaitForResult());
    431 
    432   // The script itself only does 2 DNS resolves per execution, however it
    433   // constructs the hostname using a global counter which changes on each
    434   // invocation.
    435   EXPECT_EQ(3u, host_resolver.num_resolve());
    436 
    437   EXPECT_EQ("166.155.144.11-133.199.111.4:100",
    438             proxy_info.proxy_server().ToURI());
    439 
    440   // No errors.
    441   EXPECT_EQ("", error_observer->GetOutput());
    442 
    443   // Check the NetLogs -- the script generated 1 alert, mirrored to both
    444   // the per-request and global logs.
    445   CapturingNetLog::CapturedEntryList entries_list[2];
    446   log.GetEntries(&entries_list[0]);
    447   request_log.GetEntries(&entries_list[1]);
    448 
    449   for (size_t list_i = 0; list_i < arraysize(entries_list); list_i++) {
    450     const CapturingNetLog::CapturedEntryList& entries = entries_list[list_i];
    451     EXPECT_EQ(1u, entries.size());
    452     EXPECT_TRUE(
    453         LogContainsEvent(entries, 0, NetLog::TYPE_PAC_JAVASCRIPT_ALERT,
    454                          NetLog::PHASE_NONE));
    455     EXPECT_EQ("{\"message\":\"iteration: 4\"}", entries[0].GetParamsJson());
    456   }
    457 }
    458 
    459 // This test runs a weird PAC script that was designed to defeat the DNS tracing
    460 // optimization. The proxy resolver should detect the inconsistency and
    461 // fall-back to synchronous mode execution.
    462 TEST_F(ProxyResolverV8TracingTest, FallBackToSynchronous2) {
    463   CapturingNetLog log;
    464   CapturingBoundNetLog request_log;
    465   MockCachingHostResolver host_resolver;
    466   MockErrorObserver* error_observer = new MockErrorObserver;
    467   ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
    468 
    469   host_resolver.rules()->AddRule("host1", "166.155.144.11");
    470   host_resolver.rules()->AddRule("host2", "166.155.144.22");
    471   host_resolver.rules()->AddRule("host3", "166.155.144.33");
    472   host_resolver.rules()->AddRule("host4", "166.155.144.44");
    473   host_resolver.rules()->AddRule("*", "122.133.144.155");
    474 
    475   InitResolver(&resolver, "global_sideffects2.js");
    476 
    477   TestCompletionCallback callback;
    478   ProxyInfo proxy_info;
    479 
    480   int rv = resolver.GetProxyForURL(
    481       GURL("http://foo/"), &proxy_info, callback.callback(), NULL,
    482       request_log.bound());
    483   EXPECT_EQ(ERR_IO_PENDING, rv);
    484   EXPECT_EQ(OK, callback.WaitForResult());
    485 
    486   EXPECT_EQ(3u, host_resolver.num_resolve());
    487 
    488   EXPECT_EQ("166.155.144.44:100", proxy_info.proxy_server().ToURI());
    489 
    490   // No errors.
    491   EXPECT_EQ("", error_observer->GetOutput());
    492 
    493   // Check the NetLogs -- nothing was logged.
    494   EXPECT_EQ(0u, log.GetSize());
    495   EXPECT_EQ(0u, request_log.GetSize());
    496 }
    497 
    498 // This test runs a weird PAC script that yields a never ending sequence
    499 // of DNS resolves when restarting. Running it will hit the maximum
    500 // DNS resolves per request limit (20) after which every DNS resolve will
    501 // fail.
    502 TEST_F(ProxyResolverV8TracingTest, InfiniteDNSSequence) {
    503   CapturingNetLog log;
    504   CapturingBoundNetLog request_log;
    505   MockCachingHostResolver host_resolver;
    506   MockErrorObserver* error_observer = new MockErrorObserver;
    507   ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
    508 
    509   host_resolver.rules()->AddRule("host*", "166.155.144.11");
    510   host_resolver.rules()->AddRule("*", "122.133.144.155");
    511 
    512   InitResolver(&resolver, "global_sideffects3.js");
    513 
    514   TestCompletionCallback callback;
    515   ProxyInfo proxy_info;
    516 
    517   int rv = resolver.GetProxyForURL(
    518       GURL("http://foo/"), &proxy_info, callback.callback(), NULL,
    519       request_log.bound());
    520   EXPECT_EQ(ERR_IO_PENDING, rv);
    521   EXPECT_EQ(OK, callback.WaitForResult());
    522 
    523   EXPECT_EQ(20u, host_resolver.num_resolve());
    524 
    525   EXPECT_EQ(
    526       "166.155.144.11-166.155.144.11-166.155.144.11-166.155.144.11-"
    527       "166.155.144.11-166.155.144.11-166.155.144.11-166.155.144.11-"
    528       "166.155.144.11-166.155.144.11-166.155.144.11-166.155.144.11-"
    529       "166.155.144.11-166.155.144.11-166.155.144.11-166.155.144.11-"
    530       "166.155.144.11-166.155.144.11-166.155.144.11-166.155.144.11-"
    531       "null:21", proxy_info.proxy_server().ToURI());
    532 
    533   // No errors.
    534   EXPECT_EQ("", error_observer->GetOutput());
    535 
    536   // Check the NetLogs -- 1 alert was logged.
    537   EXPECT_EQ(1u, log.GetSize());
    538   EXPECT_EQ(1u, request_log.GetSize());
    539 }
    540 
    541 // This test runs a weird PAC script that yields a never ending sequence
    542 // of DNS resolves when restarting. Running it will hit the maximum
    543 // DNS resolves per request limit (20) after which every DNS resolve will
    544 // fail.
    545 TEST_F(ProxyResolverV8TracingTest, InfiniteDNSSequence2) {
    546   CapturingNetLog log;
    547   CapturingBoundNetLog request_log;
    548   MockCachingHostResolver host_resolver;
    549   MockErrorObserver* error_observer = new MockErrorObserver;
    550   ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
    551 
    552   host_resolver.rules()->AddRule("host*", "166.155.144.11");
    553   host_resolver.rules()->AddRule("*", "122.133.144.155");
    554 
    555   InitResolver(&resolver, "global_sideffects4.js");
    556 
    557   TestCompletionCallback callback;
    558   ProxyInfo proxy_info;
    559 
    560   int rv = resolver.GetProxyForURL(
    561       GURL("http://foo/"), &proxy_info, callback.callback(), NULL,
    562       request_log.bound());
    563   EXPECT_EQ(ERR_IO_PENDING, rv);
    564   EXPECT_EQ(OK, callback.WaitForResult());
    565 
    566   EXPECT_EQ(20u, host_resolver.num_resolve());
    567 
    568   EXPECT_EQ("null21:34", proxy_info.proxy_server().ToURI());
    569 
    570   // No errors.
    571   EXPECT_EQ("", error_observer->GetOutput());
    572 
    573   // Check the NetLogs -- 1 alert was logged.
    574   EXPECT_EQ(1u, log.GetSize());
    575   EXPECT_EQ(1u, request_log.GetSize());
    576 }
    577 
    578 void DnsDuringInitHelper(bool synchronous_host_resolver) {
    579   CapturingNetLog log;
    580   CapturingBoundNetLog request_log;
    581   MockCachingHostResolver host_resolver;
    582   host_resolver.set_synchronous_mode(synchronous_host_resolver);
    583   MockErrorObserver* error_observer = new MockErrorObserver;
    584   ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
    585 
    586   host_resolver.rules()->AddRule("host1", "91.13.12.1");
    587   host_resolver.rules()->AddRule("host2", "91.13.12.2");
    588 
    589   InitResolver(&resolver, "dns_during_init.js");
    590 
    591   // Initialization did 2 dnsResolves.
    592   EXPECT_EQ(2u, host_resolver.num_resolve());
    593 
    594   host_resolver.rules()->ClearRules();
    595   host_resolver.GetHostCache()->clear();
    596 
    597   host_resolver.rules()->AddRule("host1", "145.88.13.3");
    598   host_resolver.rules()->AddRule("host2", "137.89.8.45");
    599 
    600   TestCompletionCallback callback;
    601   ProxyInfo proxy_info;
    602 
    603   int rv = resolver.GetProxyForURL(
    604       GURL("http://foo/"), &proxy_info, callback.callback(), NULL,
    605       request_log.bound());
    606   EXPECT_EQ(ERR_IO_PENDING, rv);
    607   EXPECT_EQ(OK, callback.WaitForResult());
    608 
    609   // Fetched host1 and host2 again, since the ones done during initialization
    610   // should not have been cached.
    611   EXPECT_EQ(4u, host_resolver.num_resolve());
    612 
    613   EXPECT_EQ("91.13.12.1-91.13.12.2-145.88.13.3-137.89.8.45:99",
    614             proxy_info.proxy_server().ToURI());
    615 
    616   // Check the NetLogs -- the script generated 2 alerts during initialization.
    617   EXPECT_EQ(0u, request_log.GetSize());
    618   CapturingNetLog::CapturedEntryList entries;
    619   log.GetEntries(&entries);
    620 
    621   ASSERT_EQ(2u, entries.size());
    622   EXPECT_TRUE(
    623       LogContainsEvent(entries, 0, NetLog::TYPE_PAC_JAVASCRIPT_ALERT,
    624                        NetLog::PHASE_NONE));
    625   EXPECT_TRUE(
    626       LogContainsEvent(entries, 1, NetLog::TYPE_PAC_JAVASCRIPT_ALERT,
    627                        NetLog::PHASE_NONE));
    628 
    629   EXPECT_EQ("{\"message\":\"Watsup\"}", entries[0].GetParamsJson());
    630   EXPECT_EQ("{\"message\":\"Watsup2\"}", entries[1].GetParamsJson());
    631 }
    632 
    633 // Tests a PAC script which does DNS resolves during initialization.
    634 TEST_F(ProxyResolverV8TracingTest, DnsDuringInit) {
    635   // Test with both both a host resolver that always completes asynchronously,
    636   // and then again with one that completes synchronously.
    637   DnsDuringInitHelper(false);
    638   DnsDuringInitHelper(true);
    639 }
    640 
    641 void CrashCallback(int) {
    642   // Be extra sure that if the callback ever gets invoked, the test will fail.
    643   CHECK(false);
    644 }
    645 
    646 // Start some requests, cancel them all, and then destroy the resolver.
    647 // Note the execution order for this test can vary. Since multiple
    648 // threads are involved, the cancellation may be received a different
    649 // times.
    650 TEST_F(ProxyResolverV8TracingTest, CancelAll) {
    651   MockCachingHostResolver host_resolver;
    652   MockErrorObserver* error_observer = new MockErrorObserver;
    653   ProxyResolverV8Tracing resolver(&host_resolver, error_observer, NULL);
    654 
    655   host_resolver.rules()->AddSimulatedFailure("*");
    656 
    657   InitResolver(&resolver, "dns.js");
    658 
    659   const size_t kNumRequests = 5;
    660   ProxyInfo proxy_info[kNumRequests];
    661   ProxyResolver::RequestHandle request[kNumRequests];
    662 
    663   for (size_t i = 0; i < kNumRequests; ++i) {
    664     int rv = resolver.GetProxyForURL(
    665         GURL("http://foo/"), &proxy_info[i],
    666         base::Bind(&CrashCallback), &request[i], BoundNetLog());
    667     EXPECT_EQ(ERR_IO_PENDING, rv);
    668   }
    669 
    670   for (size_t i = 0; i < kNumRequests; ++i) {
    671     resolver.CancelRequest(request[i]);
    672   }
    673 }
    674 
    675 // Note the execution order for this test can vary. Since multiple
    676 // threads are involved, the cancellation may be received a different
    677 // times.
    678 TEST_F(ProxyResolverV8TracingTest, CancelSome) {
    679   MockCachingHostResolver host_resolver;
    680   MockErrorObserver* error_observer = new MockErrorObserver;
    681   ProxyResolverV8Tracing resolver(&host_resolver, error_observer, NULL);
    682 
    683   host_resolver.rules()->AddSimulatedFailure("*");
    684 
    685   InitResolver(&resolver, "dns.js");
    686 
    687   ProxyInfo proxy_info1;
    688   ProxyInfo proxy_info2;
    689   ProxyResolver::RequestHandle request1;
    690   ProxyResolver::RequestHandle request2;
    691   TestCompletionCallback callback;
    692 
    693   int rv = resolver.GetProxyForURL(
    694       GURL("http://foo/"), &proxy_info1,
    695       base::Bind(&CrashCallback), &request1, BoundNetLog());
    696   EXPECT_EQ(ERR_IO_PENDING, rv);
    697 
    698   rv = resolver.GetProxyForURL(
    699       GURL("http://foo/"), &proxy_info2,
    700       callback.callback(), &request2, BoundNetLog());
    701   EXPECT_EQ(ERR_IO_PENDING, rv);
    702 
    703   resolver.CancelRequest(request1);
    704 
    705   EXPECT_EQ(OK, callback.WaitForResult());
    706 }
    707 
    708 // Cancel a request after it has finished running on the worker thread, and has
    709 // posted a task the completion task back to origin thread.
    710 TEST_F(ProxyResolverV8TracingTest, CancelWhilePendingCompletionTask) {
    711   MockCachingHostResolver host_resolver;
    712   MockErrorObserver* error_observer = new MockErrorObserver;
    713   ProxyResolverV8Tracing resolver(&host_resolver, error_observer, NULL);
    714 
    715   host_resolver.rules()->AddSimulatedFailure("*");
    716 
    717   InitResolver(&resolver, "error.js");
    718 
    719   ProxyInfo proxy_info1;
    720   ProxyInfo proxy_info2;
    721   ProxyInfo proxy_info3;
    722   ProxyResolver::RequestHandle request1;
    723   ProxyResolver::RequestHandle request2;
    724   ProxyResolver::RequestHandle request3;
    725   TestCompletionCallback callback;
    726 
    727   int rv = resolver.GetProxyForURL(
    728       GURL("http://foo/"), &proxy_info1,
    729       base::Bind(&CrashCallback), &request1, BoundNetLog());
    730   EXPECT_EQ(ERR_IO_PENDING, rv);
    731 
    732   rv = resolver.GetProxyForURL(
    733       GURL("http://throw-an-error/"), &proxy_info2,
    734       callback.callback(), &request2, BoundNetLog());
    735   EXPECT_EQ(ERR_IO_PENDING, rv);
    736 
    737   // Wait until the first request has finished running on the worker thread.
    738   // (The second request will output an error).
    739   error_observer->WaitForOutput();
    740 
    741   // Cancel the first request, while it has a pending completion task on
    742   // the origin thread.
    743   resolver.CancelRequest(request1);
    744 
    745   EXPECT_EQ(ERR_PAC_SCRIPT_FAILED, callback.WaitForResult());
    746 
    747   // Start another request, to make sure it is able to complete.
    748   rv = resolver.GetProxyForURL(
    749       GURL("http://i-have-no-idea-what-im-doing/"), &proxy_info3,
    750       callback.callback(), &request3, BoundNetLog());
    751   EXPECT_EQ(ERR_IO_PENDING, rv);
    752 
    753   EXPECT_EQ(OK, callback.WaitForResult());
    754 
    755   EXPECT_EQ("i-approve-this-message:42",
    756             proxy_info3.proxy_server().ToURI());
    757 }
    758 
    759 // This implementation of HostResolver allows blocking until a resolve request
    760 // has been received. The resolve requests it receives will never be completed.
    761 class BlockableHostResolver : public HostResolver {
    762  public:
    763   BlockableHostResolver()
    764       : num_cancelled_requests_(0), waiting_for_resolve_(false) {}
    765 
    766   virtual int Resolve(const RequestInfo& info,
    767                       RequestPriority priority,
    768                       AddressList* addresses,
    769                       const CompletionCallback& callback,
    770                       RequestHandle* out_req,
    771                       const BoundNetLog& net_log) OVERRIDE {
    772     EXPECT_FALSE(callback.is_null());
    773     EXPECT_TRUE(out_req);
    774 
    775     if (!action_.is_null())
    776       action_.Run();
    777 
    778     // Indicate to the caller that a request was received.
    779     EXPECT_TRUE(waiting_for_resolve_);
    780     base::MessageLoop::current()->Quit();
    781 
    782     // This line is intentionally after action_.Run(), since one of the
    783     // tests does a cancellation inside of Resolve(), and it is more
    784     // interesting if *out_req hasn't been written yet at that point.
    785     *out_req = reinterpret_cast<RequestHandle*>(1);  // Magic value.
    786 
    787     // Return ERR_IO_PENDING as this request will NEVER be completed.
    788     // Expectation is for the caller to later cancel the request.
    789     return ERR_IO_PENDING;
    790   }
    791 
    792   virtual int ResolveFromCache(const RequestInfo& info,
    793                                AddressList* addresses,
    794                                const BoundNetLog& net_log) OVERRIDE {
    795     NOTREACHED();
    796     return ERR_DNS_CACHE_MISS;
    797   }
    798 
    799   virtual void CancelRequest(RequestHandle req) OVERRIDE {
    800     EXPECT_EQ(reinterpret_cast<RequestHandle*>(1), req);
    801     num_cancelled_requests_++;
    802   }
    803 
    804   void SetAction(const base::Callback<void(void)>& action) {
    805     action_ = action;
    806   }
    807 
    808   // Waits until Resolve() has been called.
    809   void WaitUntilRequestIsReceived() {
    810     waiting_for_resolve_ = true;
    811     base::MessageLoop::current()->Run();
    812     DCHECK(waiting_for_resolve_);
    813     waiting_for_resolve_ = false;
    814   }
    815 
    816   int num_cancelled_requests() const {
    817     return num_cancelled_requests_;
    818   }
    819 
    820  private:
    821   int num_cancelled_requests_;
    822   bool waiting_for_resolve_;
    823   base::Callback<void(void)> action_;
    824 };
    825 
    826 // This cancellation test exercises a more predictable cancellation codepath --
    827 // when the request has an outstanding DNS request in flight.
    828 TEST_F(ProxyResolverV8TracingTest, CancelWhileOutstandingNonBlockingDns) {
    829   BlockableHostResolver host_resolver;
    830   MockErrorObserver* error_observer = new MockErrorObserver;
    831   ProxyResolverV8Tracing resolver(&host_resolver, error_observer, NULL);
    832 
    833   InitResolver(&resolver, "dns.js");
    834 
    835   ProxyInfo proxy_info1;
    836   ProxyInfo proxy_info2;
    837   ProxyResolver::RequestHandle request1;
    838   ProxyResolver::RequestHandle request2;
    839 
    840   int rv = resolver.GetProxyForURL(
    841       GURL("http://foo/req1"), &proxy_info1,
    842       base::Bind(&CrashCallback), &request1, BoundNetLog());
    843 
    844   EXPECT_EQ(ERR_IO_PENDING, rv);
    845 
    846   host_resolver.WaitUntilRequestIsReceived();
    847 
    848   rv = resolver.GetProxyForURL(
    849       GURL("http://foo/req2"), &proxy_info2,
    850       base::Bind(&CrashCallback), &request2, BoundNetLog());
    851 
    852   EXPECT_EQ(ERR_IO_PENDING, rv);
    853 
    854   host_resolver.WaitUntilRequestIsReceived();
    855 
    856   resolver.CancelRequest(request1);
    857   resolver.CancelRequest(request2);
    858 
    859   EXPECT_EQ(2, host_resolver.num_cancelled_requests());
    860 
    861   // After leaving this scope, the ProxyResolver is destroyed.
    862   // This should not cause any problems, as the outstanding work
    863   // should have been cancelled.
    864 }
    865 
    866 void CancelRequestAndPause(ProxyResolverV8Tracing* resolver,
    867                            ProxyResolver::RequestHandle request) {
    868   resolver->CancelRequest(request);
    869 
    870   // Sleep for a little bit. This makes it more likely for the worker
    871   // thread to have returned from its call, and serves as a regression
    872   // test for http://crbug.com/173373.
    873   base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(30));
    874 }
    875 
    876 // In non-blocking mode, the worker thread actually does block for
    877 // a short time to see if the result is in the DNS cache. Test
    878 // cancellation while the worker thread is waiting on this event.
    879 TEST_F(ProxyResolverV8TracingTest, CancelWhileBlockedInNonBlockingDns) {
    880   BlockableHostResolver host_resolver;
    881   MockErrorObserver* error_observer = new MockErrorObserver;
    882   ProxyResolverV8Tracing resolver(&host_resolver, error_observer, NULL);
    883 
    884   InitResolver(&resolver, "dns.js");
    885 
    886   ProxyInfo proxy_info;
    887   ProxyResolver::RequestHandle request;
    888 
    889   int rv = resolver.GetProxyForURL(
    890       GURL("http://foo/"), &proxy_info,
    891       base::Bind(&CrashCallback), &request, BoundNetLog());
    892 
    893   EXPECT_EQ(ERR_IO_PENDING, rv);
    894 
    895   host_resolver.SetAction(
    896       base::Bind(CancelRequestAndPause, &resolver, request));
    897 
    898   host_resolver.WaitUntilRequestIsReceived();
    899 
    900   // At this point the host resolver ran Resolve(), and should have cancelled
    901   // the request.
    902 
    903   EXPECT_EQ(1, host_resolver.num_cancelled_requests());
    904 }
    905 
    906 // Cancel the request while there is a pending DNS request, however before
    907 // the request is sent to the host resolver.
    908 TEST_F(ProxyResolverV8TracingTest, CancelWhileBlockedInNonBlockingDns2) {
    909   MockCachingHostResolver host_resolver;
    910   MockErrorObserver* error_observer = new MockErrorObserver;
    911   ProxyResolverV8Tracing resolver(&host_resolver, error_observer, NULL);
    912 
    913   InitResolver(&resolver, "dns.js");
    914 
    915   ProxyInfo proxy_info;
    916   ProxyResolver::RequestHandle request;
    917 
    918   int rv = resolver.GetProxyForURL(
    919       GURL("http://foo/"), &proxy_info,
    920       base::Bind(&CrashCallback), &request, BoundNetLog());
    921 
    922   EXPECT_EQ(ERR_IO_PENDING, rv);
    923 
    924   // Wait a bit, so the DNS task has hopefully been posted. The test will
    925   // work whatever the delay is here, but it is most useful if the delay
    926   // is large enough to allow a task to be posted back.
    927   base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10));
    928   resolver.CancelRequest(request);
    929 
    930   EXPECT_EQ(0u, host_resolver.num_resolve());
    931 }
    932 
    933 TEST_F(ProxyResolverV8TracingTest, CancelSetPacWhileOutstandingBlockingDns) {
    934   BlockableHostResolver host_resolver;
    935   MockErrorObserver* error_observer = new MockErrorObserver;
    936 
    937   ProxyResolverV8Tracing resolver(&host_resolver, error_observer, NULL);
    938 
    939   int rv =
    940       resolver.SetPacScript(LoadScriptData("dns_during_init.js"),
    941       base::Bind(&CrashCallback));
    942   EXPECT_EQ(ERR_IO_PENDING, rv);
    943 
    944   host_resolver.WaitUntilRequestIsReceived();
    945 
    946   resolver.CancelSetPacScript();
    947   EXPECT_EQ(1, host_resolver.num_cancelled_requests());
    948 }
    949 
    950 // This tests that the execution of a PAC script is terminated when the DNS
    951 // dependencies are missing. If the test fails, then it will hang.
    952 TEST_F(ProxyResolverV8TracingTest, Terminate) {
    953   CapturingNetLog log;
    954   CapturingBoundNetLog request_log;
    955   MockCachingHostResolver host_resolver;
    956   MockErrorObserver* error_observer = new MockErrorObserver;
    957   ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
    958 
    959   host_resolver.rules()->AddRule("host1", "182.111.0.222");
    960   host_resolver.rules()->AddRule("host2", "111.33.44.55");
    961 
    962   InitResolver(&resolver, "terminate.js");
    963 
    964   TestCompletionCallback callback;
    965   ProxyInfo proxy_info;
    966 
    967   int rv = resolver.GetProxyForURL(
    968       GURL("http://foopy/req1"),
    969       &proxy_info,
    970       callback.callback(),
    971       NULL,
    972       request_log.bound());
    973 
    974   EXPECT_EQ(ERR_IO_PENDING, rv);
    975   EXPECT_EQ(OK, callback.WaitForResult());
    976 
    977   // The test does 2 DNS resolutions.
    978   EXPECT_EQ(2u, host_resolver.num_resolve());
    979 
    980   EXPECT_EQ("foopy:3", proxy_info.proxy_server().ToURI());
    981 
    982   // No errors.
    983   EXPECT_EQ("", error_observer->GetOutput());
    984 
    985   EXPECT_EQ(0u, log.GetSize());
    986   EXPECT_EQ(0u, request_log.GetSize());
    987 }
    988 
    989 // Tests that multiple instances of ProxyResolverV8Tracing can coexist and run
    990 // correctly at the same time. This is relevant because at the moment (time
    991 // this test was written) each ProxyResolverV8Tracing creates its own thread to
    992 // run V8 on, however each thread is operating on the same v8::Isolate.
    993 TEST_F(ProxyResolverV8TracingTest, MultipleResolvers) {
    994   // ------------------------
    995   // Setup resolver0
    996   // ------------------------
    997   MockHostResolver host_resolver0;
    998   host_resolver0.rules()->AddRuleForAddressFamily(
    999       "host1", ADDRESS_FAMILY_IPV4, "166.155.144.44");
   1000   host_resolver0.rules()
   1001       ->AddIPLiteralRule("host1", "::1,192.168.1.1", std::string());
   1002   host_resolver0.rules()->AddSimulatedFailure("host2");
   1003   host_resolver0.rules()->AddRule("host3", "166.155.144.33");
   1004   host_resolver0.rules()->AddRule("host5", "166.155.144.55");
   1005   host_resolver0.rules()->AddSimulatedFailure("host6");
   1006   host_resolver0.rules()->AddRuleForAddressFamily(
   1007       "*", ADDRESS_FAMILY_IPV4, "122.133.144.155");
   1008   host_resolver0.rules()->AddRule("*", "133.122.100.200");
   1009   ProxyResolverV8Tracing resolver0(
   1010       &host_resolver0, new MockErrorObserver, NULL);
   1011   InitResolver(&resolver0, "dns.js");
   1012 
   1013   // ------------------------
   1014   // Setup resolver1
   1015   // ------------------------
   1016   ProxyResolverV8Tracing resolver1(
   1017       &host_resolver0, new MockErrorObserver, NULL);
   1018   InitResolver(&resolver1, "dns.js");
   1019 
   1020   // ------------------------
   1021   // Setup resolver2
   1022   // ------------------------
   1023   ProxyResolverV8Tracing resolver2(
   1024       &host_resolver0, new MockErrorObserver, NULL);
   1025   InitResolver(&resolver2, "simple.js");
   1026 
   1027   // ------------------------
   1028   // Setup resolver3
   1029   // ------------------------
   1030   MockHostResolver host_resolver3;
   1031   host_resolver3.rules()->AddRule("foo", "166.155.144.33");
   1032   ProxyResolverV8Tracing resolver3(
   1033       &host_resolver3, new MockErrorObserver, NULL);
   1034   InitResolver(&resolver3, "simple_dns.js");
   1035 
   1036   // ------------------------
   1037   // Queue up work for each resolver (which will be running in parallel).
   1038   // ------------------------
   1039 
   1040   ProxyResolverV8Tracing* resolver[] = {
   1041     &resolver0, &resolver1, &resolver2, &resolver3,
   1042   };
   1043 
   1044   const size_t kNumResolvers = arraysize(resolver);
   1045   const size_t kNumIterations = 20;
   1046   const size_t kNumResults = kNumResolvers * kNumIterations;
   1047   TestCompletionCallback callback[kNumResults];
   1048   ProxyInfo proxy_info[kNumResults];
   1049 
   1050   for (size_t i = 0; i < kNumResults; ++i) {
   1051     size_t resolver_i = i % kNumResolvers;
   1052     int rv = resolver[resolver_i]->GetProxyForURL(
   1053         GURL("http://foo/"), &proxy_info[i], callback[i].callback(), NULL,
   1054         BoundNetLog());
   1055     EXPECT_EQ(ERR_IO_PENDING, rv);
   1056   }
   1057 
   1058   // ------------------------
   1059   // Verify all of the results.
   1060   // ------------------------
   1061 
   1062   const char* kExpectedForDnsJs =
   1063     "122.133.144.155-"  // myIpAddress()
   1064     "null-"  // dnsResolve('')
   1065     "__1_192.168.1.1-"  // dnsResolveEx('host1')
   1066     "null-"  // dnsResolve('host2')
   1067     "166.155.144.33-"  // dnsResolve('host3')
   1068     "122.133.144.155-"  // myIpAddress()
   1069     "166.155.144.33-"  // dnsResolve('host3')
   1070     "__1_192.168.1.1-"  // dnsResolveEx('host1')
   1071     "122.133.144.155-"  // myIpAddress()
   1072     "null-"  // dnsResolve('host2')
   1073     "-"  // dnsResolveEx('host6')
   1074     "133.122.100.200-"  // myIpAddressEx()
   1075     "166.155.144.44"  // dnsResolve('host1')
   1076     ":99";
   1077 
   1078   for (size_t i = 0; i < kNumResults; ++i) {
   1079     size_t resolver_i = i % kNumResolvers;
   1080     EXPECT_EQ(OK, callback[i].WaitForResult());
   1081 
   1082     std::string proxy_uri = proxy_info[i].proxy_server().ToURI();
   1083 
   1084     if (resolver_i == 0 || resolver_i == 1) {
   1085       EXPECT_EQ(kExpectedForDnsJs, proxy_uri);
   1086     } else if (resolver_i == 2) {
   1087       EXPECT_EQ("foo:99", proxy_uri);
   1088     } else if (resolver_i == 3) {
   1089       EXPECT_EQ("166.155.144.33:",
   1090                 proxy_uri.substr(0, proxy_uri.find(':') + 1));
   1091     } else {
   1092       NOTREACHED();
   1093     }
   1094   }
   1095 }
   1096 
   1097 }  // namespace
   1098 
   1099 }  // namespace net
   1100