blob: 1deab113a2484196892637a16b0117112e56daa6 [file] [log] [blame]
Andrew de los Reyes9cd120d2010-11-18 17:50:03 -08001// Copyright (c) 2010 The Chromium OS 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 "update_engine/chrome_proxy_resolver.h"
6
7#include <base/json/json_reader.h>
8#include <base/scoped_ptr.h>
9#include <base/values.h>
10
11#include "update_engine/utils.h"
12
Andrew de los Reyesf3ed8e72011-02-16 10:35:46 -080013using google::protobuf::Closure;
14using google::protobuf::NewCallback;
15using std::deque;
Andrew de los Reyes9cd120d2010-11-18 17:50:03 -080016using std::string;
17using std::vector;
18
19namespace chromeos_update_engine {
20
21const char kSessionManagerService[] = "org.chromium.SessionManager";
22const char kSessionManagerPath[] = "/org/chromium/SessionManager";
23const char kSessionManagerInterface[] = "org.chromium.SessionManagerInterface";
24const char kSessionManagerRetrievePropertyMethod[] =
25 "RetrieveProperty";
26const char kSessionManagerProxySettingsKey[] = "cros.proxy.everywhere";
27
28bool ChromeProxyResolver::GetProxiesForUrl(
29 const std::string& url,
Andrew de los Reyesf3ed8e72011-02-16 10:35:46 -080030 ProxiesResolvedFn callback,
31 void* data) {
32 ChromeProxyResolverClosureArgs args;
33 args.url = url;
34 args.callback = callback;
35 args.data = data;
36 Closure* closure = NewCallback(this,
37 &ChromeProxyResolver::GetProxiesForUrlCallback,
38 args);
39 g_idle_add(utils::GlibRunClosure, closure);
40 return true;
41}
42
43void ChromeProxyResolver::GetProxiesForUrlCallback(
44 ChromeProxyResolverClosureArgs args) {
45 deque<string> proxies;
Andrew de los Reyes9cd120d2010-11-18 17:50:03 -080046 // First, query dbus for the currently stored settings
47 DBusGProxy* proxy = DbusProxy();
Andrew de los Reyesf3ed8e72011-02-16 10:35:46 -080048 if (proxy) {
49 string json_settings;
50 if (GetJsonProxySettings(proxy, &json_settings)) {
51 LOG(INFO) << "got settings:" << json_settings;
52 GetProxiesForUrlWithSettings(args.url, json_settings, &proxies);
53 }
54 }
55 (*args.callback)(proxies, args.data);
Andrew de los Reyes9cd120d2010-11-18 17:50:03 -080056}
57
58bool ChromeProxyResolver::GetJsonProxySettings(DBusGProxy* proxy,
59 std::string* out_json) {
60 gchar* value = NULL;
61 GArray* sig = NULL;
62 GError* error = NULL;
63 TEST_AND_RETURN_FALSE(
64 dbus_->ProxyCall(proxy,
65 kSessionManagerRetrievePropertyMethod,
66 &error,
67 G_TYPE_STRING, kSessionManagerProxySettingsKey,
68 G_TYPE_INVALID,
69 G_TYPE_STRING, &value,
70 DBUS_TYPE_G_UCHAR_ARRAY, &sig,
71 G_TYPE_INVALID));
72 g_array_free(sig, false);
73 out_json->assign(value);
74 g_free(value);
75 return true;
76}
77
78DBusGProxy* ChromeProxyResolver::DbusProxy() {
79 GError* error = NULL;
80 DBusGConnection* bus = dbus_->BusGet(DBUS_BUS_SYSTEM, &error);
81 TEST_AND_RETURN_FALSE(bus);
82 DBusGProxy* proxy = dbus_->ProxyNewForNameOwner(bus,
83 kSessionManagerService,
84 kSessionManagerPath,
85 kSessionManagerInterface,
86 &error);
87 if (!proxy) {
88 LOG(ERROR) << "Error getting FlimFlam proxy: "
89 << utils::GetGErrorMessage(error);
90 }
91 return proxy;
92}
93
94namespace {
95enum ProxyMode {
96 kProxyModeDirect = 0,
97 kProxyModeAutoDetect,
98 kProxyModePACScript,
99 kProxyModeSingle,
100 kProxyModeProxyPerScheme
101};
102} // namespace {}
103
104bool ChromeProxyResolver::GetProxiesForUrlWithSettings(
105 const string& url,
106 const string& json_settings,
Andrew de los Reyes45168102010-11-22 11:13:50 -0800107 std::deque<std::string>* out_proxies) {
Andrew de los Reyes9cd120d2010-11-18 17:50:03 -0800108 base::JSONReader parser;
109
110 scoped_ptr<Value> root(
111 parser.JsonToValue(json_settings,
112 true, // check root is obj/arr
113 false)); // false = disallow trailing comma
114 if (!root.get()) {
115 LOG(ERROR) << "Unable to parse \"" << json_settings << "\": "
116 << parser.GetErrorMessage();
117 return false;
118 }
119
120 TEST_AND_RETURN_FALSE(root->IsType(Value::TYPE_DICTIONARY));
121
122 DictionaryValue* root_dict = dynamic_cast<DictionaryValue*>(root.get());
123 TEST_AND_RETURN_FALSE(root_dict);
124 int mode = -1;
125 TEST_AND_RETURN_FALSE(root_dict->GetInteger("mode", &mode));
126
127 LOG(INFO) << "proxy mode: " << mode;
128 if (mode != kProxyModeSingle &&
129 mode != kProxyModeProxyPerScheme) {
130 LOG(INFO) << "unsupported proxy scheme";
131 out_proxies->clear();
132 out_proxies->push_back(kNoProxy);
133 return true;
134 }
135 if (mode == kProxyModeSingle) {
136 LOG(INFO) << "single proxy mode";
137 string proxy_string;
138 TEST_AND_RETURN_FALSE(root_dict->GetString("single.server", &proxy_string));
139 if (proxy_string.find("://") == string::npos) {
140 // missing protocol, assume http.
141 proxy_string = string("http://") + proxy_string;
142 }
143 out_proxies->clear();
144 out_proxies->push_back(proxy_string);
145 LOG(INFO) << "single proxy: " << (*out_proxies)[0];
146 out_proxies->push_back(kNoProxy);
147 return true;
148 }
149 // Proxy per scheme mode.
150 LOG(INFO) << "proxy per scheme mode";
151
152 // Find which scheme we are
153 bool url_is_http = utils::StringHasPrefix(url, "http://");
154 if (!url_is_http)
155 TEST_AND_RETURN_FALSE(utils::StringHasPrefix(url, "https://"));
156
157 // Using "proto_*" variables to refer to http or https
158 const string proto_path = url_is_http ? "http.server" : "https.server";
159 const string socks_path = "socks.server";
160
161 out_proxies->clear();
162
163 string proto_server, socks_server;
164 if (root_dict->GetString(proto_path, &proto_server)) {
165 if (proto_server.find("://") == string::npos) {
166 // missing protocol, assume http.
167 proto_server = string("http://") + proto_server;
168 }
169 out_proxies->push_back(proto_server);
170 LOG(INFO) << "got http/https server: " << proto_server;
171 }
172 if (root_dict->GetString(socks_path, &socks_server)) {
173 out_proxies->push_back(socks_server);
174 LOG(INFO) << "got socks server: " << proto_server;
175 }
176 out_proxies->push_back(kNoProxy);
177 return true;
178}
179
180bool ChromeProxyResolver::GetProxyType(const std::string& proxy,
181 curl_proxytype* out_type) {
182 if (utils::StringHasPrefix(proxy, "socks5://") ||
183 utils::StringHasPrefix(proxy, "socks://")) {
184 *out_type = CURLPROXY_SOCKS5_HOSTNAME;
185 return true;
186 }
187 if (utils::StringHasPrefix(proxy, "socks4://")) {
188 *out_type = CURLPROXY_SOCKS4A;
189 return true;
190 }
191 if (utils::StringHasPrefix(proxy, "http://") ||
192 utils::StringHasPrefix(proxy, "https://")) {
193 *out_type = CURLPROXY_HTTP;
194 return true;
195 }
196 if (utils::StringHasPrefix(proxy, kNoProxy)) {
197 // known failure case. don't log.
198 return false;
199 }
200 LOG(INFO) << "Unknown proxy type: " << proxy;
201 return false;
202}
203
204} // namespace chromeos_update_engine