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 // Implementation of the Chrome Extensions Proxy Settings API.
6
7 #include "chrome/browser/extensions/api/proxy/proxy_api.h"
8
9 #include "base/json/json_writer.h"
10 #include "base/strings/stringprintf.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "base/values.h"
13 #include "chrome/browser/extensions/api/proxy/proxy_api_constants.h"
14 #include "chrome/browser/extensions/api/proxy/proxy_api_helpers.h"
15 #include "chrome/browser/extensions/event_router_forwarder.h"
16 #include "chrome/browser/extensions/extension_service.h"
17 #include "chrome/browser/prefs/proxy_config_dictionary.h"
18 #include "net/base/net_errors.h"
19
20 namespace extensions {
21
22 namespace helpers = proxy_api_helpers;
23 namespace keys = proxy_api_constants;
24
25 // static
GetInstance()26 ProxyEventRouter* ProxyEventRouter::GetInstance() {
27 return Singleton<ProxyEventRouter>::get();
28 }
29
ProxyEventRouter()30 ProxyEventRouter::ProxyEventRouter() {
31 }
32
~ProxyEventRouter()33 ProxyEventRouter::~ProxyEventRouter() {
34 }
35
OnProxyError(EventRouterForwarder * event_router,void * profile,int error_code)36 void ProxyEventRouter::OnProxyError(
37 EventRouterForwarder* event_router,
38 void* profile,
39 int error_code) {
40 scoped_ptr<base::ListValue> args(new base::ListValue());
41 base::DictionaryValue* dict = new base::DictionaryValue();
42 dict->SetBoolean(keys::kProxyEventFatal, true);
43 dict->SetString(keys::kProxyEventError, net::ErrorToString(error_code));
44 dict->SetString(keys::kProxyEventDetails, std::string());
45 args->Append(dict);
46
47 if (profile) {
48 event_router->DispatchEventToRenderers(
49 keys::kProxyEventOnProxyError, args.Pass(), profile, true, GURL());
50 } else {
51 event_router->BroadcastEventToRenderers(
52 keys::kProxyEventOnProxyError, args.Pass(), GURL());
53 }
54 }
55
OnPACScriptError(EventRouterForwarder * event_router,void * profile,int line_number,const base::string16 & error)56 void ProxyEventRouter::OnPACScriptError(
57 EventRouterForwarder* event_router,
58 void* profile,
59 int line_number,
60 const base::string16& error) {
61 scoped_ptr<base::ListValue> args(new base::ListValue());
62 base::DictionaryValue* dict = new base::DictionaryValue();
63 dict->SetBoolean(keys::kProxyEventFatal, false);
64 dict->SetString(keys::kProxyEventError,
65 net::ErrorToString(net::ERR_PAC_SCRIPT_FAILED));
66 std::string error_msg;
67 if (line_number != -1) {
68 base::SStringPrintf(&error_msg,
69 "line: %d: %s",
70 line_number, base::UTF16ToUTF8(error).c_str());
71 } else {
72 error_msg = base::UTF16ToUTF8(error);
73 }
74 dict->SetString(keys::kProxyEventDetails, error_msg);
75 args->Append(dict);
76
77 if (profile) {
78 event_router->DispatchEventToRenderers(
79 keys::kProxyEventOnProxyError, args.Pass(), profile, true, GURL());
80 } else {
81 event_router->BroadcastEventToRenderers(
82 keys::kProxyEventOnProxyError, args.Pass(), GURL());
83 }
84 }
85
ProxyPrefTransformer()86 ProxyPrefTransformer::ProxyPrefTransformer() {
87 }
88
~ProxyPrefTransformer()89 ProxyPrefTransformer::~ProxyPrefTransformer() {
90 }
91
ExtensionToBrowserPref(const base::Value * extension_pref,std::string * error,bool * bad_message)92 base::Value* ProxyPrefTransformer::ExtensionToBrowserPref(
93 const base::Value* extension_pref,
94 std::string* error,
95 bool* bad_message) {
96 // When ExtensionToBrowserPref is called, the format of |extension_pref|
97 // has been verified already by the extension API to match the schema
98 // defined in the extension API JSON.
99 CHECK(extension_pref->IsType(base::Value::TYPE_DICTIONARY));
100 const base::DictionaryValue* config =
101 static_cast<const base::DictionaryValue*>(extension_pref);
102
103 // Extract the various pieces of information passed to
104 // chrome.proxy.settings.set(). Several of these strings will
105 // remain blank no respective values have been passed to set().
106 // If a values has been passed to set but could not be parsed, we bail
107 // out and return NULL.
108 ProxyPrefs::ProxyMode mode_enum;
109 bool pac_mandatory;
110 std::string pac_url;
111 std::string pac_data;
112 std::string proxy_rules_string;
113 std::string bypass_list;
114 if (!helpers::GetProxyModeFromExtensionPref(
115 config, &mode_enum, error, bad_message) ||
116 !helpers::GetPacMandatoryFromExtensionPref(
117 config, &pac_mandatory, error, bad_message) ||
118 !helpers::GetPacUrlFromExtensionPref(
119 config, &pac_url, error, bad_message) ||
120 !helpers::GetPacDataFromExtensionPref(
121 config, &pac_data, error, bad_message) ||
122 !helpers::GetProxyRulesStringFromExtensionPref(
123 config, &proxy_rules_string, error, bad_message) ||
124 !helpers::GetBypassListFromExtensionPref(
125 config, &bypass_list, error, bad_message)) {
126 return NULL;
127 }
128
129 return helpers::CreateProxyConfigDict(
130 mode_enum, pac_mandatory, pac_url, pac_data, proxy_rules_string,
131 bypass_list, error);
132 }
133
BrowserToExtensionPref(const base::Value * browser_pref)134 base::Value* ProxyPrefTransformer::BrowserToExtensionPref(
135 const base::Value* browser_pref) {
136 CHECK(browser_pref->IsType(base::Value::TYPE_DICTIONARY));
137
138 // This is a dictionary wrapper that exposes the proxy configuration stored in
139 // the browser preferences.
140 ProxyConfigDictionary config(
141 static_cast<const base::DictionaryValue*>(browser_pref));
142
143 ProxyPrefs::ProxyMode mode;
144 if (!config.GetMode(&mode)) {
145 LOG(ERROR) << "Cannot determine proxy mode.";
146 return NULL;
147 }
148
149 // Build a new ProxyConfig instance as defined in the extension API.
150 scoped_ptr<base::DictionaryValue> extension_pref(new base::DictionaryValue);
151
152 extension_pref->SetString(keys::kProxyConfigMode,
153 ProxyPrefs::ProxyModeToString(mode));
154
155 switch (mode) {
156 case ProxyPrefs::MODE_DIRECT:
157 case ProxyPrefs::MODE_AUTO_DETECT:
158 case ProxyPrefs::MODE_SYSTEM:
159 // These modes have no further parameters.
160 break;
161 case ProxyPrefs::MODE_PAC_SCRIPT: {
162 // A PAC URL either point to a PAC script or contain a base64 encoded
163 // PAC script. In either case we build a PacScript dictionary as defined
164 // in the extension API.
165 base::DictionaryValue* pac_dict = helpers::CreatePacScriptDict(config);
166 if (!pac_dict)
167 return NULL;
168 extension_pref->Set(keys::kProxyConfigPacScript, pac_dict);
169 break;
170 }
171 case ProxyPrefs::MODE_FIXED_SERVERS: {
172 // Build ProxyRules dictionary according to the extension API.
173 base::DictionaryValue* proxy_rules_dict =
174 helpers::CreateProxyRulesDict(config);
175 if (!proxy_rules_dict)
176 return NULL;
177 extension_pref->Set(keys::kProxyConfigRules, proxy_rules_dict);
178 break;
179 }
180 case ProxyPrefs::kModeCount:
181 NOTREACHED();
182 }
183 return extension_pref.release();
184 }
185
186 } // namespace extensions
187