diff options
28 files changed, 241 insertions, 51 deletions
diff --git a/chrome/browser/automation/automation_provider.cc b/chrome/browser/automation/automation_provider.cc index 5a86ca7..a5a6686 100644 --- a/chrome/browser/automation/automation_provider.cc +++ b/chrome/browser/automation/automation_provider.cc @@ -550,6 +550,10 @@ class SetProxyConfigTask : public Task { if (dict.GetString(automation::kJSONProxyPacUrl, &pac_url)) { pc->set_pac_url(GURL(pac_url)); } + bool pac_mandatory; + if (dict.GetBoolean(automation::kJSONProxyPacMandatory, &pac_mandatory)) { + pc->set_pac_mandatory(pac_mandatory); + } std::string proxy_bypass_list; if (dict.GetString(automation::kJSONProxyBypassList, &proxy_bypass_list)) { pc->proxy_rules().bypass_rules.ParseFromString(proxy_bypass_list); diff --git a/chrome/browser/extensions/extension_preference_api.h b/chrome/browser/extensions/extension_preference_api.h index 31c4452..19325d5 100644 --- a/chrome/browser/extensions/extension_preference_api.h +++ b/chrome/browser/extensions/extension_preference_api.h @@ -50,6 +50,8 @@ class PrefTransformerInterface { // Returns the pref store representation in case of success or sets // |error| and returns NULL otherwise. // The ownership of the returned value is passed to the caller. + // TODO(battre): add bool* bad_message to allow terminating the entire + // extension in order to simulate the behavior of EXTENSION_FUNCTION_VALIDATE. virtual Value* ExtensionToBrowserPref(const Value* extension_pref, std::string* error) = 0; diff --git a/chrome/browser/extensions/extension_proxy_api.cc b/chrome/browser/extensions/extension_proxy_api.cc index ccf62bd..ad9aae9 100644 --- a/chrome/browser/extensions/extension_proxy_api.cc +++ b/chrome/browser/extensions/extension_proxy_api.cc @@ -73,11 +73,14 @@ Value* ProxyPrefTransformer::ExtensionToBrowserPref(const Value* extension_pref, // If a values has been passed to set but could not be parsed, we bail // out and return NULL. ProxyPrefs::ProxyMode mode_enum; + bool pac_mandatory; std::string pac_url; std::string pac_data; std::string proxy_rules_string; std::string bypass_list; if (!helpers::GetProxyModeFromExtensionPref(config, &mode_enum, error) || + !helpers::GetPacMandatoryFromExtensionPref(config, &pac_mandatory, + error) || !helpers::GetPacUrlFromExtensionPref(config, &pac_url, error) || !helpers::GetPacDataFromExtensionPref(config, &pac_data, error) || !helpers::GetProxyRulesStringFromExtensionPref( @@ -87,7 +90,8 @@ Value* ProxyPrefTransformer::ExtensionToBrowserPref(const Value* extension_pref, } return helpers::CreateProxyConfigDict( - mode_enum, pac_url, pac_data, proxy_rules_string, bypass_list, error); + mode_enum, pac_mandatory, pac_url, pac_data, proxy_rules_string, + bypass_list, error); } Value* ProxyPrefTransformer::BrowserToExtensionPref(const Value* browser_pref) { diff --git a/chrome/browser/extensions/extension_proxy_api_constants.cc b/chrome/browser/extensions/extension_proxy_api_constants.cc index f7f52bb..9078265 100644 --- a/chrome/browser/extensions/extension_proxy_api_constants.cc +++ b/chrome/browser/extensions/extension_proxy_api_constants.cc @@ -12,6 +12,7 @@ namespace extension_proxy_api_constants { const char kProxyConfigMode[] = "mode"; const char kProxyConfigPacScript[] = "pacScript"; +const char kProxyConfigPacScriptMandatory[] = "mandatory"; const char kProxyConfigPacScriptUrl[] = "url"; const char kProxyConfigPacScriptData[] = "data"; const char kProxyConfigRules[] = "rules"; diff --git a/chrome/browser/extensions/extension_proxy_api_constants.h b/chrome/browser/extensions/extension_proxy_api_constants.h index 13fbe67..1b8a99d 100644 --- a/chrome/browser/extensions/extension_proxy_api_constants.h +++ b/chrome/browser/extensions/extension_proxy_api_constants.h @@ -13,6 +13,7 @@ namespace extension_proxy_api_constants { // String literals in dictionaries used to communicate with extension. extern const char kProxyConfigMode[]; extern const char kProxyConfigPacScript[]; +extern const char kProxyConfigPacScriptMandatory[]; extern const char kProxyConfigPacScriptUrl[]; extern const char kProxyConfigPacScriptData[]; extern const char kProxyConfigRules[]; diff --git a/chrome/browser/extensions/extension_proxy_api_helpers.cc b/chrome/browser/extensions/extension_proxy_api_helpers.cc index 6429843..8c258b0 100644 --- a/chrome/browser/extensions/extension_proxy_api_helpers.cc +++ b/chrome/browser/extensions/extension_proxy_api_helpers.cc @@ -72,6 +72,25 @@ bool GetProxyModeFromExtensionPref(const DictionaryValue* proxy_config, return true; } +bool GetPacMandatoryFromExtensionPref(const DictionaryValue* proxy_config, + bool* out, + std::string* error){ + DictionaryValue* pac_dict = NULL; + proxy_config->GetDictionary(keys::kProxyConfigPacScript, &pac_dict); + if (!pac_dict) + return true; + + bool mandatory_pac = false; + if (pac_dict->HasKey(keys::kProxyConfigPacScriptMandatory) && + !pac_dict->GetBoolean(keys::kProxyConfigPacScriptMandatory, + &mandatory_pac)) { + LOG(ERROR) << "'pacScript.mandatory' could not be parsed."; + return false; + } + *out = mandatory_pac; + return true; +} + bool GetPacUrlFromExtensionPref(const DictionaryValue* proxy_config, std::string* out, std::string* error) { @@ -272,6 +291,7 @@ bool GetBypassListFromExtensionPref(const DictionaryValue* proxy_config, } DictionaryValue* CreateProxyConfigDict(ProxyPrefs::ProxyMode mode_enum, + bool pac_mandatory, const std::string& pac_url, const std::string& pac_data, const std::string& proxy_rules_string, @@ -299,7 +319,8 @@ DictionaryValue* CreateProxyConfigDict(ProxyPrefs::ProxyMode mode_enum, "either a 'url' field or a 'data' field."; return NULL; } - result_proxy_config = ProxyConfigDictionary::CreatePacScript(url); + result_proxy_config = + ProxyConfigDictionary::CreatePacScript(url, pac_mandatory); break; } case ProxyPrefs::MODE_FIXED_SERVERS: { @@ -419,6 +440,11 @@ DictionaryValue* CreatePacScriptDict( LOG(ERROR) << "Invalid proxy configuration. Missing PAC URL."; return NULL; } + bool pac_mandatory = false; + if (!proxy_config.GetPacMandatory(&pac_mandatory)) { + LOG(ERROR) << "Invalid proxy configuration. Missing PAC mandatory field."; + return NULL; + } if (pac_url.find("data") == 0) { std::string pac_data; @@ -430,6 +456,8 @@ DictionaryValue* CreatePacScriptDict( } else { pac_script_dict->SetString(keys::kProxyConfigPacScriptUrl, pac_url); } + pac_script_dict->SetBoolean(keys::kProxyConfigPacScriptMandatory, + pac_mandatory); return pac_script_dict.release(); } diff --git a/chrome/browser/extensions/extension_proxy_api_helpers.h b/chrome/browser/extensions/extension_proxy_api_helpers.h index d1d6782..11eb6b9 100644 --- a/chrome/browser/extensions/extension_proxy_api_helpers.h +++ b/chrome/browser/extensions/extension_proxy_api_helpers.h @@ -46,6 +46,9 @@ bool CreatePACScriptFromDataURL( bool GetProxyModeFromExtensionPref(const DictionaryValue* proxy_config, ProxyPrefs::ProxyMode* out, std::string* error); +bool GetPacMandatoryFromExtensionPref(const DictionaryValue* proxy_config, + bool* out, + std::string* error); bool GetPacUrlFromExtensionPref(const DictionaryValue* proxy_config, std::string* out, std::string* error); @@ -63,6 +66,7 @@ bool GetBypassListFromExtensionPref(const DictionaryValue* proxy_config, // API) from the given parameters. Ownership is passed to the caller. // Depending on the value of |mode_enum|, several of the strings may be empty. DictionaryValue* CreateProxyConfigDict(ProxyPrefs::ProxyMode mode_enum, + bool pac_mandatory, const std::string& pac_url, const std::string& pac_data, const std::string& proxy_rules_string, diff --git a/chrome/browser/extensions/extension_proxy_api_helpers_unittest.cc b/chrome/browser/extensions/extension_proxy_api_helpers_unittest.cc index ef1fe16..2f73547 100644 --- a/chrome/browser/extensions/extension_proxy_api_helpers_unittest.cc +++ b/chrome/browser/extensions/extension_proxy_api_helpers_unittest.cc @@ -189,40 +189,42 @@ TEST(ExtensionProxyApiHelpers, CreateProxyConfigDict) { std::string error; scoped_ptr<DictionaryValue> exp_direct(ProxyConfigDictionary::CreateDirect()); scoped_ptr<DictionaryValue> out_direct( - CreateProxyConfigDict(ProxyPrefs::MODE_DIRECT, "", "", "", "", &error)); + CreateProxyConfigDict(ProxyPrefs::MODE_DIRECT, false, "", "", "", "", + &error)); EXPECT_TRUE(Value::Equals(exp_direct.get(), out_direct.get())); scoped_ptr<DictionaryValue> exp_auto( ProxyConfigDictionary::CreateAutoDetect()); scoped_ptr<DictionaryValue> out_auto( - CreateProxyConfigDict(ProxyPrefs::MODE_AUTO_DETECT, "", "", "", "", + CreateProxyConfigDict(ProxyPrefs::MODE_AUTO_DETECT, false, "", "", "", "", &error)); EXPECT_TRUE(Value::Equals(exp_auto.get(), out_auto.get())); scoped_ptr<DictionaryValue> exp_pac_url( - ProxyConfigDictionary::CreatePacScript(kSamplePacScriptUrl)); + ProxyConfigDictionary::CreatePacScript(kSamplePacScriptUrl, false)); scoped_ptr<DictionaryValue> out_pac_url( - CreateProxyConfigDict(ProxyPrefs::MODE_PAC_SCRIPT, kSamplePacScriptUrl, - "", "", "", &error)); + CreateProxyConfigDict(ProxyPrefs::MODE_PAC_SCRIPT, false, + kSamplePacScriptUrl, "", "", "", &error)); EXPECT_TRUE(Value::Equals(exp_pac_url.get(), out_pac_url.get())); scoped_ptr<DictionaryValue> exp_pac_data( - ProxyConfigDictionary::CreatePacScript(kSamplePacScriptAsDataUrl)); + ProxyConfigDictionary::CreatePacScript(kSamplePacScriptAsDataUrl, false)); scoped_ptr<DictionaryValue> out_pac_data( - CreateProxyConfigDict(ProxyPrefs::MODE_PAC_SCRIPT, "", + CreateProxyConfigDict(ProxyPrefs::MODE_PAC_SCRIPT, false, "", kSamplePacScript, "", "", &error)); EXPECT_TRUE(Value::Equals(exp_pac_data.get(), out_pac_data.get())); scoped_ptr<DictionaryValue> exp_fixed( ProxyConfigDictionary::CreateFixedServers("foo:80", "localhost")); scoped_ptr<DictionaryValue> out_fixed( - CreateProxyConfigDict(ProxyPrefs::MODE_FIXED_SERVERS, "", "", + CreateProxyConfigDict(ProxyPrefs::MODE_FIXED_SERVERS, false, "", "", "foo:80", "localhost", &error)); EXPECT_TRUE(Value::Equals(exp_fixed.get(), out_fixed.get())); scoped_ptr<DictionaryValue> exp_system(ProxyConfigDictionary::CreateSystem()); scoped_ptr<DictionaryValue> out_system( - CreateProxyConfigDict(ProxyPrefs::MODE_SYSTEM, "", "", "", "", &error)); + CreateProxyConfigDict(ProxyPrefs::MODE_SYSTEM, false, "", "", "", "", + &error)); EXPECT_TRUE(Value::Equals(exp_system.get(), out_system.get())); // Neither of them should have set an error. @@ -291,13 +293,14 @@ TEST(ExtensionProxyApiHelpers, CreateProxyRulesDict) { // Test if a PAC script URL is specified. TEST(ExtensionProxyApiHelpers, CreatePacScriptDictWithUrl) { scoped_ptr<DictionaryValue> browser_pref( - ProxyConfigDictionary::CreatePacScript(kSamplePacScriptUrl)); + ProxyConfigDictionary::CreatePacScript(kSamplePacScriptUrl, false)); ProxyConfigDictionary config(browser_pref.get()); scoped_ptr<DictionaryValue> extension_pref(CreatePacScriptDict(config)); ASSERT_TRUE(extension_pref.get()); scoped_ptr<DictionaryValue> expected(new DictionaryValue); expected->SetString(keys::kProxyConfigPacScriptUrl, kSamplePacScriptUrl); + expected->SetBoolean(keys::kProxyConfigPacScriptMandatory, false); EXPECT_TRUE(Value::Equals(expected.get(), extension_pref.get())); } @@ -305,13 +308,14 @@ TEST(ExtensionProxyApiHelpers, CreatePacScriptDictWithUrl) { // Test if a PAC script is encoded in a data URL. TEST(ExtensionProxyApiHelpers, CreatePacScriptDictWidthData) { scoped_ptr<DictionaryValue> browser_pref( - ProxyConfigDictionary::CreatePacScript(kSamplePacScriptAsDataUrl)); + ProxyConfigDictionary::CreatePacScript(kSamplePacScriptAsDataUrl, false)); ProxyConfigDictionary config(browser_pref.get()); scoped_ptr<DictionaryValue> extension_pref(CreatePacScriptDict(config)); ASSERT_TRUE(extension_pref.get()); scoped_ptr<DictionaryValue> expected(new DictionaryValue); expected->SetString(keys::kProxyConfigPacScriptData, kSamplePacScript); + expected->SetBoolean(keys::kProxyConfigPacScriptMandatory, false); EXPECT_TRUE(Value::Equals(expected.get(), extension_pref.get())); } diff --git a/chrome/browser/net/pref_proxy_config_service.cc b/chrome/browser/net/pref_proxy_config_service.cc index 7862be9..f867923 100644 --- a/chrome/browser/net/pref_proxy_config_service.cc +++ b/chrome/browser/net/pref_proxy_config_service.cc @@ -137,6 +137,9 @@ bool PrefProxyConfigTracker::PrefConfigToNetConfig( return true; } config->set_pac_url(proxy_pac_url); + bool pac_mandatory = false; + proxy_dict.GetPacMandatory(&pac_mandatory); + config->set_pac_mandatory(pac_mandatory); return true; } case ProxyPrefs::MODE_FIXED_SERVERS: { diff --git a/chrome/browser/net/pref_proxy_config_service_unittest.cc b/chrome/browser/net/pref_proxy_config_service_unittest.cc index 19bb53b..6d959a3 100644 --- a/chrome/browser/net/pref_proxy_config_service_unittest.cc +++ b/chrome/browser/net/pref_proxy_config_service_unittest.cc @@ -177,7 +177,7 @@ TEST_F(PrefProxyConfigServiceTest, Observers) { CONFIG_VALID)).Times(1); pref_service_->SetManagedPref( prefs::kProxy, - ProxyConfigDictionary::CreatePacScript(kFixedPacUrl)); + ProxyConfigDictionary::CreatePacScript(kFixedPacUrl, false)); loop_.RunAllPending(); Mock::VerifyAndClearExpectations(&observer); @@ -242,7 +242,7 @@ TEST_F(PrefProxyConfigServiceTest, Fallback) { CONFIG_VALID)).Times(1); pref_service_->SetManagedPref( prefs::kProxy, - ProxyConfigDictionary::CreatePacScript(kFixedPacUrl)); + ProxyConfigDictionary::CreatePacScript(kFixedPacUrl, false)); loop_.RunAllPending(); Mock::VerifyAndClearExpectations(&observer); EXPECT_EQ(CONFIG_VALID, diff --git a/chrome/browser/policy/configuration_policy_pref_store.cc b/chrome/browser/policy/configuration_policy_pref_store.cc index e24cbfd..b5ab3d0 100644 --- a/chrome/browser/policy/configuration_policy_pref_store.cc +++ b/chrome/browser/policy/configuration_policy_pref_store.cc @@ -692,7 +692,7 @@ void ConfigurationPolicyPrefKeeper::ApplyProxySettings() { std::string pac_url; proxy_policies_[kPolicyProxyPacUrl]->GetAsString(&pac_url); prefs_.SetValue(prefs::kProxy, - ProxyConfigDictionary::CreatePacScript(pac_url)); + ProxyConfigDictionary::CreatePacScript(pac_url, false)); break; } case ProxyPrefs::MODE_FIXED_SERVERS: { diff --git a/chrome/browser/prefs/command_line_pref_store.cc b/chrome/browser/prefs/command_line_pref_store.cc index a992ced..03b6ef6 100644 --- a/chrome/browser/prefs/command_line_pref_store.cc +++ b/chrome/browser/prefs/command_line_pref_store.cc @@ -86,7 +86,7 @@ void CommandLinePrefStore::ApplyProxyMode() { std::string pac_script_url = command_line_->GetSwitchValueASCII(switches::kProxyPacUrl); SetValue(prefs::kProxy, - ProxyConfigDictionary::CreatePacScript(pac_script_url)); + ProxyConfigDictionary::CreatePacScript(pac_script_url, false)); } else if (command_line_->HasSwitch(switches::kProxyAutoDetect)) { SetValue(prefs::kProxy, ProxyConfigDictionary::CreateAutoDetect()); diff --git a/chrome/browser/prefs/proxy_config_dictionary.cc b/chrome/browser/prefs/proxy_config_dictionary.cc index 0c063cd..a99fa7c 100644 --- a/chrome/browser/prefs/proxy_config_dictionary.cc +++ b/chrome/browser/prefs/proxy_config_dictionary.cc @@ -19,6 +19,10 @@ const char kProxyMode[] = "mode"; const char kProxyServer[] = "server"; // URL to the proxy .pac file. const char kProxyPacUrl[] = "pac_url"; +// Optional boolean flag indicating whether a valid PAC script is mandatory. +// If true, network traffic does not fall back to direct connections in case the +// PAC script is not available. +const char kProxyPacMandatory[] = "pac_mandatory"; // String containing proxy bypass rules. For a specification of the // expected syntax see net::ProxyBypassRules::ParseFromString(). const char kProxyBypassList[] = "bypass_list"; @@ -41,6 +45,14 @@ bool ProxyConfigDictionary::GetPacUrl(std::string* out) const { return dict_->GetString(kProxyPacUrl, out); } +bool ProxyConfigDictionary::GetPacMandatory(bool* out) const { + if (!dict_->HasKey(kProxyPacMandatory)) { + *out = false; + return true; + } + return dict_->GetBoolean(kProxyPacMandatory, out); +} + bool ProxyConfigDictionary::GetProxyServer(std::string* out) const { return dict_->GetString(kProxyServer, out); } @@ -55,18 +67,20 @@ bool ProxyConfigDictionary::HasBypassList() const { // static DictionaryValue* ProxyConfigDictionary::CreateDirect() { - return CreateDictionary(ProxyPrefs::MODE_DIRECT, "", "", ""); + return CreateDictionary(ProxyPrefs::MODE_DIRECT, "", false, "", ""); } // static DictionaryValue* ProxyConfigDictionary::CreateAutoDetect() { - return CreateDictionary(ProxyPrefs::MODE_AUTO_DETECT, "", "", ""); + return CreateDictionary(ProxyPrefs::MODE_AUTO_DETECT, "", false, "", ""); } // static DictionaryValue* ProxyConfigDictionary::CreatePacScript( - const std::string& pac_url) { - return CreateDictionary(ProxyPrefs::MODE_PAC_SCRIPT, pac_url, "", ""); + const std::string& pac_url, + bool pac_mandatory) { + return CreateDictionary(ProxyPrefs::MODE_PAC_SCRIPT, + pac_url, pac_mandatory, "", ""); } // static @@ -75,7 +89,7 @@ DictionaryValue* ProxyConfigDictionary::CreateFixedServers( const std::string& bypass_list) { if (!proxy_server.empty()) { return CreateDictionary( - ProxyPrefs::MODE_FIXED_SERVERS, "", proxy_server, bypass_list); + ProxyPrefs::MODE_FIXED_SERVERS, "", false, proxy_server, bypass_list); } else { return CreateDirect(); } @@ -83,19 +97,22 @@ DictionaryValue* ProxyConfigDictionary::CreateFixedServers( // static DictionaryValue* ProxyConfigDictionary::CreateSystem() { - return CreateDictionary(ProxyPrefs::MODE_SYSTEM, "", "", ""); + return CreateDictionary(ProxyPrefs::MODE_SYSTEM, "", false, "", ""); } // static DictionaryValue* ProxyConfigDictionary::CreateDictionary( ProxyPrefs::ProxyMode mode, const std::string& pac_url, + bool pac_mandatory, const std::string& proxy_server, const std::string& bypass_list) { DictionaryValue* dict = new DictionaryValue(); dict->SetString(kProxyMode, ProxyModeToString(mode)); - if (!pac_url.empty()) + if (!pac_url.empty()) { dict->SetString(kProxyPacUrl, pac_url); + dict->SetBoolean(kProxyPacMandatory, pac_mandatory); + } if (!proxy_server.empty()) dict->SetString(kProxyServer, proxy_server); if (!bypass_list.empty()) diff --git a/chrome/browser/prefs/proxy_config_dictionary.h b/chrome/browser/prefs/proxy_config_dictionary.h index c05f182..3eeac12 100644 --- a/chrome/browser/prefs/proxy_config_dictionary.h +++ b/chrome/browser/prefs/proxy_config_dictionary.h @@ -31,13 +31,15 @@ class ProxyConfigDictionary { bool GetMode(ProxyPrefs::ProxyMode* out) const; bool GetPacUrl(std::string* out) const; + bool GetPacMandatory(bool* out) const; bool GetProxyServer(std::string* out) const; bool GetBypassList(std::string* out) const; bool HasBypassList() const; static DictionaryValue* CreateDirect(); static DictionaryValue* CreateAutoDetect(); - static DictionaryValue* CreatePacScript(const std::string& pac_url); + static DictionaryValue* CreatePacScript(const std::string& pac_url, + bool pac_mandatory); static DictionaryValue* CreateFixedServers( const std::string& proxy_server, const std::string& bypass_list); @@ -45,6 +47,7 @@ class ProxyConfigDictionary { private: static DictionaryValue* CreateDictionary(ProxyPrefs::ProxyMode mode, const std::string& pac_url, + bool pac_mandatory, const std::string& proxy_server, const std::string& bypass_list); diff --git a/chrome/browser/prefs/proxy_config_dictionary_unittest.cc b/chrome/browser/prefs/proxy_config_dictionary_unittest.cc index 5575b66..8301266 100644 --- a/chrome/browser/prefs/proxy_config_dictionary_unittest.cc +++ b/chrome/browser/prefs/proxy_config_dictionary_unittest.cc @@ -43,7 +43,7 @@ TEST(ProxyConfigDictionaryTest, CreateAutoDetect) { TEST(ProxyConfigDictionaryTest, CreatePacScript) { scoped_ptr<DictionaryValue> dict_value( - ProxyConfigDictionary::CreatePacScript("pac")); + ProxyConfigDictionary::CreatePacScript("pac", false)); ProxyConfigDictionary dict(dict_value.get()); ProxyConfigHolder h; diff --git a/chrome/common/automation_constants.cc b/chrome/common/automation_constants.cc index 1956ab5..f380088 100644 --- a/chrome/common/automation_constants.cc +++ b/chrome/common/automation_constants.cc @@ -11,6 +11,7 @@ namespace automation { const char kJSONProxyAutoconfig[] = "proxy.autoconfig"; const char kJSONProxyNoProxy[] = "proxy.no_proxy"; const char kJSONProxyPacUrl[] = "proxy.pac_url"; +const char kJSONProxyPacMandatory[] = "proxy.pac_mandatory"; const char kJSONProxyBypassList[] = "proxy.bypass_list"; const char kJSONProxyServer[] = "proxy.server"; diff --git a/chrome/common/automation_constants.h b/chrome/common/automation_constants.h index ed7f2d2..e1f1d63 100644 --- a/chrome/common/automation_constants.h +++ b/chrome/common/automation_constants.h @@ -14,6 +14,7 @@ namespace automation { extern const char kJSONProxyAutoconfig[]; extern const char kJSONProxyNoProxy[]; extern const char kJSONProxyPacUrl[]; +extern const char kJSONProxyPacMandatory[]; extern const char kJSONProxyBypassList[]; extern const char kJSONProxyServer[]; diff --git a/chrome/common/extensions/api/extension_api.json b/chrome/common/extensions/api/extension_api.json index 989d82d..8993dcc 100644 --- a/chrome/common/extensions/api/extension_api.json +++ b/chrome/common/extensions/api/extension_api.json @@ -4000,7 +4000,8 @@ "description": "An object holding proxy auto-config information. Exactly one of the fields should be non-empty.", "properties": { "url": {"type": "string", "optional": true, "description": "URL of the PAC file to be used."}, - "data": {"type": "string", "optional": true, "description": "A PAC script."} + "data": {"type": "string", "optional": true, "description": "A PAC script."}, + "mandatory": {"type": "boolean", "optional": true, "description": "If true, an invalid PAC script will prevent the network stack from falling back to direct connections. Defaults to false."} } }, { diff --git a/chrome/common/extensions/docs/examples/extensions/proxy_configuration.zip b/chrome/common/extensions/docs/examples/extensions/proxy_configuration.zip Binary files differindex 5b7cb0a..fa7b74b 100644 --- a/chrome/common/extensions/docs/examples/extensions/proxy_configuration.zip +++ b/chrome/common/extensions/docs/examples/extensions/proxy_configuration.zip diff --git a/chrome/common/extensions/docs/examples/extensions/proxy_configuration/proxy_form_controller.js b/chrome/common/extensions/docs/examples/extensions/proxy_configuration/proxy_form_controller.js index 6b4fc09..796d7b0 100644 --- a/chrome/common/extensions/docs/examples/extensions/proxy_configuration/proxy_form_controller.js +++ b/chrome/common/extensions/docs/examples/extensions/proxy_configuration/proxy_form_controller.js @@ -590,9 +590,11 @@ ProxyFormController.prototype = { var pacScriptURL = this.pacURL; var pacManual = this.manualPac; if (pacScriptURL) - return {mode: 'pac_script', pacScript: {url: pacScriptURL}}; + return {mode: 'pac_script', + pacScript: {url: pacScriptURL, mandatory: true}}; else if (pacManual) - return {mode: 'pac_script', pacScript: {data: pacManual}}; + return {mode: 'pac_script', + pacScript: {data: pacManual, mandatory: true}}; else return {mode: 'auto_detect'}; case ProxyFormController.ProxyTypes.FIXED: diff --git a/chrome/common/extensions/docs/experimental.proxy.html b/chrome/common/extensions/docs/experimental.proxy.html index 44cd5fe..4010576 100644 --- a/chrome/common/extensions/docs/experimental.proxy.html +++ b/chrome/common/extensions/docs/experimental.proxy.html @@ -2042,6 +2042,74 @@ element. </dd> </div> + </div><div> + <div> + <dt> + <var>mandatory</var> + <em> + + <!-- TYPE --> + <div style="display:inline"> + ( + <span class="optional">optional</span> + <span class="enum" style="display: none; ">enumerated</span> + <span id="typeTemplate"> + <span style="display: none; "> + <a> Type</a> + </span> + <span> + <span style="display: none; "> + array of <span><span></span></span> + </span> + <span>boolean</span> + <span style="display: none; "></span> + </span> + </span> + ) + </div> + + </em> + </dt> + <dd class="todo" style="display: none; "> + Undocumented. + </dd> + <dd>If true, an invalid PAC script will prevent the network stack from falling back to direct connections. Defaults to false.</dd> + <dd style="display: none; "> + This parameter was added in version + <b><span></span></b>. + You must omit this parameter in earlier versions, + and you may omit it in any version. If you require this + parameter, the manifest key + <a href="manifest.html#minimum_chrome_version">minimum_chrome_version</a> + can ensure that your extension won't be run in an earlier browser version. + </dd> + + <!-- OBJECT PROPERTIES --> + <dd style="display: none; "> + <dl> + <div> + <div> + </div> + </div> + </dl> + </dd> + + <!-- OBJECT METHODS --> + <dd style="display: none; "> + <div></div> + </dd> + + <!-- OBJECT EVENT FIELDS --> + <dd style="display: none; "> + <div></div> + </dd> + + <!-- FUNCTION PARAMETERS --> + <dd style="display: none; "> + <div></div> + </dd> + + </div> </div> </dl> </dd> diff --git a/chrome/common/extensions/docs/samples.json b/chrome/common/extensions/docs/samples.json index 56efe9a..66b4bba 100644 --- a/chrome/common/extensions/docs/samples.json +++ b/chrome/common/extensions/docs/samples.json @@ -1530,7 +1530,7 @@ "test\/proxy_form_controller_test.js", "test\/unittest.css" ], - "source_hash": "8f6768d78649cc4e69e595e7e43b3f06431c84e0", + "source_hash": "7b3ff4599334eaa9f50aa70940bb5dead970665f", "zip_path": "examples\/extensions\/proxy_configuration.zip" }, { diff --git a/chrome/test/data/extensions/api_test/proxy/pacdata/test.js b/chrome/test/data/extensions/api_test/proxy/pacdata/test.js index e5cb541..deec64d 100644 --- a/chrome/test/data/extensions/api_test/proxy/pacdata/test.js +++ b/chrome/test/data/extensions/api_test/proxy/pacdata/test.js @@ -18,7 +18,8 @@ chrome.test.runTests([ " if (host == 'foobar.com')\n" + " return 'PROXY blackhole:80';\n" + " return 'DIRECT';\n" + - "}" + "}", + mandatory: false }; var config = { mode: "pac_script", diff --git a/net/base/net_error_list.h b/net/base/net_error_list.h index 1147267..9979394 100644 --- a/net/base/net_error_list.h +++ b/net/base/net_error_list.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -180,7 +180,9 @@ NET_ERROR(SSL_WEAK_SERVER_EPHEMERAL_DH_KEY, -129) // of an HTTP proxy. NET_ERROR(PROXY_CONNECTION_FAILED, -130) -// Free: 131 +// A mandatory proxy configuration could not be used. Currently this means +// that a mandatory PAC script could not be fetched, parsed or executed. +NET_ERROR(MANDATORY_PROXY_CONFIGURATION_FAILED, -131) // We detected an ESET product intercepting our HTTPS connections. Since these // products are False Start intolerant, we return this error so that we can diff --git a/net/proxy/proxy_config.cc b/net/proxy/proxy_config.cc index 70e6549..42589a9 100644 --- a/net/proxy/proxy_config.cc +++ b/net/proxy/proxy_config.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -158,12 +158,14 @@ ProxyServer* ProxyConfig::ProxyRules::MapUrlSchemeToProxyNoFallback( return NULL; // No mapping for this scheme. } -ProxyConfig::ProxyConfig() : auto_detect_(false), id_(INVALID_ID) { +ProxyConfig::ProxyConfig() + : auto_detect_(false), pac_mandatory_(false), id_(INVALID_ID) { } ProxyConfig::ProxyConfig(const ProxyConfig& config) : auto_detect_(config.auto_detect_), pac_url_(config.pac_url_), + pac_mandatory_(config.pac_mandatory_), proxy_rules_(config.proxy_rules_), id_(config.id_) { } @@ -174,6 +176,7 @@ ProxyConfig::~ProxyConfig() { ProxyConfig& ProxyConfig::operator=(const ProxyConfig& config) { auto_detect_ = config.auto_detect_; pac_url_ = config.pac_url_; + pac_mandatory_ = config.pac_mandatory_; proxy_rules_ = config.proxy_rules_; id_ = config.id_; return *this; @@ -184,6 +187,7 @@ bool ProxyConfig::Equals(const ProxyConfig& other) const { // have the same settings. return auto_detect_ == other.auto_detect_ && pac_url_ == other.pac_url_ && + pac_mandatory_ == other.pac_mandatory_ && proxy_rules_.Equals(other.proxy_rules()); } @@ -202,8 +206,11 @@ Value* ProxyConfig::ToValue() const { // Output the automatic settings. if (auto_detect_) dict->SetBoolean("auto_detect", auto_detect_); - if (has_pac_url()) + if (has_pac_url()) { dict->SetString("pac_url", pac_url_.possibly_invalid_spec()); + if (pac_mandatory_) + dict->SetBoolean("pac_mandatory", pac_mandatory_); + } // Output the manual settings. if (proxy_rules_.type != ProxyRules::TYPE_NO_RULES) { @@ -246,4 +253,3 @@ Value* ProxyConfig::ToValue() const { } } // namespace net - diff --git a/net/proxy/proxy_config.h b/net/proxy/proxy_config.h index 9012a31..dc0fd71 100644 --- a/net/proxy/proxy_config.h +++ b/net/proxy/proxy_config.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -148,6 +148,14 @@ class ProxyConfig { return pac_url_; } + void set_pac_mandatory(bool enable_pac_mandatory) { + pac_mandatory_ = enable_pac_mandatory; + } + + bool pac_mandatory() const { + return pac_mandatory_; + } + bool has_pac_url() const { return pac_url_.is_valid(); } @@ -175,6 +183,8 @@ class ProxyConfig { static ProxyConfig CreateFromCustomPacURL(const GURL& pac_url) { ProxyConfig config; config.set_pac_url(pac_url); + // By default fall back to direct connection in case PAC script fails. + config.set_pac_mandatory(false); return config; } @@ -185,6 +195,10 @@ class ProxyConfig { // If non-empty, indicates the URL of the proxy auto-config file to use. GURL pac_url_; + // If true, blocks all traffic in case fetching the pac script from |pac_url_| + // fails. Only valid if |pac_url_| is non-empty. + bool pac_mandatory_; + // Manual proxy settings. ProxyRules proxy_rules_; diff --git a/net/proxy/proxy_service.cc b/net/proxy/proxy_service.cc index 75411c3..15ad381 100644 --- a/net/proxy/proxy_service.cc +++ b/net/proxy/proxy_service.cc @@ -562,6 +562,11 @@ int ProxyService::TryToCompleteSynchronously(const GURL& url, DCHECK_NE(config_.id(), ProxyConfig::INVALID_ID); + // If it was impossible to fetch or parse the PAC script, we cannot complete + // the request here and bail out. + if (permanent_error_ != OK) + return permanent_error_; + if (config_.HasAutomaticSettings()) return ERR_IO_PENDING; // Must submit the request to the proxy resolver. @@ -652,11 +657,20 @@ void ProxyService::OnInitProxyResolverComplete(int result) { init_proxy_resolver_.reset(); if (result != OK) { - VLOG(1) << "Failed configuring with PAC script, falling-back to manual " - "proxy servers."; - config_ = fetched_config_; - config_.ClearAutomaticSettings(); + if (fetched_config_.pac_mandatory()) { + VLOG(1) << "Failed configuring with mandatory PAC script, blocking all " + "traffic."; + config_ = fetched_config_; + result = ERR_MANDATORY_PROXY_CONFIGURATION_FAILED; + } else { + VLOG(1) << "Failed configuring with PAC script, falling-back to manual " + "proxy servers."; + config_ = fetched_config_; + config_.ClearAutomaticSettings(); + result = OK; + } } + permanent_error_ = result; config_.set_id(fetched_config_.id()); @@ -733,15 +747,19 @@ int ProxyService::DidFinishResolvingProxy(ProxyInfo* result, make_scoped_refptr(new NetLogIntegerParameter( "net_error", result_code))); - // Fall-back to direct when the proxy resolver fails. This corresponds - // with a javascript runtime error in the PAC script. - // - // This implicit fall-back to direct matches Firefox 3.5 and - // Internet Explorer 8. For more information, see: - // - // http://www.chromium.org/developers/design-documents/proxy-settings-fallback - result->UseDirect(); - result_code = OK; + if (!config_.pac_mandatory()) { + // Fall-back to direct when the proxy resolver fails. This corresponds + // with a javascript runtime error in the PAC script. + // + // This implicit fall-back to direct matches Firefox 3.5 and + // Internet Explorer 8. For more information, see: + // + // http://www.chromium.org/developers/design-documents/proxy-settings-fallback + result->UseDirect(); + result_code = OK; + } else { + result_code = ERR_MANDATORY_PROXY_CONFIGURATION_FAILED; + } } net_log.EndEvent(NetLog::TYPE_PROXY_SERVICE, NULL); @@ -766,6 +784,7 @@ ProxyService::State ProxyService::ResetProxyConfig(bool reset_fetched_config) { DCHECK(CalledOnValidThread()); State previous_state = current_state_; + permanent_error_ = OK; proxy_retry_info_.clear(); init_proxy_resolver_.reset(); SuspendAllPendingRequests(); diff --git a/net/proxy/proxy_service.h b/net/proxy/proxy_service.h index 4838954..f7856e5 100644 --- a/net/proxy/proxy_service.h +++ b/net/proxy/proxy_service.h @@ -330,6 +330,10 @@ class ProxyService : public NetworkChangeNotifier::IPAddressObserver, State current_state_; + // Either OK or an ERR_* value indicating that a permanent error (e.g. + // failed to fetch the PAC script) prevents proxy resolution. + int permanent_error_; + // This is the log where any events generated by |init_proxy_resolver_| are // sent to. NetLog* net_log_; |