Home | History | Annotate | Download | only in proxy
      1 // Copyright (c) 2006-2008 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_list.h"
      6 
      7 #include "net/base/net_errors.h"
      8 #include "net/base/net_log.h"
      9 #include "net/proxy/proxy_retry_info.h"
     10 #include "net/proxy/proxy_server.h"
     11 #include "testing/gtest/include/gtest/gtest.h"
     12 
     13 namespace net {
     14 
     15 namespace {
     16 
     17 // Test parsing from a PAC string.
     18 TEST(ProxyListTest, SetFromPacString) {
     19   const struct {
     20     const char* pac_input;
     21     const char* pac_output;
     22   } tests[] = {
     23     // Valid inputs:
     24     {  "PROXY foopy:10",
     25        "PROXY foopy:10",
     26     },
     27     {  " DIRECT",  // leading space.
     28        "DIRECT",
     29     },
     30     {  "PROXY foopy1 ; proxy foopy2;\t DIRECT",
     31        "PROXY foopy1:80;PROXY foopy2:80;DIRECT",
     32     },
     33     {  "proxy foopy1 ; SOCKS foopy2",
     34        "PROXY foopy1:80;SOCKS foopy2:1080",
     35     },
     36     // Try putting DIRECT first.
     37     {  "DIRECT ; proxy foopy1 ; DIRECT ; SOCKS5 foopy2;DIRECT ",
     38        "DIRECT;PROXY foopy1:80;DIRECT;SOCKS5 foopy2:1080;DIRECT",
     39     },
     40     // Try putting DIRECT consecutively.
     41     {  "DIRECT ; proxy foopy1:80; DIRECT ; DIRECT",
     42        "DIRECT;PROXY foopy1:80;DIRECT;DIRECT",
     43     },
     44 
     45     // Invalid inputs (parts which aren't understood get
     46     // silently discarded):
     47     //
     48     // If the proxy list string parsed to empty, automatically fall-back to
     49     // DIRECT.
     50     {  "PROXY-foopy:10",
     51        "DIRECT",
     52     },
     53     {  "PROXY",
     54        "DIRECT",
     55     },
     56     {  "PROXY foopy1 ; JUNK ; JUNK ; SOCKS5 foopy2 ; ;",
     57        "PROXY foopy1:80;SOCKS5 foopy2:1080",
     58     },
     59   };
     60 
     61   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
     62     ProxyList list;
     63     list.SetFromPacString(tests[i].pac_input);
     64     EXPECT_EQ(tests[i].pac_output, list.ToPacString());
     65     EXPECT_FALSE(list.IsEmpty());
     66   }
     67 }
     68 
     69 TEST(ProxyListTest, RemoveProxiesWithoutScheme) {
     70   const struct {
     71     const char* pac_input;
     72     int filter;
     73     const char* filtered_pac_output;
     74   } tests[] = {
     75     {  "PROXY foopy:10 ; SOCKS5 foopy2 ; SOCKS foopy11 ; PROXY foopy3 ; DIRECT",
     76        // Remove anything that isn't HTTP or DIRECT.
     77        ProxyServer::SCHEME_DIRECT | ProxyServer::SCHEME_HTTP,
     78        "PROXY foopy:10;PROXY foopy3:80;DIRECT",
     79     },
     80     {  "PROXY foopy:10 ; SOCKS5 foopy2",
     81        // Remove anything that isn't HTTP or SOCKS5.
     82        ProxyServer::SCHEME_DIRECT | ProxyServer::SCHEME_SOCKS4,
     83        "",
     84     },
     85   };
     86 
     87   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
     88     ProxyList list;
     89     list.SetFromPacString(tests[i].pac_input);
     90     list.RemoveProxiesWithoutScheme(tests[i].filter);
     91     EXPECT_EQ(tests[i].filtered_pac_output, list.ToPacString());
     92   }
     93 }
     94 
     95 TEST(ProxyListTest, DeprioritizeBadProxies) {
     96   // Retry info that marks a proxy as being bad for a *very* long time (to avoid
     97   // the test depending on the current time.)
     98   ProxyRetryInfo proxy_retry_info;
     99   proxy_retry_info.bad_until =
    100       base::TimeTicks::Now() + base::TimeDelta::FromDays(1);
    101 
    102   // Call DeprioritizeBadProxies with an empty map -- should have no effect.
    103   {
    104     ProxyList list;
    105     list.SetFromPacString("PROXY foopy1:80;PROXY foopy2:80;PROXY foopy3:80");
    106 
    107     ProxyRetryInfoMap retry_info_map;
    108     list.DeprioritizeBadProxies(retry_info_map);
    109     EXPECT_EQ("PROXY foopy1:80;PROXY foopy2:80;PROXY foopy3:80",
    110               list.ToPacString());
    111   }
    112 
    113   // Call DeprioritizeBadProxies with 2 of the three proxies marked as bad.
    114   // These proxies should be retried last.
    115   {
    116     ProxyList list;
    117     list.SetFromPacString("PROXY foopy1:80;PROXY foopy2:80;PROXY foopy3:80");
    118 
    119     ProxyRetryInfoMap retry_info_map;
    120     retry_info_map["foopy1:80"] = proxy_retry_info;
    121     retry_info_map["foopy3:80"] = proxy_retry_info;
    122     retry_info_map["socks5://localhost:1080"] = proxy_retry_info;
    123 
    124     list.DeprioritizeBadProxies(retry_info_map);
    125 
    126     EXPECT_EQ("PROXY foopy2:80;PROXY foopy1:80;PROXY foopy3:80",
    127               list.ToPacString());
    128   }
    129 
    130   // Call DeprioritizeBadProxies where ALL of the proxies are marked as bad.
    131   // This should have no effect on the order.
    132   {
    133     ProxyList list;
    134     list.SetFromPacString("PROXY foopy1:80;PROXY foopy2:80;PROXY foopy3:80");
    135 
    136     ProxyRetryInfoMap retry_info_map;
    137     retry_info_map["foopy1:80"] = proxy_retry_info;
    138     retry_info_map["foopy2:80"] = proxy_retry_info;
    139     retry_info_map["foopy3:80"] = proxy_retry_info;
    140 
    141     list.DeprioritizeBadProxies(retry_info_map);
    142 
    143     EXPECT_EQ("PROXY foopy1:80;PROXY foopy2:80;PROXY foopy3:80",
    144               list.ToPacString());
    145   }
    146 
    147   // Call DeprioritizeBadProxies with 2 of the three proxies marked as bad. Of
    148   // the 2 bad proxies, one is to be reconsidered and should be retried last.
    149   // The other is not to be reconsidered and should be removed from the list.
    150   {
    151     ProxyList list;
    152     list.SetFromPacString("PROXY foopy1:80;PROXY foopy2:80;PROXY foopy3:80");
    153 
    154     ProxyRetryInfoMap retry_info_map;
    155     // |proxy_retry_info.reconsider defaults to true.
    156     retry_info_map["foopy1:80"] = proxy_retry_info;
    157     proxy_retry_info.try_while_bad = false;
    158     retry_info_map["foopy3:80"] = proxy_retry_info;
    159     proxy_retry_info.try_while_bad = true;
    160     retry_info_map["socks5://localhost:1080"] = proxy_retry_info;
    161 
    162     list.DeprioritizeBadProxies(retry_info_map);
    163 
    164     EXPECT_EQ("PROXY foopy2:80;PROXY foopy1:80",
    165               list.ToPacString());
    166   }
    167 }
    168 
    169 TEST(ProxyListTest, UpdateRetryInfoOnFallback) {
    170   ProxyRetryInfo proxy_retry_info;
    171   // Retrying should put the first proxy on the retry list.
    172   {
    173     ProxyList list;
    174     ProxyRetryInfoMap retry_info_map;
    175     BoundNetLog net_log;
    176     ProxyServer proxy_server(
    177         ProxyServer::FromURI("foopy1:80", ProxyServer::SCHEME_HTTP));
    178     list.SetFromPacString("PROXY foopy1:80;PROXY foopy2:80;PROXY foopy3:80");
    179     list.UpdateRetryInfoOnFallback(&retry_info_map,
    180                                    base::TimeDelta::FromSeconds(60),
    181                                    true,
    182                                    proxy_server,
    183                                    ERR_PROXY_CONNECTION_FAILED,
    184                                    net_log);
    185     EXPECT_TRUE(retry_info_map.end() != retry_info_map.find("foopy1:80"));
    186     EXPECT_EQ(ERR_PROXY_CONNECTION_FAILED,
    187               retry_info_map[proxy_server.ToURI()].net_error);
    188     EXPECT_TRUE(retry_info_map.end() == retry_info_map.find("foopy2:80"));
    189     EXPECT_TRUE(retry_info_map.end() == retry_info_map.find("foopy3:80"));
    190   }
    191   // Retrying should put the first proxy on the retry list, even if there
    192   // was no network error.
    193   {
    194     ProxyList list;
    195     ProxyRetryInfoMap retry_info_map;
    196     BoundNetLog net_log;
    197     ProxyServer proxy_server(
    198         ProxyServer::FromURI("foopy1:80", ProxyServer::SCHEME_HTTP));
    199     list.SetFromPacString("PROXY foopy1:80;PROXY foopy2:80;PROXY foopy3:80");
    200     list.UpdateRetryInfoOnFallback(&retry_info_map,
    201                                    base::TimeDelta::FromSeconds(60),
    202                                    true,
    203                                    proxy_server,
    204                                    OK,
    205                                    net_log);
    206     EXPECT_TRUE(retry_info_map.end() != retry_info_map.find("foopy1:80"));
    207     EXPECT_EQ(OK, retry_info_map[proxy_server.ToURI()].net_error);
    208     EXPECT_TRUE(retry_info_map.end() == retry_info_map.find("foopy2:80"));
    209     EXPECT_TRUE(retry_info_map.end() == retry_info_map.find("foopy3:80"));
    210   }
    211   // Including another bad proxy should put both the first and the specified
    212   // proxy on the retry list.
    213   {
    214     ProxyList list;
    215     ProxyRetryInfoMap retry_info_map;
    216     BoundNetLog net_log;
    217     ProxyServer proxy_server = ProxyServer::FromURI("foopy3:80",
    218                                                     ProxyServer::SCHEME_HTTP);
    219     list.SetFromPacString("PROXY foopy1:80;PROXY foopy2:80;PROXY foopy3:80");
    220     list.UpdateRetryInfoOnFallback(&retry_info_map,
    221                                    base::TimeDelta::FromSeconds(60),
    222                                    true,
    223                                    proxy_server,
    224                                    ERR_NAME_RESOLUTION_FAILED,
    225                                    net_log);
    226     EXPECT_TRUE(retry_info_map.end() != retry_info_map.find("foopy1:80"));
    227     EXPECT_EQ(ERR_NAME_RESOLUTION_FAILED,
    228               retry_info_map[proxy_server.ToURI()].net_error);
    229     EXPECT_TRUE(retry_info_map.end() == retry_info_map.find("foopy2:80"));
    230     EXPECT_TRUE(retry_info_map.end() != retry_info_map.find("foopy3:80"));
    231   }
    232   // If the first proxy is DIRECT, nothing is added to the retry list, even
    233   // if another bad proxy is specified.
    234   {
    235     ProxyList list;
    236     ProxyRetryInfoMap retry_info_map;
    237     BoundNetLog net_log;
    238     ProxyServer proxy_server = ProxyServer::FromURI("foopy2:80",
    239                                                     ProxyServer::SCHEME_HTTP);
    240     list.SetFromPacString("DIRECT;PROXY foopy2:80;PROXY foopy3:80");
    241     list.UpdateRetryInfoOnFallback(&retry_info_map,
    242                                    base::TimeDelta::FromSeconds(60),
    243                                    true,
    244                                    proxy_server,
    245                                    OK,
    246                                    net_log);
    247     EXPECT_TRUE(retry_info_map.end() == retry_info_map.find("foopy2:80"));
    248     EXPECT_TRUE(retry_info_map.end() == retry_info_map.find("foopy3:80"));
    249   }
    250 }
    251 
    252 }  // namesapce
    253 
    254 }  // namespace net
    255