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