Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(355)

Side by Side Diff: get_proxies.cc

Issue 6730021: crash-reporter: Create a list_proxies command (Closed) Base URL: ssh://git@gitrw.chromium.org:9222/crash-reporter.git@master
Patch Set: Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« Makefile ('K') | « Makefile ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2011 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 <deque>
6 #include <string>
7
8 #include <chromeos/dbus/dbus.h>
kmixter1 2011/03/24 17:24:34 existing style is to put this in ""s with the othe
Michael Krebs 2011/04/05 01:12:03 Done.
9 #include <dbus/dbus-glib-lowlevel.h>
10 #include <glib.h>
11
12 #include "base/basictypes.h"
13 #include "base/command_line.h"
14 #include "base/json/json_reader.h"
kmixter1 2011/03/24 17:24:34 abc order
Michael Krebs 2011/04/05 01:12:03 Done.
15 #include "base/file_util.h"
16 #include "base/logging.h"
17 #include "base/string_tokenizer.h"
18 #include "base/string_util.h"
19 #include "base/values.h"
20 #include "chromeos/syslog_logging.h"
21 #include "gflags/gflags.h"
22
23
24 #pragma GCC diagnostic ignored "-Wstrict-aliasing"
25 DEFINE_bool(force_session_proxies, false, "Print list of session proxies");
26 DEFINE_bool(force_browser_proxies, false, "Print list of browser proxies");
27 DEFINE_bool(quiet, false, "Only print the proxies");
28 #pragma GCC diagnostic error "-Wstrict-aliasing"
29
30
31 const char kNoProxy[] = "direct://";
32
33 // For ShowBrowserProxies()
34 const char kLibCrosServiceName[] = "org.chromium.LibCrosService";
35 const char kLibCrosServicePath[] = "/org/chromium/LibCrosService";
36 const char kLibCrosServiceInterface[] = "org.chromium.LibCrosServiceInterface";
37 const char kLibCrosServiceResolveNetworkProxyMethodName[] =
38 "ResolveNetworkProxy";
39 const char kLibCrosProxyResolveName[] = "ProxyResolved";
40 const char kLibCrosProxyResolveSignalInterface[] =
41 "org.chromium.CrashReporterLibcrosProxyResolvedInterface";
42
43 // For ShowSessionProxies()
kmixter1 2011/03/24 17:24:34 Why do we need to get the proxy setting directly f
Michael Krebs 2011/04/05 01:12:03 This is in case Chrome is unavailable/not respondi
44 const char kSessionManagerService[] = "org.chromium.SessionManager";
45 const char kSessionManagerPath[] = "/org/chromium/SessionManager";
46 const char kSessionManagerInterface[] = "org.chromium.SessionManagerInterface";
47 const char kSessionManagerRetrievePropertyMethod[] = "RetrieveProperty";
48 const char kSessionManagerProxySettingsKey[] = "cros.proxy.everywhere";
49
50
51 // Number of seconds to wait for browser to send us a signal
52 const int kBrowserTimeout = 5;
53
54
55 #define TEST_AND_RETURN_FALSE(_x) \
56 do { \
57 bool _success = (_x); \
58 if (!_success) { \
59 LOG(ERROR) << #_x " failed."; \
60 return false; \
61 } \
62 } while (0)
63
64 static bool StringHasPrefix(const std::string& str, const std::string& prefix) {
65 if (prefix.size() > str.size())
66 return false;
67 return 0 == str.compare(0, prefix.size(), prefix);
68 }
69
70 static const char* GetGErrorMessage(const GError* error) {
71 if (!error)
72 return "Unknown error.";
73 return error->message;
74 }
75
76
77 bool PrinterrAndLog(const char *format, ...) {
78 va_list ap;
79 va_start(ap, format);
80 const gchar *buffer = g_strdup_vprintf(format, ap);
81 va_end(ap);
82 LOG(ERROR) << buffer;
83 if (!FLAGS_quiet)
84 g_printerr("%s\n", buffer);
85 return false;
86 }
87
88
89 // Copied from src/update_engine/chrome_browser_proxy_resolver.cc
90 std::deque<std::string> ParseProxyString(const std::string &input) {
kmixter1 2011/03/24 17:24:34 This should eventually be moved into a library in
Michael Krebs 2011/04/05 01:12:03 Should I do anything with this function for this C
91 std::deque<std::string> ret;
92 // Some of this code taken from
93 // http://src.chromium.org/svn/trunk/src/net/proxy/proxy_server.cc and
94 // http://src.chromium.org/svn/trunk/src/net/proxy/proxy_list.cc
95 StringTokenizer entry_tok(input, ";");
96 while (entry_tok.GetNext()) {
97 std::string token = entry_tok.token();
98 TrimWhitespaceASCII(token, TRIM_ALL, &token);
99
100 // Start by finding the first space (if any).
101 std::string::iterator space;
102 for (space = token.begin(); space != token.end(); ++space) {
103 if (IsAsciiWhitespace(*space)) {
104 break;
105 }
106 }
107
108 std::string scheme = std::string(token.begin(), space);
109 StringToLowerASCII(&scheme);
110 // Chrome uses "socks" to mean socks4 and "proxy" to mean http.
111 if (scheme == "socks")
112 scheme += "4";
113 else if (scheme == "proxy")
114 scheme = "http";
115 else if (scheme != "https" &&
116 scheme != "socks4" &&
117 scheme != "socks5" &&
118 scheme != "direct")
119 continue; // Invalid proxy scheme
120
121 std::string host_and_port = std::string(space, token.end());
122 TrimWhitespaceASCII(host_and_port, TRIM_ALL, &host_and_port);
123 if (scheme != "direct" && host_and_port.empty())
124 continue; // Must supply host/port when non-direct proxy used.
125 ret.push_back(scheme + "://" + host_and_port);
126 }
127 if (ret.empty() || *ret.rbegin() != kNoProxy)
128 ret.push_back(kNoProxy);
129 return ret;
130 }
131
132 class BrowserProxyResolvedSignalWatcher : public chromeos::dbus::SignalWatcher {
kmixter1 2011/03/24 17:24:34 I think I've run into a simpler way to do this wit
Michael Krebs 2011/04/05 01:12:03 I can't find the simpler way to do this. Could yo
133 public:
134 explicit BrowserProxyResolvedSignalWatcher(GMainLoop *main_loop,
135 std::deque<std::string> *proxies)
136 : main_loop_(main_loop), proxies_(proxies) { }
137
138 virtual void OnSignal(DBusMessage *message) {
139 // Get args
140 char *source_url = NULL;
141 char *proxy_list = NULL;
142 char *error = NULL;
143 DBusError arg_error;
144 dbus_error_init(&arg_error);
145 if (!dbus_message_get_args(message, &arg_error,
146 DBUS_TYPE_STRING, &source_url,
147 DBUS_TYPE_STRING, &proxy_list,
148 DBUS_TYPE_STRING, &error,
149 DBUS_TYPE_INVALID)) {
150 PrinterrAndLog("Error reading D-Bus signal");
151 return;
152 }
153 if (!source_url || !proxy_list) {
154 PrinterrAndLog("Error getting url, proxy list from D-Bus signal");
kmixter1 2011/03/24 17:24:34 Why isn't this just LOG(ERROR)?
Michael Krebs 2011/04/05 01:12:03 Done.
155 return;
156 }
157
158 const std::deque<std::string> &proxies = ParseProxyString(proxy_list);
159 for (std::deque<std::string>::const_iterator it = proxies.begin();
160 it != proxies.end(); ++it) {
161 LOG(INFO) << "Browser signal add: " << (*it).c_str();
162 proxies_->push_back(*it);
163 }
164
165 g_main_loop_quit(main_loop_);
166 }
167
168 private:
169 GMainLoop *main_loop_;
170 std::deque<std::string> *proxies_;
171 };
172
173 static gboolean HandleBrowserTimeout(void *data) {
174 GMainLoop *main_loop = reinterpret_cast<GMainLoop *>(data);
175 PrinterrAndLog("Timeout while waiting for browser to resolve proxy");
176 g_main_loop_quit(main_loop);
177 return false; // only call once
178 }
179
180 static bool ShowBrowserProxies(const char *url) {
181 GMainLoop *main_loop = g_main_loop_new(NULL, false);
182
183 chromeos::dbus::BusConnection dbus = chromeos::dbus::GetSystemBusConnection();
184 chromeos::dbus::Proxy browser_proxy(dbus,
185 kLibCrosServiceName,
186 kLibCrosServicePath,
187 kLibCrosServiceInterface);
188 if (!browser_proxy.gproxy()) {
189 PrinterrAndLog("Error creating proxy to D-Bus interface '%s'",
190 kLibCrosServiceName);
191 return false;
192 }
193
194 // Watch for a proxy-resolved signal sent to us
195 std::deque<std::string> proxies;
196 BrowserProxyResolvedSignalWatcher proxy_resolver(main_loop, &proxies);
197 proxy_resolver.StartMonitoring(kLibCrosProxyResolveSignalInterface,
198 kLibCrosProxyResolveName);
199
200 // Request the proxies for our URL. The answer is sent to us via a
201 // proxy-resolved signal.
202 GError *gerror = NULL;
203 if (!dbus_g_proxy_call(browser_proxy.gproxy(),
204 kLibCrosServiceResolveNetworkProxyMethodName,
205 &gerror,
206 G_TYPE_STRING, url,
207 G_TYPE_STRING, kLibCrosProxyResolveSignalInterface,
208 G_TYPE_STRING, kLibCrosProxyResolveName,
209 G_TYPE_INVALID, G_TYPE_INVALID)) {
210 PrinterrAndLog("Error performing D-Bus proxy call '%s': %s",
211 kLibCrosServiceResolveNetworkProxyMethodName,
212 GetGErrorMessage(gerror));
213 return false;
214 }
215
216 // Setup a timeout in case the browser doesn't respond with our signal
217 g_timeout_add_seconds(kBrowserTimeout, &HandleBrowserTimeout, main_loop);
218
219 // Loop until we either get the proxy-resolved signal, or until the
220 // timeout is reached.
221 g_main_loop_run(main_loop);
222
223 for (std::deque<std::string>::const_iterator it = proxies.begin();
224 it != proxies.end(); ++it) {
225 if (!FLAGS_quiet)
226 g_print("Browser proxy: ");
227 g_print("%s\n", (*it).c_str());
228 }
229
230 return true;
231 }
232
233
234 namespace {
235 enum ProxyMode {
236 kProxyModeDirect = 0,
237 kProxyModeAutoDetect = 1,
238 kProxyModePACScript = 2,
239 kProxyModeSingle = 3,
240 kProxyModeProxyPerScheme = 4
241 };
242 } // namespace {}
243
244 // Copied from src/update_engine/chrome_proxy_resolver.cc
245 bool GetProxiesForUrlWithSettings(const char *url,
kmixter1 2011/03/24 17:24:34 Needs docs. What is json_settings besides json?
Michael Krebs 2011/04/05 01:12:03 Done.
246 const char *json_settings,
247 std::deque<std::string> *out_proxies) {
248 base::JSONReader parser;
249
250 out_proxies->clear();
251
252 scoped_ptr<Value> root(
253 parser.JsonToValue(json_settings,
254 true, // check root is obj/arr
255 false)); // false = disallow trailing comma
256 if (!root.get()) {
257 PrinterrAndLog("Unable to parse \"%s\": %s", json_settings,
258 parser.GetErrorMessage().c_str());
259 return false;
260 }
261
262 TEST_AND_RETURN_FALSE(root->IsType(Value::TYPE_DICTIONARY));
kmixter1 2011/03/24 17:24:34 I really don't like macros that have control flow
Michael Krebs 2011/04/05 01:12:03 Done.
263
264 DictionaryValue* root_dict = dynamic_cast<DictionaryValue*>(root.get());
265 TEST_AND_RETURN_FALSE(root_dict);
266 int mode = -1;
267 TEST_AND_RETURN_FALSE(root_dict->GetInteger("mode", &mode));
268
269 // TODO(mkrebs): This ignores any "bypass_rules" setting.
270 switch (mode) {
271 case kProxyModeDirect: {
272 // Do nothing.
273 break;
274 }
275
276 case kProxyModeSingle: {
277 LOG(INFO) << "single proxy mode";
278 std::string proxy_string;
279 if (!root_dict->GetString("single.server", &proxy_string)) {
280 PrinterrAndLog("Unable to find \"single.server\" key in "
281 "session manager proxy message");
282 return false;
283 }
284 if (proxy_string.find("://") == std::string::npos) {
285 // missing protocol, assume http.
286 proxy_string = std::string("http://") + proxy_string;
287 }
288 out_proxies->push_back(proxy_string);
289 LOG(INFO) << "single proxy: " << (*out_proxies)[0];
290 break;
291 }
292
293 case kProxyModeProxyPerScheme: {
294 // Proxy per scheme mode.
295 LOG(INFO) << "proxy per scheme mode";
296
297 // Find which scheme we are. An undefined URL defaults to "http://".
kmixter1 2011/03/24 17:24:34 This should have been a separate function and an e
Michael Krebs 2011/04/05 01:12:03 Done.
298 bool url_is_http = !url || StringHasPrefix(url, "http://");
299 if (!url_is_http)
300 TEST_AND_RETURN_FALSE(StringHasPrefix(url, "https://"));
301
302 // Using "proto_*" variables to refer to http or https
303 const std::string proto_path = url_is_http ? "http.server" :
304 "https.server";
305 const std::string socks_path = "socks.server";
306
307 std::string proto_server, socks_server;
308 if (root_dict->GetString(proto_path, &proto_server)) {
309 if (proto_server.find("://") == std::string::npos) {
310 // missing protocol, assume http.
311 proto_server = std::string("http://") + proto_server;
312 }
313 out_proxies->push_back(proto_server);
314 LOG(INFO) << "got http/https server: " << proto_server;
315 }
316 if (root_dict->GetString(socks_path, &socks_server)) {
317 out_proxies->push_back(socks_server);
318 LOG(INFO) << "got socks server: " << proto_server;
319 }
320 break;
321 }
322
323 default: {
324 LOG(INFO) << "unsupported proxy mode: " << mode;
325 break;
326 }
327 }
328
329 // Always add direct proxy.
330 out_proxies->push_back(kNoProxy);
331 return true;
332 }
333
334 static bool ShowSessionProxies(const char *url) {
335 chromeos::dbus::BusConnection dbus = chromeos::dbus::GetSystemBusConnection();
336 chromeos::dbus::Proxy session_proxy(dbus,
337 kSessionManagerService,
338 kSessionManagerPath,
339 kSessionManagerInterface);
340 CHECK(session_proxy.gproxy());
341
342 // ChromeProxyResolver::GetProxiesForUrl()
343 std::deque<std::string> proxies;
344 // First, query dbus for the currently stored settings
345 // ChromeProxyResolver::GetJsonProxySettings()
346 gchar *json_settings = NULL;
347 GError *gerror = NULL;
348 GArray *sig = NULL;
349 if (!dbus_g_proxy_call(session_proxy.gproxy(),
350 kSessionManagerRetrievePropertyMethod,
351 &gerror,
352 G_TYPE_STRING, kSessionManagerProxySettingsKey,
353 G_TYPE_INVALID,
354 G_TYPE_STRING, &json_settings,
355 DBUS_TYPE_G_UCHAR_ARRAY, &sig,
356 G_TYPE_INVALID)) {
357 PrinterrAndLog("Error retrieving property '%s' via D-Bus proxy call: %s",
358 kSessionManagerProxySettingsKey,
359 GetGErrorMessage(gerror));
360 return false;
361 }
362 g_array_free(sig, false);
363 LOG(INFO) << "Received session manager proxy settings: " << json_settings;
364 GetProxiesForUrlWithSettings(url, json_settings, &proxies);
365 g_free(json_settings);
366
367 for (std::deque<std::string>::const_iterator it = proxies.begin();
368 it != proxies.end(); ++it) {
369 if (!FLAGS_quiet)
370 g_print("Session manager proxy: ");
371 g_print("%s\n", (*it).c_str());
372 }
373 return true;
374 }
375
376
377 int main(int argc, char *argv[]) {
378 google::ParseCommandLineFlags(&argc, &argv, true);
379 FilePath my_path(argv[0]);
380 file_util::AbsolutePath(&my_path);
381 CommandLine::Init(argc, argv);
382 chromeos::OpenLog(my_path.BaseName().value().c_str(), true);
kmixter1 2011/03/24 17:24:34 Doing OpenLog may not be necessary (and thus the o
Michael Krebs 2011/04/05 01:12:03 Done.
383 chromeos::InitLog(chromeos::kLogToSyslog);
384
385 ::g_type_init();
386
387 const char *url = (argc >= 2) ? argv[1] : NULL;
388
389 if (!FLAGS_quiet)
390 g_print("Resolving proxies for URL: %s\n", url);
kmixter1 2011/03/24 17:24:34 do you plan to leave this in? If so why not LOG(I
Michael Krebs 2011/04/05 01:12:03 Done.
391
392 if (FLAGS_force_browser_proxies || FLAGS_force_session_proxies) {
393 if (FLAGS_force_browser_proxies)
394 ShowBrowserProxies(url);
395 if (FLAGS_force_session_proxies)
396 ShowSessionProxies(url);
397 } else {
398 if (!ShowBrowserProxies(url)) {
399 if (!ShowSessionProxies(url)) {
400 PrinterrAndLog("Error resolving proxies for URL '%s'", url);
401 if (!FLAGS_quiet)
402 g_print("Default proxy: ");
403 g_print("%s\n", kNoProxy);
404 }
405 }
406 }
407
408 return 0;
409 }
OLDNEW
« Makefile ('K') | « Makefile ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698