proxy_list_unittest.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  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. #include "net/proxy_resolution/proxy_list.h"
  5. #include <vector>
  6. #include "net/base/net_errors.h"
  7. #include "net/base/proxy_server.h"
  8. #include "net/base/proxy_string_util.h"
  9. #include "net/log/net_log_with_source.h"
  10. #include "net/proxy_resolution/proxy_retry_info.h"
  11. #include "net/test/gtest_util.h"
  12. #include "testing/gmock/include/gmock/gmock.h"
  13. #include "testing/gtest/include/gtest/gtest.h"
  14. using net::test::IsOk;
  15. namespace net {
  16. namespace {
  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. // 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. for (const auto& test : tests) {
  60. ProxyList list;
  61. list.SetFromPacString(test.pac_input);
  62. EXPECT_EQ(test.pac_output, list.ToPacString());
  63. EXPECT_FALSE(list.IsEmpty());
  64. }
  65. }
  66. TEST(ProxyListTest, RemoveProxiesWithoutScheme) {
  67. const struct {
  68. const char* pac_input;
  69. int filter;
  70. const char* filtered_pac_output;
  71. } tests[] = {
  72. { "PROXY foopy:10 ; SOCKS5 foopy2 ; SOCKS foopy11 ; PROXY foopy3 ; DIRECT",
  73. // Remove anything that isn't HTTP or DIRECT.
  74. ProxyServer::SCHEME_DIRECT | ProxyServer::SCHEME_HTTP,
  75. "PROXY foopy:10;PROXY foopy3:80;DIRECT",
  76. },
  77. { "PROXY foopy:10 ; SOCKS5 foopy2",
  78. // Remove anything that isn't HTTP or SOCKS5.
  79. ProxyServer::SCHEME_DIRECT | ProxyServer::SCHEME_SOCKS4,
  80. "",
  81. },
  82. };
  83. for (const auto& test : tests) {
  84. ProxyList list;
  85. list.SetFromPacString(test.pac_input);
  86. list.RemoveProxiesWithoutScheme(test.filter);
  87. EXPECT_EQ(test.filtered_pac_output, list.ToPacString());
  88. }
  89. }
  90. TEST(ProxyListTest, DeprioritizeBadProxies) {
  91. // Retry info that marks a proxy as being bad for a *very* long time (to avoid
  92. // the test depending on the current time.)
  93. ProxyRetryInfo proxy_retry_info;
  94. proxy_retry_info.bad_until = base::TimeTicks::Now() + base::Days(1);
  95. // Call DeprioritizeBadProxies with an empty map -- should have no effect.
  96. {
  97. ProxyList list;
  98. list.SetFromPacString("PROXY foopy1:80;PROXY foopy2:80;PROXY foopy3:80");
  99. ProxyRetryInfoMap retry_info_map;
  100. list.DeprioritizeBadProxies(retry_info_map);
  101. EXPECT_EQ("PROXY foopy1:80;PROXY foopy2:80;PROXY foopy3:80",
  102. list.ToPacString());
  103. }
  104. // Call DeprioritizeBadProxies with 2 of the three proxies marked as bad.
  105. // These proxies should be retried last.
  106. {
  107. ProxyList list;
  108. list.SetFromPacString("PROXY foopy1:80;PROXY foopy2:80;PROXY foopy3:80");
  109. ProxyRetryInfoMap retry_info_map;
  110. retry_info_map["foopy1:80"] = proxy_retry_info;
  111. retry_info_map["foopy3:80"] = proxy_retry_info;
  112. retry_info_map["socks5://localhost:1080"] = proxy_retry_info;
  113. list.DeprioritizeBadProxies(retry_info_map);
  114. EXPECT_EQ("PROXY foopy2:80;PROXY foopy1:80;PROXY foopy3:80",
  115. list.ToPacString());
  116. }
  117. // Call DeprioritizeBadProxies where ALL of the proxies are marked as bad.
  118. // This should have no effect on the order.
  119. {
  120. ProxyList list;
  121. list.SetFromPacString("PROXY foopy1:80;PROXY foopy2:80;PROXY foopy3:80");
  122. ProxyRetryInfoMap retry_info_map;
  123. retry_info_map["foopy1:80"] = proxy_retry_info;
  124. retry_info_map["foopy2:80"] = proxy_retry_info;
  125. retry_info_map["foopy3:80"] = proxy_retry_info;
  126. list.DeprioritizeBadProxies(retry_info_map);
  127. EXPECT_EQ("PROXY foopy1:80;PROXY foopy2:80;PROXY foopy3:80",
  128. list.ToPacString());
  129. }
  130. // Call DeprioritizeBadProxies with 2 of the three proxies marked as bad. Of
  131. // the 2 bad proxies, one is to be reconsidered and should be retried last.
  132. // The other is not to be reconsidered and should be removed from the list.
  133. {
  134. ProxyList list;
  135. list.SetFromPacString("PROXY foopy1:80;PROXY foopy2:80;PROXY foopy3:80");
  136. ProxyRetryInfoMap retry_info_map;
  137. // |proxy_retry_info.reconsider defaults to true.
  138. retry_info_map["foopy1:80"] = proxy_retry_info;
  139. proxy_retry_info.try_while_bad = false;
  140. retry_info_map["foopy3:80"] = proxy_retry_info;
  141. proxy_retry_info.try_while_bad = true;
  142. retry_info_map["socks5://localhost:1080"] = proxy_retry_info;
  143. list.DeprioritizeBadProxies(retry_info_map);
  144. EXPECT_EQ("PROXY foopy2:80;PROXY foopy1:80",
  145. list.ToPacString());
  146. }
  147. }
  148. TEST(ProxyListTest, UpdateRetryInfoOnFallback) {
  149. // Retrying should put the first proxy on the retry list.
  150. {
  151. ProxyList list;
  152. ProxyRetryInfoMap retry_info_map;
  153. NetLogWithSource net_log;
  154. ProxyServer proxy_server(
  155. ProxyUriToProxyServer("foopy1:80", ProxyServer::SCHEME_HTTP));
  156. std::vector<ProxyServer> bad_proxies;
  157. bad_proxies.push_back(proxy_server);
  158. list.SetFromPacString("PROXY foopy1:80;PROXY foopy2:80;PROXY foopy3:80");
  159. list.UpdateRetryInfoOnFallback(&retry_info_map, base::Seconds(60), true,
  160. bad_proxies, ERR_PROXY_CONNECTION_FAILED,
  161. net_log);
  162. EXPECT_TRUE(retry_info_map.end() != retry_info_map.find("foopy1:80"));
  163. EXPECT_EQ(ERR_PROXY_CONNECTION_FAILED,
  164. retry_info_map[ProxyServerToProxyUri(proxy_server)].net_error);
  165. EXPECT_TRUE(retry_info_map.end() == retry_info_map.find("foopy2:80"));
  166. EXPECT_TRUE(retry_info_map.end() == retry_info_map.find("foopy3:80"));
  167. }
  168. // Retrying should put the first proxy on the retry list, even if there
  169. // was no network error.
  170. {
  171. ProxyList list;
  172. ProxyRetryInfoMap retry_info_map;
  173. NetLogWithSource net_log;
  174. ProxyServer proxy_server(
  175. ProxyUriToProxyServer("foopy1:80", ProxyServer::SCHEME_HTTP));
  176. std::vector<ProxyServer> bad_proxies;
  177. bad_proxies.push_back(proxy_server);
  178. list.SetFromPacString("PROXY foopy1:80;PROXY foopy2:80;PROXY foopy3:80");
  179. list.UpdateRetryInfoOnFallback(&retry_info_map, base::Seconds(60), true,
  180. bad_proxies, OK, net_log);
  181. EXPECT_TRUE(retry_info_map.end() != retry_info_map.find("foopy1:80"));
  182. EXPECT_THAT(retry_info_map[ProxyServerToProxyUri(proxy_server)].net_error,
  183. IsOk());
  184. EXPECT_TRUE(retry_info_map.end() == retry_info_map.find("foopy2:80"));
  185. EXPECT_TRUE(retry_info_map.end() == retry_info_map.find("foopy3:80"));
  186. }
  187. // Including another bad proxy should put both the first and the specified
  188. // proxy on the retry list.
  189. {
  190. ProxyList list;
  191. ProxyRetryInfoMap retry_info_map;
  192. NetLogWithSource net_log;
  193. ProxyServer proxy_server =
  194. ProxyUriToProxyServer("foopy3:80", ProxyServer::SCHEME_HTTP);
  195. std::vector<ProxyServer> bad_proxies;
  196. bad_proxies.push_back(proxy_server);
  197. list.SetFromPacString("PROXY foopy1:80;PROXY foopy2:80;PROXY foopy3:80");
  198. list.UpdateRetryInfoOnFallback(&retry_info_map, base::Seconds(60), true,
  199. bad_proxies, ERR_NAME_RESOLUTION_FAILED,
  200. net_log);
  201. EXPECT_TRUE(retry_info_map.end() != retry_info_map.find("foopy1:80"));
  202. EXPECT_EQ(ERR_NAME_RESOLUTION_FAILED,
  203. retry_info_map[ProxyServerToProxyUri(proxy_server)].net_error);
  204. EXPECT_TRUE(retry_info_map.end() == retry_info_map.find("foopy2:80"));
  205. EXPECT_TRUE(retry_info_map.end() != retry_info_map.find("foopy3:80"));
  206. }
  207. // If the first proxy is DIRECT, nothing is added to the retry list, even
  208. // if another bad proxy is specified.
  209. {
  210. ProxyList list;
  211. ProxyRetryInfoMap retry_info_map;
  212. NetLogWithSource net_log;
  213. ProxyServer proxy_server =
  214. ProxyUriToProxyServer("foopy2:80", ProxyServer::SCHEME_HTTP);
  215. std::vector<ProxyServer> bad_proxies;
  216. bad_proxies.push_back(proxy_server);
  217. list.SetFromPacString("DIRECT;PROXY foopy2:80;PROXY foopy3:80");
  218. list.UpdateRetryInfoOnFallback(&retry_info_map, base::Seconds(60), true,
  219. bad_proxies, OK, net_log);
  220. EXPECT_TRUE(retry_info_map.end() == retry_info_map.find("foopy2:80"));
  221. EXPECT_TRUE(retry_info_map.end() == retry_info_map.find("foopy3:80"));
  222. }
  223. // If the bad proxy is already on the retry list, and the old retry info would
  224. // cause the proxy to be retried later than the newly specified retry info,
  225. // then the old retry info should be kept.
  226. {
  227. ProxyList list;
  228. ProxyRetryInfoMap retry_info_map;
  229. NetLogWithSource net_log;
  230. list.SetFromPacString("PROXY foopy1:80;PROXY foopy2:80;PROXY foopy3:80");
  231. // First, mark the proxy as bad for 60 seconds.
  232. list.UpdateRetryInfoOnFallback(&retry_info_map, base::Seconds(60), true,
  233. std::vector<ProxyServer>(),
  234. ERR_PROXY_CONNECTION_FAILED, net_log);
  235. // Next, mark the same proxy as bad for 1 second. This call should have no
  236. // effect, since this would cause the bad proxy to be retried sooner than
  237. // the existing retry info.
  238. list.UpdateRetryInfoOnFallback(&retry_info_map, base::Seconds(1), false,
  239. std::vector<ProxyServer>(), OK, net_log);
  240. EXPECT_TRUE(retry_info_map.end() != retry_info_map.find("foopy1:80"));
  241. EXPECT_EQ(ERR_PROXY_CONNECTION_FAILED,
  242. retry_info_map["foopy1:80"].net_error);
  243. EXPECT_TRUE(retry_info_map["foopy1:80"].try_while_bad);
  244. EXPECT_EQ(base::Seconds(60), retry_info_map["foopy1:80"].current_delay);
  245. EXPECT_GT(retry_info_map["foopy1:80"].bad_until,
  246. base::TimeTicks::Now() + base::Seconds(30));
  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. // If the bad proxy is already on the retry list, and the newly specified
  251. // retry info would cause the proxy to be retried later than the old retry
  252. // info, then the old retry info should be replaced with the new retry info.
  253. {
  254. ProxyList list;
  255. ProxyRetryInfoMap retry_info_map;
  256. NetLogWithSource net_log;
  257. list.SetFromPacString("PROXY foopy1:80;PROXY foopy2:80;PROXY foopy3:80");
  258. // First, mark the proxy as bad for 1 second.
  259. list.UpdateRetryInfoOnFallback(&retry_info_map, base::Seconds(1), false,
  260. std::vector<ProxyServer>(), OK, net_log);
  261. // Next, mark the same proxy as bad for 60 seconds. This call should replace
  262. // the existing retry info with the new 60 second retry info.
  263. list.UpdateRetryInfoOnFallback(&retry_info_map, base::Seconds(60), true,
  264. std::vector<ProxyServer>(),
  265. ERR_PROXY_CONNECTION_FAILED, net_log);
  266. EXPECT_TRUE(retry_info_map.end() != retry_info_map.find("foopy1:80"));
  267. EXPECT_EQ(ERR_PROXY_CONNECTION_FAILED,
  268. retry_info_map["foopy1:80"].net_error);
  269. EXPECT_TRUE(retry_info_map["foopy1:80"].try_while_bad);
  270. EXPECT_EQ(base::Seconds(60), retry_info_map["foopy1:80"].current_delay);
  271. EXPECT_GT(retry_info_map["foopy1:80"].bad_until,
  272. base::TimeTicks::Now() + base::Seconds(30));
  273. EXPECT_TRUE(retry_info_map.end() == retry_info_map.find("foopy2:80"));
  274. EXPECT_TRUE(retry_info_map.end() == retry_info_map.find("foopy3:80"));
  275. }
  276. }
  277. } // anonymous namespace
  278. } // namespace net