1// Copyright (c) 2011 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/extension_proxy_api.h"
8
9#include "base/json/json_writer.h"
10#include "base/values.h"
11#include "chrome/browser/extensions/extension_event_router_forwarder.h"
12#include "chrome/browser/extensions/extension_proxy_api_constants.h"
13#include "chrome/browser/extensions/extension_proxy_api_helpers.h"
14#include "chrome/browser/extensions/extension_service.h"
15#include "chrome/browser/prefs/proxy_config_dictionary.h"
16#include "net/base/net_errors.h"
17
18namespace helpers = extension_proxy_api_helpers;
19namespace keys = extension_proxy_api_constants;
20
21// static
22ExtensionProxyEventRouter* ExtensionProxyEventRouter::GetInstance() {
23  return Singleton<ExtensionProxyEventRouter>::get();
24}
25
26ExtensionProxyEventRouter::ExtensionProxyEventRouter() {
27}
28
29ExtensionProxyEventRouter::~ExtensionProxyEventRouter() {
30}
31
32void ExtensionProxyEventRouter::OnProxyError(
33    ExtensionEventRouterForwarder* event_router,
34    ProfileId profile_id,
35    int error_code) {
36  ListValue args;
37  DictionaryValue* dict = new DictionaryValue();
38  dict->SetBoolean(keys::kProxyEventFatal, true);
39  dict->SetString(keys::kProxyEventError, net::ErrorToString(error_code));
40  dict->SetString(keys::kProxyEventDetails, "");
41  args.Append(dict);
42
43  std::string json_args;
44  base::JSONWriter::Write(&args, false, &json_args);
45
46  if (profile_id != Profile::kInvalidProfileId) {
47    event_router->DispatchEventToRenderers(
48        keys::kProxyEventOnProxyError, json_args, profile_id, true, GURL());
49  } else {
50    event_router->BroadcastEventToRenderers(
51        keys::kProxyEventOnProxyError, json_args, GURL());
52  }
53}
54
55ProxyPrefTransformer::ProxyPrefTransformer() {
56}
57
58ProxyPrefTransformer::~ProxyPrefTransformer() {
59}
60
61Value* ProxyPrefTransformer::ExtensionToBrowserPref(const Value* extension_pref,
62                                                    std::string* error) {
63  // When ExtensionToBrowserPref is called, the format of |extension_pref|
64  // has been verified already by the extension API to match the schema
65  // defined in chrome/common/extensions/api/extension_api.json.
66  CHECK(extension_pref->IsType(Value::TYPE_DICTIONARY));
67  const DictionaryValue* config =
68      static_cast<const DictionaryValue*>(extension_pref);
69
70  // Extract the various pieces of information passed to
71  // chrome.experimental.proxy.settings.set(). Several of these strings will
72  // remain blank no respective values have been passed to set().
73  // If a values has been passed to set but could not be parsed, we bail
74  // out and return NULL.
75  ProxyPrefs::ProxyMode mode_enum;
76  std::string pac_url;
77  std::string pac_data;
78  std::string proxy_rules_string;
79  std::string bypass_list;
80  if (!helpers::GetProxyModeFromExtensionPref(config, &mode_enum, error) ||
81      !helpers::GetPacUrlFromExtensionPref(config, &pac_url, error) ||
82      !helpers::GetPacDataFromExtensionPref(config, &pac_data, error) ||
83      !helpers::GetProxyRulesStringFromExtensionPref(
84          config, &proxy_rules_string, error) ||
85      !helpers::GetBypassListFromExtensionPref(config, &bypass_list, error)) {
86    return NULL;
87  }
88
89  return helpers::CreateProxyConfigDict(
90      mode_enum, pac_url, pac_data, proxy_rules_string, bypass_list, error);
91}
92
93Value* ProxyPrefTransformer::BrowserToExtensionPref(const Value* browser_pref) {
94  CHECK(browser_pref->IsType(Value::TYPE_DICTIONARY));
95
96  // This is a dictionary wrapper that exposes the proxy configuration stored in
97  // the browser preferences.
98  ProxyConfigDictionary config(
99      static_cast<const DictionaryValue*>(browser_pref));
100
101  ProxyPrefs::ProxyMode mode;
102  if (!config.GetMode(&mode)) {
103    LOG(ERROR) << "Cannot determine proxy mode.";
104    return NULL;
105  }
106
107  // Build a new ProxyConfig instance as defined in the extension API.
108  scoped_ptr<DictionaryValue> extension_pref(new DictionaryValue);
109
110  extension_pref->SetString(keys::kProxyConfigMode,
111                            ProxyPrefs::ProxyModeToString(mode));
112
113  switch (mode) {
114    case ProxyPrefs::MODE_DIRECT:
115    case ProxyPrefs::MODE_AUTO_DETECT:
116    case ProxyPrefs::MODE_SYSTEM:
117      // These modes have no further parameters.
118      break;
119    case ProxyPrefs::MODE_PAC_SCRIPT: {
120      // A PAC URL either point to a PAC script or contain a base64 encoded
121      // PAC script. In either case we build a PacScript dictionary as defined
122      // in the extension API.
123      DictionaryValue* pac_dict = helpers::CreatePacScriptDict(config);
124      if (!pac_dict)
125        return NULL;
126      extension_pref->Set(keys::kProxyConfigPacScript, pac_dict);
127      break;
128    }
129    case ProxyPrefs::MODE_FIXED_SERVERS: {
130      // Build ProxyRules dictionary according to the extension API.
131      DictionaryValue* proxy_rules_dict = helpers::CreateProxyRulesDict(config);
132      if (!proxy_rules_dict)
133        return NULL;
134      extension_pref->Set(keys::kProxyConfigRules, proxy_rules_dict);
135      break;
136    }
137    case ProxyPrefs::kModeCount:
138      NOTREACHED();
139  }
140  return extension_pref.release();
141}
142