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 13namespace net { 14 15namespace { 16 17// Test parsing from a PAC string. 18TEST(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 69TEST(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 95TEST(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 169TEST(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