extension_proxy_api.cc revision 21d179b334e59e9a3bfcaed4c4430bef1bc5759d
1// Copyright (c) 2010 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 "chrome/browser/extensions/extension_proxy_api.h" 6 7#include "base/string_util.h" 8#include "base/stringprintf.h" 9#include "base/values.h" 10#include "chrome/browser/prefs/proxy_prefs.h" 11#include "chrome/browser/profiles/profile.h" 12#include "chrome/browser/extensions/extension_service.h" 13#include "chrome/common/pref_names.h" 14 15namespace { 16 17// The scheme for which to use a manually specified proxy, not of the proxy URI 18// itself. 19enum { 20 SCHEME_ALL = 0, 21 SCHEME_HTTP, 22 SCHEME_HTTPS, 23 SCHEME_FTP, 24 SCHEME_SOCKS, 25 SCHEME_MAX = SCHEME_SOCKS // Keep this value up to date. 26}; 27 28// The names of the JavaScript properties to extract from the proxy_rules. 29// These must be kept in sync with the SCHEME_* constants. 30const char* field_name[] = { "singleProxy", 31 "proxyForHttp", 32 "proxyForHttps", 33 "proxyForFtp", 34 "socksProxy" }; 35 36// The names of the schemes to be used to build the preference value string 37// for manual proxy settings. These must be kept in sync with the SCHEME_* 38// constants. 39const char* scheme_name[] = { "*error*", 40 "http", 41 "https", 42 "ftp", 43 "socks" }; 44 45} // namespace 46 47COMPILE_ASSERT(SCHEME_MAX == SCHEME_SOCKS, SCHEME_MAX_must_equal_SCHEME_SOCKS); 48COMPILE_ASSERT(arraysize(field_name) == SCHEME_MAX + 1, 49 field_name_array_is_wrong_size); 50COMPILE_ASSERT(arraysize(scheme_name) == SCHEME_MAX + 1, 51 scheme_name_array_is_wrong_size); 52 53bool UseCustomProxySettingsFunction::RunImpl() { 54 DictionaryValue* proxy_config; 55 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &proxy_config)); 56 57 std::string proxy_mode; 58 proxy_config->GetString("mode", &proxy_mode); 59 60 DictionaryValue* pac_dict = NULL; 61 proxy_config->GetDictionary("pacScript", &pac_dict); 62 63 DictionaryValue* proxy_rules = NULL; 64 proxy_config->GetDictionary("rules", &proxy_rules); 65 66 // TODO(battre,gfeher): Make sure all the preferences get always 67 // overwritten. 68 return ApplyMode(proxy_mode) && 69 ApplyPacScript(pac_dict) && 70 ApplyProxyRules(proxy_rules); 71} 72 73bool UseCustomProxySettingsFunction::GetProxyServer( 74 const DictionaryValue* dict, ProxyServer* proxy_server) { 75 dict->GetString("scheme", &proxy_server->scheme); 76 EXTENSION_FUNCTION_VALIDATE(dict->GetString("host", &proxy_server->host)); 77 dict->GetInteger("port", &proxy_server->port); 78 return true; 79} 80 81bool UseCustomProxySettingsFunction::ApplyMode(const std::string& mode) { 82 // We take control of the mode preference even if none was specified, so that 83 // all proxy preferences are controlled by the same extension (if not by a 84 // higher-priority source). 85 bool result = true; 86 ProxyPrefs::ProxyMode mode_enum; 87 if (!ProxyPrefs::StringToProxyMode(mode, &mode_enum)) { 88 mode_enum = ProxyPrefs::MODE_SYSTEM; 89 LOG(WARNING) << "Invalid mode for proxy settings: " << mode; 90 result = false; 91 } 92 ApplyPreference(prefs::kProxyMode, Value::CreateIntegerValue(mode_enum)); 93 return result; 94} 95 96bool UseCustomProxySettingsFunction::ApplyPacScript(DictionaryValue* pac_dict) { 97 std::string pac_url; 98 if (pac_dict) 99 pac_dict->GetString("url", &pac_url); 100 101 // We take control of the PAC preference even if none was specified, so that 102 // all proxy preferences are controlled by the same extension (if not by a 103 // higher-priority source). 104 ApplyPreference(prefs::kProxyPacUrl, Value::CreateStringValue(pac_url)); 105 return true; 106} 107 108bool UseCustomProxySettingsFunction::ApplyProxyRules( 109 DictionaryValue* proxy_rules) { 110 if (!proxy_rules) { 111 ApplyPreference(prefs::kProxyServer, Value::CreateStringValue("")); 112 return true; 113 } 114 115 // Local data into which the parameters will be parsed. has_proxy describes 116 // whether a setting was found for the scheme; proxy_dict holds the 117 // DictionaryValues which in turn contain proxy server descriptions, and 118 // proxy_server holds ProxyServer structs containing those descriptions. 119 bool has_proxy[SCHEME_MAX + 1]; 120 DictionaryValue* proxy_dict[SCHEME_MAX + 1]; 121 ProxyServer proxy_server[SCHEME_MAX + 1]; 122 123 // Looking for all possible proxy types is inefficient if we have a 124 // singleProxy that will supersede per-URL proxies, but it's worth it to keep 125 // the code simple and extensible. 126 for (size_t i = 0; i <= SCHEME_MAX; ++i) { 127 has_proxy[i] = proxy_rules->GetDictionary(field_name[i], &proxy_dict[i]); 128 if (has_proxy[i]) { 129 if (!GetProxyServer(proxy_dict[i], &proxy_server[i])) 130 return false; 131 } 132 } 133 134 // A single proxy supersedes individual HTTP, HTTPS, and FTP proxies. 135 if (has_proxy[SCHEME_ALL]) { 136 proxy_server[SCHEME_HTTP] = proxy_server[SCHEME_ALL]; 137 proxy_server[SCHEME_HTTPS] = proxy_server[SCHEME_ALL]; 138 proxy_server[SCHEME_FTP] = proxy_server[SCHEME_ALL]; 139 has_proxy[SCHEME_HTTP] = true; 140 has_proxy[SCHEME_HTTPS] = true; 141 has_proxy[SCHEME_FTP] = true; 142 has_proxy[SCHEME_ALL] = false; 143 } 144 145 // TODO(pamg): Ensure that if a value is empty, that means "don't use a proxy 146 // for this scheme". 147 148 // Build the proxy preference string. 149 std::string proxy_pref; 150 for (size_t i = 0; i <= SCHEME_MAX; ++i) { 151 if (has_proxy[i]) { 152 // http=foopy:4010;ftp=socks://foopy2:80 153 if (!proxy_pref.empty()) 154 proxy_pref.append(";"); 155 proxy_pref.append(scheme_name[i]); 156 proxy_pref.append("="); 157 proxy_pref.append(proxy_server[i].scheme); 158 proxy_pref.append("://"); 159 proxy_pref.append(proxy_server[i].host); 160 if (proxy_server[i].port != ProxyServer::INVALID_PORT) { 161 proxy_pref.append(":"); 162 proxy_pref.append(base::StringPrintf("%d", proxy_server[i].port)); 163 } 164 } 165 } 166 167 ApplyPreference(prefs::kProxyServer, Value::CreateStringValue(proxy_pref)); 168 return true; 169} 170 171void UseCustomProxySettingsFunction::ApplyPreference(const char* pref_path, 172 Value* pref_value) { 173 profile()->GetExtensionService()->extension_prefs() 174 ->SetExtensionControlledPref(extension_id(), pref_path, pref_value); 175} 176