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