172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen// Use of this source code is governed by a BSD-style license that can be
3bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen// found in the LICENSE file.
4bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
5ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Implementation of the Chrome Extensions Proxy Settings API.
6ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
7bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#include "chrome/browser/extensions/extension_proxy_api.h"
8bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
9dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "base/json/json_writer.h"
10bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#include "base/values.h"
11dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "chrome/browser/extensions/extension_event_router_forwarder.h"
12ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/extensions/extension_proxy_api_constants.h"
13ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/extensions/extension_proxy_api_helpers.h"
1421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/extensions/extension_service.h"
15ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/prefs/proxy_config_dictionary.h"
16dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "net/base/net_errors.h"
17dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
18ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsennamespace helpers = extension_proxy_api_helpers;
19ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsennamespace keys = extension_proxy_api_constants;
20dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
21dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// static
22dc0f95d653279beabeb9817299e2902918ba123eKristian MonsenExtensionProxyEventRouter* ExtensionProxyEventRouter::GetInstance() {
23dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  return Singleton<ExtensionProxyEventRouter>::get();
24dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
25dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
26dc0f95d653279beabeb9817299e2902918ba123eKristian MonsenExtensionProxyEventRouter::ExtensionProxyEventRouter() {
27dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
28dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
29dc0f95d653279beabeb9817299e2902918ba123eKristian MonsenExtensionProxyEventRouter::~ExtensionProxyEventRouter() {
30dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
31dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
32dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid ExtensionProxyEventRouter::OnProxyError(
33dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    ExtensionEventRouterForwarder* event_router,
34dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    ProfileId profile_id,
35dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    int error_code) {
36dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  ListValue args;
37dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DictionaryValue* dict = new DictionaryValue();
38ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  dict->SetBoolean(keys::kProxyEventFatal, true);
39ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  dict->SetString(keys::kProxyEventError, net::ErrorToString(error_code));
40ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  dict->SetString(keys::kProxyEventDetails, "");
41dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  args.Append(dict);
42dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
43dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  std::string json_args;
44dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  base::JSONWriter::Write(&args, false, &json_args);
45dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
46dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (profile_id != Profile::kInvalidProfileId) {
47dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    event_router->DispatchEventToRenderers(
48ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        keys::kProxyEventOnProxyError, json_args, profile_id, true, GURL());
49dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  } else {
50dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    event_router->BroadcastEventToRenderers(
51ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        keys::kProxyEventOnProxyError, json_args, GURL());
52dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
5372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
5472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
55ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenProxyPrefTransformer::ProxyPrefTransformer() {
56dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
57dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
58ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenProxyPrefTransformer::~ProxyPrefTransformer() {
5972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
6072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
61ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenValue* ProxyPrefTransformer::ExtensionToBrowserPref(const Value* extension_pref,
62ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                                    std::string* error) {
63ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // When ExtensionToBrowserPref is called, the format of |extension_pref|
64ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // has been verified already by the extension API to match the schema
65ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // defined in chrome/common/extensions/api/extension_api.json.
66ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  CHECK(extension_pref->IsType(Value::TYPE_DICTIONARY));
67ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  const DictionaryValue* config =
68ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      static_cast<const DictionaryValue*>(extension_pref);
6972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
70ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Extract the various pieces of information passed to
71ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // chrome.experimental.proxy.settings.set(). Several of these strings will
72ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // remain blank no respective values have been passed to set().
73ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // If a values has been passed to set but could not be parsed, we bail
74ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // out and return NULL.
7572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  ProxyPrefs::ProxyMode mode_enum;
76ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::string pac_url;
77ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::string pac_data;
7872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  std::string proxy_rules_string;
7972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  std::string bypass_list;
80ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!helpers::GetProxyModeFromExtensionPref(config, &mode_enum, error) ||
81ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      !helpers::GetPacUrlFromExtensionPref(config, &pac_url, error) ||
82ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      !helpers::GetPacDataFromExtensionPref(config, &pac_data, error) ||
83ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      !helpers::GetProxyRulesStringFromExtensionPref(
84ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          config, &proxy_rules_string, error) ||
85ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      !helpers::GetBypassListFromExtensionPref(config, &bypass_list, error)) {
86ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return NULL;
8772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
8872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
89ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return helpers::CreateProxyConfigDict(
90ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      mode_enum, pac_url, pac_data, proxy_rules_string, bypass_list, error);
9172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
9272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
93ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenValue* ProxyPrefTransformer::BrowserToExtensionPref(const Value* browser_pref) {
94ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  CHECK(browser_pref->IsType(Value::TYPE_DICTIONARY));
9572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
96ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // This is a dictionary wrapper that exposes the proxy configuration stored in
97ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // the browser preferences.
98ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ProxyConfigDictionary config(
99ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      static_cast<const DictionaryValue*>(browser_pref));
10072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
10172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  ProxyPrefs::ProxyMode mode;
102ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!config.GetMode(&mode)) {
10372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    LOG(ERROR) << "Cannot determine proxy mode.";
104ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return NULL;
10572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
106ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
107ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Build a new ProxyConfig instance as defined in the extension API.
108ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  scoped_ptr<DictionaryValue> extension_pref(new DictionaryValue);
109ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
110ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  extension_pref->SetString(keys::kProxyConfigMode,
111ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                            ProxyPrefs::ProxyModeToString(mode));
11272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
11372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  switch (mode) {
11472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    case ProxyPrefs::MODE_DIRECT:
11572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    case ProxyPrefs::MODE_AUTO_DETECT:
11672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    case ProxyPrefs::MODE_SYSTEM:
11772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      // These modes have no further parameters.
11872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      break;
11972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    case ProxyPrefs::MODE_PAC_SCRIPT: {
120ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // A PAC URL either point to a PAC script or contain a base64 encoded
121ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // PAC script. In either case we build a PacScript dictionary as defined
122ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // in the extension API.
123ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      DictionaryValue* pac_dict = helpers::CreatePacScriptDict(config);
124ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (!pac_dict)
125ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        return NULL;
126ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      extension_pref->Set(keys::kProxyConfigPacScript, pac_dict);
12772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      break;
12872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    }
12972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    case ProxyPrefs::MODE_FIXED_SERVERS: {
130ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // Build ProxyRules dictionary according to the extension API.
131ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      DictionaryValue* proxy_rules_dict = helpers::CreateProxyRulesDict(config);
132ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (!proxy_rules_dict)
133ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        return NULL;
134ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      extension_pref->Set(keys::kProxyConfigRules, proxy_rules_dict);
13572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      break;
13672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    }
13772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    case ProxyPrefs::kModeCount:
13872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      NOTREACHED();
13972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
140ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return extension_pref.release();
141bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen}
142