blob: 37ccd8cba1c53bdd505dd73f507bf26ffb900957 [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>
Chris Masoned903c3b2011-05-12 15:35:46 -07008#include <base/memory/scoped_ptr.h>
Andrew de los Reyes9cd120d2010-11-18 17:50:03 -08009#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);
Andrew de los Reyese05fc282011-06-02 09:50:08 -070081 if (!bus) {
82 LOG(ERROR) << "Failed to get System Dbus";
83 return NULL;
84 }
Andrew de los Reyes9cd120d2010-11-18 17:50:03 -080085 DBusGProxy* proxy = dbus_->ProxyNewForNameOwner(bus,
86 kSessionManagerService,
87 kSessionManagerPath,
88 kSessionManagerInterface,
89 &error);
90 if (!proxy) {
91 LOG(ERROR) << "Error getting FlimFlam proxy: "
92 << utils::GetGErrorMessage(error);
93 }
94 return proxy;
95}
96
97namespace {
98enum ProxyMode {
99 kProxyModeDirect = 0,
100 kProxyModeAutoDetect,
101 kProxyModePACScript,
102 kProxyModeSingle,
103 kProxyModeProxyPerScheme
104};
105} // namespace {}
106
107bool ChromeProxyResolver::GetProxiesForUrlWithSettings(
108 const string& url,
109 const string& json_settings,
Andrew de los Reyes45168102010-11-22 11:13:50 -0800110 std::deque<std::string>* out_proxies) {
Andrew de los Reyes9cd120d2010-11-18 17:50:03 -0800111 base::JSONReader parser;
112
113 scoped_ptr<Value> root(
114 parser.JsonToValue(json_settings,
115 true, // check root is obj/arr
116 false)); // false = disallow trailing comma
117 if (!root.get()) {
118 LOG(ERROR) << "Unable to parse \"" << json_settings << "\": "
119 << parser.GetErrorMessage();
120 return false;
121 }
122
123 TEST_AND_RETURN_FALSE(root->IsType(Value::TYPE_DICTIONARY));
124
125 DictionaryValue* root_dict = dynamic_cast<DictionaryValue*>(root.get());
126 TEST_AND_RETURN_FALSE(root_dict);
127 int mode = -1;
128 TEST_AND_RETURN_FALSE(root_dict->GetInteger("mode", &mode));
129
130 LOG(INFO) << "proxy mode: " << mode;
131 if (mode != kProxyModeSingle &&
132 mode != kProxyModeProxyPerScheme) {
133 LOG(INFO) << "unsupported proxy scheme";
134 out_proxies->clear();
135 out_proxies->push_back(kNoProxy);
136 return true;
137 }
138 if (mode == kProxyModeSingle) {
139 LOG(INFO) << "single proxy mode";
140 string proxy_string;
141 TEST_AND_RETURN_FALSE(root_dict->GetString("single.server", &proxy_string));
142 if (proxy_string.find("://") == string::npos) {
143 // missing protocol, assume http.
144 proxy_string = string("http://") + proxy_string;
145 }
146 out_proxies->clear();
147 out_proxies->push_back(proxy_string);
148 LOG(INFO) << "single proxy: " << (*out_proxies)[0];
149 out_proxies->push_back(kNoProxy);
150 return true;
151 }
152 // Proxy per scheme mode.
153 LOG(INFO) << "proxy per scheme mode";
154
155 // Find which scheme we are
156 bool url_is_http = utils::StringHasPrefix(url, "http://");
157 if (!url_is_http)
158 TEST_AND_RETURN_FALSE(utils::StringHasPrefix(url, "https://"));
159
160 // Using "proto_*" variables to refer to http or https
161 const string proto_path = url_is_http ? "http.server" : "https.server";
162 const string socks_path = "socks.server";
163
164 out_proxies->clear();
165
166 string proto_server, socks_server;
167 if (root_dict->GetString(proto_path, &proto_server)) {
168 if (proto_server.find("://") == string::npos) {
169 // missing protocol, assume http.
170 proto_server = string("http://") + proto_server;
171 }
172 out_proxies->push_back(proto_server);
173 LOG(INFO) << "got http/https server: " << proto_server;
174 }
175 if (root_dict->GetString(socks_path, &socks_server)) {
176 out_proxies->push_back(socks_server);
177 LOG(INFO) << "got socks server: " << proto_server;
178 }
179 out_proxies->push_back(kNoProxy);
180 return true;
181}
182
183bool ChromeProxyResolver::GetProxyType(const std::string& proxy,
184 curl_proxytype* out_type) {
185 if (utils::StringHasPrefix(proxy, "socks5://") ||
186 utils::StringHasPrefix(proxy, "socks://")) {
187 *out_type = CURLPROXY_SOCKS5_HOSTNAME;
188 return true;
189 }
190 if (utils::StringHasPrefix(proxy, "socks4://")) {
191 *out_type = CURLPROXY_SOCKS4A;
192 return true;
193 }
194 if (utils::StringHasPrefix(proxy, "http://") ||
195 utils::StringHasPrefix(proxy, "https://")) {
196 *out_type = CURLPROXY_HTTP;
197 return true;
198 }
199 if (utils::StringHasPrefix(proxy, kNoProxy)) {
200 // known failure case. don't log.
201 return false;
202 }
203 LOG(INFO) << "Unknown proxy type: " << proxy;
204 return false;
205}
206
207} // namespace chromeos_update_engine