summaryrefslogtreecommitdiffstats
path: root/chrome/browser/extensions/extension_proxy_api.cc
blob: 1e9ba78ae986f9e07956c3d7f8fa2c0a2151e44d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
// Copyright (c) 2010 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.

#include "chrome/browser/extensions/extension_proxy_api.h"

#include "base/logging.h"
#include "base/string_util.h"
#include "base/values.h"
#include "chrome/browser/extensions/extension_pref_store.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"

namespace {

// The scheme for which to use the proxy, not of the proxy URI itself.
enum {
  SCHEME_ALL = 0,
  SCHEME_HTTP,
  SCHEME_HTTPS,
  SCHEME_FTP,
  SCHEME_SOCKS,
  SCHEME_MAX = SCHEME_SOCKS  // Keep this value up to date.
};

// The names of the JavaScript properties to extract from the args_.
// These must be kept in sync with the SCHEME_* constants.
const char* field_name[] = { "singleProxy",
                             "proxyForHttp",
                             "proxyForHttps",
                             "proxyForFtp",
                             "socksProxy" };

// The names of the schemes to be used to build the preference value string.
// These must be kept in sync with the SCHEME_* constants.
const char* scheme_name[] = { "*error*",
                              "http",
                              "https",
                              "ftp",
                              "socks" };

}  // namespace

COMPILE_ASSERT(SCHEME_MAX == SCHEME_SOCKS, SCHEME_MAX_must_equal_SCHEME_SOCKS);
COMPILE_ASSERT(arraysize(field_name) == SCHEME_MAX + 1,
               field_name_array_is_wrong_size);
COMPILE_ASSERT(arraysize(scheme_name) == SCHEME_MAX + 1,
               scheme_name_array_is_wrong_size);

bool UseCustomProxySettingsFunction::RunImpl() {
  DictionaryValue* proxy_config;
  EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &proxy_config));

  DictionaryValue* proxy_rules;
  EXTENSION_FUNCTION_VALIDATE(proxy_config->GetDictionary("rules",
      &proxy_rules));

  // Local data into which the parameters will be parsed. has_proxy describes
  // whether a setting was found for the scheme; proxy_dict holds the
  // DictionaryValues which in turn contain proxy server descriptions, and
  // proxy_server holds ProxyServer structs containing those descriptions.
  bool has_proxy[SCHEME_MAX + 1];
  DictionaryValue* proxy_dict[SCHEME_MAX + 1];
  ProxyServer proxy_server[SCHEME_MAX + 1];

  // Looking for all possible proxy types is inefficient if we have a
  // singleProxy that will supersede per-URL proxies, but it's worth it to keep
  // the code simple and extensible.
  for (size_t i = 0; i <= SCHEME_MAX; ++i) {
    has_proxy[i] = proxy_rules->GetDictionary(field_name[i], &proxy_dict[i]);
    if (has_proxy[i]) {
      if (!GetProxyServer(proxy_dict[i], &proxy_server[i]))
        return false;
    }
  }

  // A single proxy supersedes individual HTTP, HTTPS, and FTP proxies.
  if (has_proxy[SCHEME_ALL]) {
    proxy_server[SCHEME_HTTP] = proxy_server[SCHEME_ALL];
    proxy_server[SCHEME_HTTPS] = proxy_server[SCHEME_ALL];
    proxy_server[SCHEME_FTP] = proxy_server[SCHEME_ALL];
    has_proxy[SCHEME_HTTP] = true;
    has_proxy[SCHEME_HTTPS] = true;
    has_proxy[SCHEME_FTP] = true;
    has_proxy[SCHEME_ALL] = false;
  }

  // TODO(pamg): Ensure that if a value is empty, that means "don't use a proxy
  // for this scheme".

  // Build the proxy preference string.
  std::string proxy_pref;
  for (size_t i = 0; i <= SCHEME_MAX; ++i) {
    if (has_proxy[i]) {
      // http=foopy:4010;ftp=socks://foopy2:80
      if (!proxy_pref.empty())
        proxy_pref.append(";");
      proxy_pref.append(scheme_name[i]);
      proxy_pref.append("=");
      proxy_pref.append(proxy_server[i].scheme);
      proxy_pref.append("://");
      proxy_pref.append(proxy_server[i].host);
      if (proxy_server[i].port != ProxyServer::INVALID_PORT) {
        proxy_pref.append(":");
        proxy_pref.append(StringPrintf("%d", proxy_server[i].port));
      }
    }
  }

  ExtensionPrefStore::ExtensionPrefDetails details =
      std::make_pair(GetExtension(),
                     std::make_pair(prefs::kProxyServer,
                                    Value::CreateStringValue(proxy_pref)));

  NotificationService::current()->Notify(
      NotificationType::EXTENSION_PREF_CHANGED,
      Source<Profile>(profile_),
      Details<ExtensionPrefStore::ExtensionPrefDetails>(&details));

  return true;
}

bool UseCustomProxySettingsFunction::GetProxyServer(
    const DictionaryValue* dict, ProxyServer* proxy_server) {
  dict->GetString("scheme", &proxy_server->scheme);
  EXTENSION_FUNCTION_VALIDATE(dict->GetString("host", &proxy_server->host));
  dict->GetInteger("port", &proxy_server->port);
  return true;
}