1 // Copyright (c) 2012 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 // Unit tests for helper functions for the Chrome Extensions Proxy Settings API. 6 7 #include "base/memory/scoped_ptr.h" 8 #include "base/values.h" 9 #include "chrome/browser/extensions/api/proxy/proxy_api_constants.h" 10 #include "chrome/browser/extensions/api/proxy/proxy_api_helpers.h" 11 #include "chrome/browser/prefs/proxy_config_dictionary.h" 12 #include "chrome/browser/prefs/proxy_prefs.h" 13 #include "testing/gtest/include/gtest/gtest.h" 14 15 namespace extensions { 16 17 namespace keys = proxy_api_constants; 18 19 namespace { 20 21 const char kSamplePacScript[] = "test"; 22 const char kSamplePacScriptAsDataUrl[] = 23 "data:application/x-ns-proxy-autoconfig;base64,dGVzdA=="; 24 const char kSamplePacScriptAsDataUrl2[] = 25 "data:;base64,dGVzdA=="; 26 const char kSamplePacScriptUrl[] = "http://wpad/wpad.dat"; 27 28 // Helper function to create a ProxyServer dictionary as defined in the 29 // extension API. 30 base::DictionaryValue* CreateTestProxyServerDict(const std::string& host) { 31 base::DictionaryValue* dict = new base::DictionaryValue; 32 dict->SetString(keys::kProxyConfigRuleHost, host); 33 return dict; 34 } 35 36 // Helper function to create a ProxyServer dictionary as defined in the 37 // extension API. 38 base::DictionaryValue* CreateTestProxyServerDict(const std::string& schema, 39 const std::string& host, 40 int port) { 41 base::DictionaryValue* dict = new base::DictionaryValue; 42 dict->SetString(keys::kProxyConfigRuleScheme, schema); 43 dict->SetString(keys::kProxyConfigRuleHost, host); 44 dict->SetInteger(keys::kProxyConfigRulePort, port); 45 return dict; 46 } 47 48 } // namespace 49 50 namespace proxy_api_helpers { 51 52 TEST(ExtensionProxyApiHelpers, CreateDataURLFromPACScript) { 53 std::string out; 54 ASSERT_TRUE(CreateDataURLFromPACScript(kSamplePacScript, &out)); 55 EXPECT_EQ(kSamplePacScriptAsDataUrl, out); 56 } 57 58 TEST(ExtensionProxyApiHelpers, CreatePACScriptFromDataURL) { 59 std::string out; 60 // Verify deserialization of a PAC data:// URL that we created ourselves. 61 ASSERT_TRUE(CreatePACScriptFromDataURL(kSamplePacScriptAsDataUrl, &out)); 62 EXPECT_EQ(kSamplePacScript, out); 63 64 // Check that we don't require a mime-type. 65 ASSERT_TRUE(CreatePACScriptFromDataURL(kSamplePacScriptAsDataUrl2, &out)); 66 EXPECT_EQ(kSamplePacScript, out); 67 68 EXPECT_FALSE(CreatePACScriptFromDataURL("http://www.google.com", &out)); 69 } 70 71 TEST(ExtensionProxyApiHelpers, GetProxyModeFromExtensionPref) { 72 base::DictionaryValue proxy_config; 73 ProxyPrefs::ProxyMode mode; 74 std::string error; 75 bool bad_message = false; 76 77 // Test positive case. 78 proxy_config.SetString( 79 keys::kProxyConfigMode, 80 ProxyPrefs::ProxyModeToString(ProxyPrefs::MODE_DIRECT)); 81 ASSERT_TRUE(GetProxyModeFromExtensionPref(&proxy_config, &mode, &error, 82 &bad_message)); 83 EXPECT_EQ(ProxyPrefs::MODE_DIRECT, mode); 84 EXPECT_EQ(std::string(), error); 85 EXPECT_FALSE(bad_message); 86 87 // Test negative case. 88 proxy_config.SetString(keys::kProxyConfigMode, "foobar"); 89 EXPECT_FALSE(GetProxyModeFromExtensionPref(&proxy_config, &mode, &error, 90 &bad_message)); 91 EXPECT_TRUE(bad_message); 92 93 // Do not test |error|, as an invalid enumeration value is considered an 94 // internal error. It should be filtered by the extensions API. 95 } 96 97 TEST(ExtensionProxyApiHelpers, GetPacUrlFromExtensionPref) { 98 std::string out; 99 std::string error; 100 bool bad_message = false; 101 102 base::DictionaryValue proxy_config; 103 proxy_config.SetString( 104 keys::kProxyConfigMode, 105 ProxyPrefs::ProxyModeToString(ProxyPrefs::MODE_PAC_SCRIPT)); 106 107 // Currently we are still missing a PAC script entry. 108 // This is silently ignored. 109 ASSERT_TRUE(GetPacUrlFromExtensionPref(&proxy_config, &out, &error, 110 &bad_message)); 111 EXPECT_EQ(std::string(), out); 112 EXPECT_EQ(std::string(), error); 113 EXPECT_FALSE(bad_message); 114 115 // Set up a pac script. 116 base::DictionaryValue* pacScriptDict = new base::DictionaryValue; 117 pacScriptDict->SetString(keys::kProxyConfigPacScriptUrl, kSamplePacScriptUrl); 118 proxy_config.Set(keys::kProxyConfigPacScript, pacScriptDict); 119 120 ASSERT_TRUE(GetPacUrlFromExtensionPref(&proxy_config, &out, &error, 121 &bad_message)); 122 EXPECT_EQ(kSamplePacScriptUrl, out); 123 EXPECT_EQ(std::string(), error); 124 EXPECT_FALSE(bad_message); 125 } 126 127 TEST(ExtensionProxyApiHelpers, GetPacDataFromExtensionPref) { 128 std::string out; 129 std::string error; 130 bool bad_message = false; 131 132 base::DictionaryValue proxy_config; 133 proxy_config.SetString( 134 keys::kProxyConfigMode, 135 ProxyPrefs::ProxyModeToString(ProxyPrefs::MODE_PAC_SCRIPT)); 136 137 // Currently we are still missing a PAC data entry. This is silently ignored. 138 ASSERT_TRUE(GetPacDataFromExtensionPref(&proxy_config, &out, &error, 139 &bad_message)); 140 EXPECT_EQ(std::string(), out); 141 EXPECT_EQ(std::string(), error); 142 EXPECT_FALSE(bad_message); 143 144 // Set up a PAC script. 145 base::DictionaryValue* pacScriptDict = new base::DictionaryValue; 146 pacScriptDict->SetString(keys::kProxyConfigPacScriptData, kSamplePacScript); 147 proxy_config.Set(keys::kProxyConfigPacScript, pacScriptDict); 148 149 ASSERT_TRUE(GetPacDataFromExtensionPref(&proxy_config, &out, &error, 150 &bad_message)); 151 EXPECT_EQ(kSamplePacScript, out); 152 EXPECT_EQ(std::string(), error); 153 EXPECT_FALSE(bad_message); 154 } 155 156 TEST(ExtensionProxyApiHelpers, GetProxyRulesStringFromExtensionPref) { 157 std::string out; 158 std::string error; 159 bool bad_message = false; 160 161 base::DictionaryValue proxy_config; 162 proxy_config.SetString( 163 keys::kProxyConfigMode, 164 ProxyPrefs::ProxyModeToString(ProxyPrefs::MODE_FIXED_SERVERS)); 165 166 // Currently we are still missing a proxy config entry. 167 // This is silently ignored. 168 ASSERT_TRUE( 169 GetProxyRulesStringFromExtensionPref(&proxy_config, &out, &error, 170 &bad_message)); 171 EXPECT_EQ(std::string(), out); 172 EXPECT_EQ(std::string(), error); 173 174 base::DictionaryValue* proxy_rules = new base::DictionaryValue; 175 proxy_rules->Set(keys::field_name[1], CreateTestProxyServerDict("proxy1")); 176 proxy_rules->Set(keys::field_name[2], CreateTestProxyServerDict("proxy2")); 177 proxy_config.Set(keys::kProxyConfigRules, proxy_rules); 178 179 ASSERT_TRUE( 180 GetProxyRulesStringFromExtensionPref(&proxy_config, &out, &error, 181 &bad_message)); 182 EXPECT_EQ("http=proxy1:80;https=proxy2:80", out); 183 EXPECT_EQ(std::string(), error); 184 EXPECT_FALSE(bad_message); 185 } 186 187 TEST(ExtensionProxyApiHelpers, GetBypassListFromExtensionPref) { 188 std::string out; 189 std::string error; 190 bool bad_message = false; 191 192 base::DictionaryValue proxy_config; 193 proxy_config.SetString( 194 keys::kProxyConfigMode, 195 ProxyPrefs::ProxyModeToString(ProxyPrefs::MODE_FIXED_SERVERS)); 196 197 // Currently we are still missing a proxy config entry. 198 // This is silently ignored. 199 ASSERT_TRUE( 200 GetBypassListFromExtensionPref(&proxy_config, &out, &error, 201 &bad_message)); 202 EXPECT_EQ(std::string(), out); 203 EXPECT_EQ(std::string(), error); 204 EXPECT_FALSE(bad_message); 205 206 base::ListValue* bypass_list = new base::ListValue; 207 bypass_list->Append(new base::StringValue("host1")); 208 bypass_list->Append(new base::StringValue("host2")); 209 base::DictionaryValue* proxy_rules = new base::DictionaryValue; 210 proxy_rules->Set(keys::kProxyConfigBypassList, bypass_list); 211 proxy_config.Set(keys::kProxyConfigRules, proxy_rules); 212 213 ASSERT_TRUE( 214 GetBypassListFromExtensionPref(&proxy_config, &out, &error, 215 &bad_message)); 216 EXPECT_EQ("host1,host2", out); 217 EXPECT_EQ(std::string(), error); 218 EXPECT_FALSE(bad_message); 219 } 220 221 TEST(ExtensionProxyApiHelpers, CreateProxyConfigDict) { 222 std::string error; 223 scoped_ptr<base::DictionaryValue> exp_direct( 224 ProxyConfigDictionary::CreateDirect()); 225 scoped_ptr<base::DictionaryValue> out_direct( 226 CreateProxyConfigDict(ProxyPrefs::MODE_DIRECT, 227 false, 228 std::string(), 229 std::string(), 230 std::string(), 231 std::string(), 232 &error)); 233 EXPECT_TRUE(base::Value::Equals(exp_direct.get(), out_direct.get())); 234 235 scoped_ptr<base::DictionaryValue> exp_auto( 236 ProxyConfigDictionary::CreateAutoDetect()); 237 scoped_ptr<base::DictionaryValue> out_auto( 238 CreateProxyConfigDict(ProxyPrefs::MODE_AUTO_DETECT, 239 false, 240 std::string(), 241 std::string(), 242 std::string(), 243 std::string(), 244 &error)); 245 EXPECT_TRUE(base::Value::Equals(exp_auto.get(), out_auto.get())); 246 247 scoped_ptr<base::DictionaryValue> exp_pac_url( 248 ProxyConfigDictionary::CreatePacScript(kSamplePacScriptUrl, false)); 249 scoped_ptr<base::DictionaryValue> out_pac_url( 250 CreateProxyConfigDict(ProxyPrefs::MODE_PAC_SCRIPT, 251 false, 252 kSamplePacScriptUrl, 253 std::string(), 254 std::string(), 255 std::string(), 256 &error)); 257 EXPECT_TRUE(base::Value::Equals(exp_pac_url.get(), out_pac_url.get())); 258 259 scoped_ptr<base::DictionaryValue> exp_pac_data( 260 ProxyConfigDictionary::CreatePacScript(kSamplePacScriptAsDataUrl, false)); 261 scoped_ptr<base::DictionaryValue> out_pac_data( 262 CreateProxyConfigDict(ProxyPrefs::MODE_PAC_SCRIPT, 263 false, 264 std::string(), 265 kSamplePacScript, 266 std::string(), 267 std::string(), 268 &error)); 269 EXPECT_TRUE(base::Value::Equals(exp_pac_data.get(), out_pac_data.get())); 270 271 scoped_ptr<base::DictionaryValue> exp_fixed( 272 ProxyConfigDictionary::CreateFixedServers("foo:80", "localhost")); 273 scoped_ptr<base::DictionaryValue> out_fixed( 274 CreateProxyConfigDict(ProxyPrefs::MODE_FIXED_SERVERS, 275 false, 276 std::string(), 277 std::string(), 278 "foo:80", 279 "localhost", 280 &error)); 281 EXPECT_TRUE(base::Value::Equals(exp_fixed.get(), out_fixed.get())); 282 283 scoped_ptr<base::DictionaryValue> exp_system( 284 ProxyConfigDictionary::CreateSystem()); 285 scoped_ptr<base::DictionaryValue> out_system( 286 CreateProxyConfigDict(ProxyPrefs::MODE_SYSTEM, 287 false, 288 std::string(), 289 std::string(), 290 std::string(), 291 std::string(), 292 &error)); 293 EXPECT_TRUE(base::Value::Equals(exp_system.get(), out_system.get())); 294 295 // Neither of them should have set an error. 296 EXPECT_EQ(std::string(), error); 297 } 298 299 TEST(ExtensionProxyApiHelpers, GetProxyServer) { 300 base::DictionaryValue proxy_server_dict; 301 net::ProxyServer created; 302 std::string error; 303 bool bad_message = false; 304 305 // Test simplest case, no schema nor port specified --> defaults are used. 306 proxy_server_dict.SetString(keys::kProxyConfigRuleHost, "proxy_server"); 307 ASSERT_TRUE( 308 GetProxyServer(&proxy_server_dict, net::ProxyServer::SCHEME_HTTP, 309 &created, &error, &bad_message)); 310 EXPECT_EQ("PROXY proxy_server:80", created.ToPacString()); 311 EXPECT_FALSE(bad_message); 312 313 // Test complete case. 314 proxy_server_dict.SetString(keys::kProxyConfigRuleScheme, "socks4"); 315 proxy_server_dict.SetInteger(keys::kProxyConfigRulePort, 1234); 316 ASSERT_TRUE( 317 GetProxyServer(&proxy_server_dict, net::ProxyServer::SCHEME_HTTP, 318 &created, &error, &bad_message)); 319 EXPECT_EQ("SOCKS proxy_server:1234", created.ToPacString()); 320 EXPECT_FALSE(bad_message); 321 } 322 323 TEST(ExtensionProxyApiHelpers, JoinUrlList) { 324 bool bad_message = false; 325 base::ListValue list; 326 list.Append(new base::StringValue("s1")); 327 list.Append(new base::StringValue("s2")); 328 list.Append(new base::StringValue("s3")); 329 330 std::string out; 331 std::string error; 332 ASSERT_TRUE(JoinUrlList(&list, ";", &out, &error, &bad_message)); 333 EXPECT_EQ("s1;s2;s3", out); 334 EXPECT_FALSE(bad_message); 335 } 336 337 // This tests CreateProxyServerDict as well. 338 TEST(ExtensionProxyApiHelpers, CreateProxyRulesDict) { 339 scoped_ptr<base::DictionaryValue> browser_pref( 340 ProxyConfigDictionary::CreateFixedServers( 341 "http=proxy1:80;https=proxy2:80;ftp=proxy3:80;socks=proxy4:80", 342 "localhost")); 343 ProxyConfigDictionary config(browser_pref.get()); 344 scoped_ptr<base::DictionaryValue> extension_pref( 345 CreateProxyRulesDict(config)); 346 ASSERT_TRUE(extension_pref.get()); 347 348 scoped_ptr<base::DictionaryValue> expected(new base::DictionaryValue); 349 expected->Set("proxyForHttp", 350 CreateTestProxyServerDict("http", "proxy1", 80)); 351 expected->Set("proxyForHttps", 352 CreateTestProxyServerDict("http", "proxy2", 80)); 353 expected->Set("proxyForFtp", 354 CreateTestProxyServerDict("http", "proxy3", 80)); 355 expected->Set("fallbackProxy", 356 CreateTestProxyServerDict("socks4", "proxy4", 80)); 357 base::ListValue* bypass_list = new base::ListValue; 358 bypass_list->Append(new base::StringValue("localhost")); 359 expected->Set(keys::kProxyConfigBypassList, bypass_list); 360 361 EXPECT_TRUE(base::Value::Equals(expected.get(), extension_pref.get())); 362 } 363 364 // Test multiple proxies per scheme -- expect that only the first is returned. 365 TEST(ExtensionProxyApiHelpers, CreateProxyRulesDictMultipleProxies) { 366 scoped_ptr<base::DictionaryValue> browser_pref( 367 ProxyConfigDictionary::CreateFixedServers( 368 "http=proxy1:80,default://;https=proxy2:80,proxy1:80;ftp=proxy3:80," 369 "https://proxy5:443;socks=proxy4:80,proxy1:80", 370 "localhost")); 371 ProxyConfigDictionary config(browser_pref.get()); 372 scoped_ptr<base::DictionaryValue> extension_pref( 373 CreateProxyRulesDict(config)); 374 ASSERT_TRUE(extension_pref.get()); 375 376 scoped_ptr<base::DictionaryValue> expected(new base::DictionaryValue); 377 expected->Set("proxyForHttp", 378 CreateTestProxyServerDict("http", "proxy1", 80)); 379 expected->Set("proxyForHttps", 380 CreateTestProxyServerDict("http", "proxy2", 80)); 381 expected->Set("proxyForFtp", 382 CreateTestProxyServerDict("http", "proxy3", 80)); 383 expected->Set("fallbackProxy", 384 CreateTestProxyServerDict("socks4", "proxy4", 80)); 385 base::ListValue* bypass_list = new base::ListValue; 386 bypass_list->Append(new base::StringValue("localhost")); 387 expected->Set(keys::kProxyConfigBypassList, bypass_list); 388 389 EXPECT_TRUE(base::Value::Equals(expected.get(), extension_pref.get())); 390 } 391 392 // Test if a PAC script URL is specified. 393 TEST(ExtensionProxyApiHelpers, CreatePacScriptDictWithUrl) { 394 scoped_ptr<base::DictionaryValue> browser_pref( 395 ProxyConfigDictionary::CreatePacScript(kSamplePacScriptUrl, false)); 396 ProxyConfigDictionary config(browser_pref.get()); 397 scoped_ptr<base::DictionaryValue> extension_pref(CreatePacScriptDict(config)); 398 ASSERT_TRUE(extension_pref.get()); 399 400 scoped_ptr<base::DictionaryValue> expected(new base::DictionaryValue); 401 expected->SetString(keys::kProxyConfigPacScriptUrl, kSamplePacScriptUrl); 402 expected->SetBoolean(keys::kProxyConfigPacScriptMandatory, false); 403 404 EXPECT_TRUE(base::Value::Equals(expected.get(), extension_pref.get())); 405 } 406 407 // Test if a PAC script is encoded in a data URL. 408 TEST(ExtensionProxyApiHelpers, CreatePacScriptDictWidthData) { 409 scoped_ptr<base::DictionaryValue> browser_pref( 410 ProxyConfigDictionary::CreatePacScript(kSamplePacScriptAsDataUrl, false)); 411 ProxyConfigDictionary config(browser_pref.get()); 412 scoped_ptr<base::DictionaryValue> extension_pref(CreatePacScriptDict(config)); 413 ASSERT_TRUE(extension_pref.get()); 414 415 scoped_ptr<base::DictionaryValue> expected(new base::DictionaryValue); 416 expected->SetString(keys::kProxyConfigPacScriptData, kSamplePacScript); 417 expected->SetBoolean(keys::kProxyConfigPacScriptMandatory, false); 418 419 EXPECT_TRUE(base::Value::Equals(expected.get(), extension_pref.get())); 420 } 421 422 TEST(ExtensionProxyApiHelpers, TokenizeToStringList) { 423 base::ListValue expected; 424 expected.Append(new base::StringValue("s1")); 425 expected.Append(new base::StringValue("s2")); 426 expected.Append(new base::StringValue("s3")); 427 428 scoped_ptr<base::ListValue> out(TokenizeToStringList("s1;s2;s3", ";")); 429 EXPECT_TRUE(base::Value::Equals(&expected, out.get())); 430 } 431 432 } // namespace proxy_api_helpers 433 } // namespace extensions 434