1// Copyright (c) 2009 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 <vector> 6 7#include "net/base/net_errors.h" 8#include "net/base/load_log.h" 9#include "net/base/load_log_util.h" 10#include "net/base/load_log_unittest.h" 11#include "net/base/test_completion_callback.h" 12#include "net/proxy/init_proxy_resolver.h" 13#include "net/proxy/proxy_config.h" 14#include "net/proxy/proxy_resolver.h" 15#include "net/proxy/proxy_script_fetcher.h" 16#include "testing/gtest/include/gtest/gtest.h" 17 18namespace net { 19namespace { 20 21enum Error { 22 kFailedDownloading = -100, 23 kFailedParsing = -200, 24}; 25 26class Rules { 27 public: 28 struct Rule { 29 Rule(const GURL& url, 30 int fetch_error, 31 int set_pac_error) 32 : url(url), 33 fetch_error(fetch_error), 34 set_pac_error(set_pac_error) { 35 } 36 37 std::string bytes() const { 38 if (set_pac_error == OK) 39 return url.spec() + "!valid-script"; 40 if (fetch_error == OK) 41 return url.spec() + "!invalid-script"; 42 return std::string(); 43 } 44 45 GURL url; 46 int fetch_error; 47 int set_pac_error; 48 }; 49 50 Rule AddSuccessRule(const char* url) { 51 Rule rule(GURL(url), OK /*fetch_error*/, OK /*set_pac_error*/); 52 rules_.push_back(rule); 53 return rule; 54 } 55 56 void AddFailDownloadRule(const char* url) { 57 rules_.push_back(Rule(GURL(url), kFailedDownloading /*fetch_error*/, 58 ERR_UNEXPECTED /*set_pac_error*/)); 59 } 60 61 void AddFailParsingRule(const char* url) { 62 rules_.push_back(Rule(GURL(url), OK /*fetch_error*/, 63 kFailedParsing /*set_pac_error*/)); 64 } 65 66 const Rule& GetRuleByUrl(const GURL& url) const { 67 for (RuleList::const_iterator it = rules_.begin(); it != rules_.end(); 68 ++it) { 69 if (it->url == url) 70 return *it; 71 } 72 CHECK(false) << "Rule not found for " << url; 73 return rules_[0]; 74 } 75 76 const Rule& GetRuleByBytes(const std::string& bytes) const { 77 for (RuleList::const_iterator it = rules_.begin(); it != rules_.end(); 78 ++it) { 79 if (it->bytes() == bytes) 80 return *it; 81 } 82 CHECK(false) << "Rule not found for " << bytes; 83 return rules_[0]; 84 } 85 86 private: 87 typedef std::vector<Rule> RuleList; 88 RuleList rules_; 89}; 90 91class RuleBasedProxyScriptFetcher : public ProxyScriptFetcher { 92 public: 93 explicit RuleBasedProxyScriptFetcher(const Rules* rules) : rules_(rules) {} 94 95 // ProxyScriptFetcher implementation. 96 virtual int Fetch(const GURL& url, 97 std::string* bytes, 98 CompletionCallback* callback) { 99 const Rules::Rule& rule = rules_->GetRuleByUrl(url); 100 int rv = rule.fetch_error; 101 EXPECT_NE(ERR_UNEXPECTED, rv); 102 if (rv == OK) 103 *bytes = rule.bytes(); 104 return rv; 105 } 106 107 virtual void Cancel() {} 108 109 private: 110 const Rules* rules_; 111}; 112 113class RuleBasedProxyResolver : public ProxyResolver { 114 public: 115 RuleBasedProxyResolver(const Rules* rules, bool expects_pac_bytes) 116 : ProxyResolver(expects_pac_bytes), rules_(rules) {} 117 118 // ProxyResolver implementation: 119 virtual int GetProxyForURL(const GURL& /*url*/, 120 ProxyInfo* /*results*/, 121 CompletionCallback* /*callback*/, 122 RequestHandle* /*request_handle*/, 123 LoadLog* /*load_log*/) { 124 NOTREACHED(); 125 return ERR_UNEXPECTED; 126 } 127 128 virtual void CancelRequest(RequestHandle request_handle) { 129 NOTREACHED(); 130 } 131 132 virtual int SetPacScript(const GURL& pac_url, 133 const std::string& pac_bytes, 134 CompletionCallback* callback) { 135 const Rules::Rule& rule = expects_pac_bytes() ? 136 rules_->GetRuleByBytes(pac_bytes) : 137 rules_->GetRuleByUrl(pac_url); 138 139 int rv = rule.set_pac_error; 140 EXPECT_NE(ERR_UNEXPECTED, rv); 141 142 if (expects_pac_bytes()) 143 EXPECT_EQ(rule.bytes(), pac_bytes); 144 else 145 EXPECT_EQ(rule.url, pac_url); 146 147 if (rv == OK) { 148 pac_bytes_ = pac_bytes; 149 pac_url_ = pac_url; 150 } 151 return rv; 152 } 153 154 const std::string& pac_bytes() const { return pac_bytes_; } 155 const GURL& pac_url() const { return pac_url_; } 156 157 private: 158 const Rules* rules_; 159 std::string pac_bytes_; 160 GURL pac_url_; 161}; 162 163// Succeed using custom PAC script. 164TEST(InitProxyResolverTest, CustomPacSucceeds) { 165 Rules rules; 166 RuleBasedProxyResolver resolver(&rules, true /*expects_pac_bytes*/); 167 RuleBasedProxyScriptFetcher fetcher(&rules); 168 169 ProxyConfig config; 170 config.pac_url = GURL("http://custom/proxy.pac"); 171 172 Rules::Rule rule = rules.AddSuccessRule("http://custom/proxy.pac"); 173 174 TestCompletionCallback callback; 175 scoped_refptr<LoadLog> log(new LoadLog(LoadLog::kUnbounded)); 176 InitProxyResolver init(&resolver, &fetcher); 177 EXPECT_EQ(OK, init.Init(config, &callback, log)); 178 EXPECT_EQ(rule.bytes(), resolver.pac_bytes()); 179 180 // Check the LoadLog was filled correctly. 181 EXPECT_EQ(9u, log->entries().size()); 182 EXPECT_TRUE(LogContainsBeginEvent( 183 *log, 0, LoadLog::TYPE_INIT_PROXY_RESOLVER)); 184 EXPECT_TRUE(LogContainsBeginEvent( 185 *log, 1, LoadLog::TYPE_INIT_PROXY_RESOLVER_FETCH_PAC_SCRIPT)); 186 EXPECT_TRUE(LogContainsEndEvent( 187 *log, 4, LoadLog::TYPE_INIT_PROXY_RESOLVER_FETCH_PAC_SCRIPT)); 188 EXPECT_TRUE(LogContainsBeginEvent( 189 *log, 5, LoadLog::TYPE_INIT_PROXY_RESOLVER_SET_PAC_SCRIPT)); 190 EXPECT_TRUE(LogContainsEndEvent( 191 *log, 7, LoadLog::TYPE_INIT_PROXY_RESOLVER_SET_PAC_SCRIPT)); 192 EXPECT_TRUE(LogContainsEndEvent(*log, 8, LoadLog::TYPE_INIT_PROXY_RESOLVER)); 193} 194 195// Fail downloading the custom PAC script. 196TEST(InitProxyResolverTest, CustomPacFails1) { 197 Rules rules; 198 RuleBasedProxyResolver resolver(&rules, true /*expects_pac_bytes*/); 199 RuleBasedProxyScriptFetcher fetcher(&rules); 200 201 ProxyConfig config; 202 config.pac_url = GURL("http://custom/proxy.pac"); 203 204 rules.AddFailDownloadRule("http://custom/proxy.pac"); 205 206 TestCompletionCallback callback; 207 scoped_refptr<LoadLog> log(new LoadLog(LoadLog::kUnbounded)); 208 InitProxyResolver init(&resolver, &fetcher); 209 EXPECT_EQ(kFailedDownloading, init.Init(config, &callback, log)); 210 EXPECT_EQ("", resolver.pac_bytes()); 211 212 // Check the LoadLog was filled correctly. 213 EXPECT_EQ(6u, log->entries().size()); 214 EXPECT_TRUE(LogContainsBeginEvent( 215 *log, 0, LoadLog::TYPE_INIT_PROXY_RESOLVER)); 216 EXPECT_TRUE(LogContainsBeginEvent( 217 *log, 1, LoadLog::TYPE_INIT_PROXY_RESOLVER_FETCH_PAC_SCRIPT)); 218 EXPECT_TRUE(LogContainsEndEvent( 219 *log, 4, LoadLog::TYPE_INIT_PROXY_RESOLVER_FETCH_PAC_SCRIPT)); 220 EXPECT_TRUE(LogContainsEndEvent(*log, 5, LoadLog::TYPE_INIT_PROXY_RESOLVER)); 221} 222 223// Fail parsing the custom PAC script. 224TEST(InitProxyResolverTest, CustomPacFails2) { 225 Rules rules; 226 RuleBasedProxyResolver resolver(&rules, true /*expects_pac_bytes*/); 227 RuleBasedProxyScriptFetcher fetcher(&rules); 228 229 ProxyConfig config; 230 config.pac_url = GURL("http://custom/proxy.pac"); 231 232 rules.AddFailParsingRule("http://custom/proxy.pac"); 233 234 TestCompletionCallback callback; 235 InitProxyResolver init(&resolver, &fetcher); 236 EXPECT_EQ(kFailedParsing, init.Init(config, &callback, NULL)); 237 EXPECT_EQ("", resolver.pac_bytes()); 238} 239 240// Fail downloading the custom PAC script, because the fetcher was NULL. 241TEST(InitProxyResolverTest, HasNullProxyScriptFetcher) { 242 Rules rules; 243 RuleBasedProxyResolver resolver(&rules, true /*expects_pac_bytes*/); 244 245 ProxyConfig config; 246 config.pac_url = GURL("http://custom/proxy.pac"); 247 248 TestCompletionCallback callback; 249 InitProxyResolver init(&resolver, NULL); 250 EXPECT_EQ(ERR_UNEXPECTED, init.Init(config, &callback, NULL)); 251 EXPECT_EQ("", resolver.pac_bytes()); 252} 253 254// Succeeds in choosing autodetect (wpad). 255TEST(InitProxyResolverTest, AutodetectSuccess) { 256 Rules rules; 257 RuleBasedProxyResolver resolver(&rules, true /*expects_pac_bytes*/); 258 RuleBasedProxyScriptFetcher fetcher(&rules); 259 260 ProxyConfig config; 261 config.auto_detect = true; 262 263 Rules::Rule rule = rules.AddSuccessRule("http://wpad/wpad.dat"); 264 265 TestCompletionCallback callback; 266 InitProxyResolver init(&resolver, &fetcher); 267 EXPECT_EQ(OK, init.Init(config, &callback, NULL)); 268 EXPECT_EQ(rule.bytes(), resolver.pac_bytes()); 269} 270 271// Fails at WPAD (downloading), but succeeds in choosing the custom PAC. 272TEST(InitProxyResolverTest, AutodetectFailCustomSuccess1) { 273 Rules rules; 274 RuleBasedProxyResolver resolver(&rules, true /*expects_pac_bytes*/); 275 RuleBasedProxyScriptFetcher fetcher(&rules); 276 277 ProxyConfig config; 278 config.auto_detect = true; 279 config.pac_url = GURL("http://custom/proxy.pac"); 280 281 rules.AddFailDownloadRule("http://wpad/wpad.dat"); 282 Rules::Rule rule = rules.AddSuccessRule("http://custom/proxy.pac"); 283 284 TestCompletionCallback callback; 285 InitProxyResolver init(&resolver, &fetcher); 286 EXPECT_EQ(OK, init.Init(config, &callback, NULL)); 287 EXPECT_EQ(rule.bytes(), resolver.pac_bytes()); 288} 289 290// Fails at WPAD (parsing), but succeeds in choosing the custom PAC. 291TEST(InitProxyResolverTest, AutodetectFailCustomSuccess2) { 292 Rules rules; 293 RuleBasedProxyResolver resolver(&rules, true /*expects_pac_bytes*/); 294 RuleBasedProxyScriptFetcher fetcher(&rules); 295 296 ProxyConfig config; 297 config.auto_detect = true; 298 config.pac_url = GURL("http://custom/proxy.pac"); 299 300 rules.AddFailParsingRule("http://wpad/wpad.dat"); 301 Rules::Rule rule = rules.AddSuccessRule("http://custom/proxy.pac"); 302 303 TestCompletionCallback callback; 304 scoped_refptr<LoadLog> log(new LoadLog(LoadLog::kUnbounded)); 305 InitProxyResolver init(&resolver, &fetcher); 306 EXPECT_EQ(OK, init.Init(config, &callback, log)); 307 EXPECT_EQ(rule.bytes(), resolver.pac_bytes()); 308 309 // Check the LoadLog was filled correctly. 310 // (Note that the Fetch and Set states are repeated since both WPAD and custom 311 // PAC scripts are tried). 312 EXPECT_EQ(17u, log->entries().size()); 313 EXPECT_TRUE(LogContainsBeginEvent( 314 *log, 0, LoadLog::TYPE_INIT_PROXY_RESOLVER)); 315 EXPECT_TRUE(LogContainsBeginEvent( 316 *log, 1, LoadLog::TYPE_INIT_PROXY_RESOLVER_FETCH_PAC_SCRIPT)); 317 EXPECT_TRUE(LogContainsEndEvent( 318 *log, 4, LoadLog::TYPE_INIT_PROXY_RESOLVER_FETCH_PAC_SCRIPT)); 319 EXPECT_TRUE(LogContainsBeginEvent( 320 *log, 5, LoadLog::TYPE_INIT_PROXY_RESOLVER_SET_PAC_SCRIPT)); 321 EXPECT_TRUE(LogContainsEndEvent( 322 *log, 7, LoadLog::TYPE_INIT_PROXY_RESOLVER_SET_PAC_SCRIPT)); 323 EXPECT_TRUE(LogContainsBeginEvent( 324 *log, 9, LoadLog::TYPE_INIT_PROXY_RESOLVER_FETCH_PAC_SCRIPT)); 325 EXPECT_TRUE(LogContainsEndEvent( 326 *log, 12, LoadLog::TYPE_INIT_PROXY_RESOLVER_FETCH_PAC_SCRIPT)); 327 EXPECT_TRUE(LogContainsBeginEvent( 328 *log, 13, LoadLog::TYPE_INIT_PROXY_RESOLVER_SET_PAC_SCRIPT)); 329 EXPECT_TRUE(LogContainsEndEvent( 330 *log, 15, LoadLog::TYPE_INIT_PROXY_RESOLVER_SET_PAC_SCRIPT)); 331 EXPECT_TRUE(LogContainsEndEvent(*log, 16, LoadLog::TYPE_INIT_PROXY_RESOLVER)); 332} 333 334// Fails at WPAD (downloading), and fails at custom PAC (downloading). 335TEST(InitProxyResolverTest, AutodetectFailCustomFails1) { 336 Rules rules; 337 RuleBasedProxyResolver resolver(&rules, true /*expects_pac_bytes*/); 338 RuleBasedProxyScriptFetcher fetcher(&rules); 339 340 ProxyConfig config; 341 config.auto_detect = true; 342 config.pac_url = GURL("http://custom/proxy.pac"); 343 344 rules.AddFailDownloadRule("http://wpad/wpad.dat"); 345 rules.AddFailDownloadRule("http://custom/proxy.pac"); 346 347 TestCompletionCallback callback; 348 InitProxyResolver init(&resolver, &fetcher); 349 EXPECT_EQ(kFailedDownloading, init.Init(config, &callback, NULL)); 350 EXPECT_EQ("", resolver.pac_bytes()); 351} 352 353// Fails at WPAD (downloading), and fails at custom PAC (parsing). 354TEST(InitProxyResolverTest, AutodetectFailCustomFails2) { 355 Rules rules; 356 RuleBasedProxyResolver resolver(&rules, true /*expects_pac_bytes*/); 357 RuleBasedProxyScriptFetcher fetcher(&rules); 358 359 ProxyConfig config; 360 config.auto_detect = true; 361 config.pac_url = GURL("http://custom/proxy.pac"); 362 363 rules.AddFailDownloadRule("http://wpad/wpad.dat"); 364 rules.AddFailParsingRule("http://custom/proxy.pac"); 365 366 TestCompletionCallback callback; 367 InitProxyResolver init(&resolver, &fetcher); 368 EXPECT_EQ(kFailedParsing, init.Init(config, &callback, NULL)); 369 EXPECT_EQ("", resolver.pac_bytes()); 370} 371 372// Fails at WPAD (parsing), but succeeds in choosing the custom PAC. 373// This is the same as AutodetectFailCustomSuccess2, but using a ProxyResolver 374// that doesn't |expects_pac_bytes|. 375TEST(InitProxyResolverTest, AutodetectFailCustomSuccess2_NoFetch) { 376 Rules rules; 377 RuleBasedProxyResolver resolver(&rules, false /*expects_pac_bytes*/); 378 RuleBasedProxyScriptFetcher fetcher(&rules); 379 380 ProxyConfig config; 381 config.auto_detect = true; 382 config.pac_url = GURL("http://custom/proxy.pac"); 383 384 rules.AddFailParsingRule(""); // Autodetect. 385 Rules::Rule rule = rules.AddSuccessRule("http://custom/proxy.pac"); 386 387 TestCompletionCallback callback; 388 InitProxyResolver init(&resolver, &fetcher); 389 EXPECT_EQ(OK, init.Init(config, &callback, NULL)); 390 EXPECT_EQ(rule.url, resolver.pac_url()); 391} 392 393} // namespace 394} // namespace net 395