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

Unified 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 side-by-side diff with in-line comments
Download patch
« Makefile ('K') | « Makefile ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: get_proxies.cc
diff --git a/get_proxies.cc b/get_proxies.cc
new file mode 100644
index 0000000000000000000000000000000000000000..4a5077e44115cfeb05c75b4f13d8623c59921999
--- /dev/null
+++ b/get_proxies.cc
@@ -0,0 +1,409 @@
+// Copyright (c) 2011 The Chromium OS 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 <deque>
+#include <string>
+
+#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.
+#include <dbus/dbus-glib-lowlevel.h>
+#include <glib.h>
+
+#include "base/basictypes.h"
+#include "base/command_line.h"
+#include "base/json/json_reader.h"
kmixter1 2011/03/24 17:24:34 abc order
Michael Krebs 2011/04/05 01:12:03 Done.
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/string_tokenizer.h"
+#include "base/string_util.h"
+#include "base/values.h"
+#include "chromeos/syslog_logging.h"
+#include "gflags/gflags.h"
+
+
+#pragma GCC diagnostic ignored "-Wstrict-aliasing"
+DEFINE_bool(force_session_proxies, false, "Print list of session proxies");
+DEFINE_bool(force_browser_proxies, false, "Print list of browser proxies");
+DEFINE_bool(quiet, false, "Only print the proxies");
+#pragma GCC diagnostic error "-Wstrict-aliasing"
+
+
+const char kNoProxy[] = "direct://";
+
+// For ShowBrowserProxies()
+const char kLibCrosServiceName[] = "org.chromium.LibCrosService";
+const char kLibCrosServicePath[] = "/org/chromium/LibCrosService";
+const char kLibCrosServiceInterface[] = "org.chromium.LibCrosServiceInterface";
+const char kLibCrosServiceResolveNetworkProxyMethodName[] =
+ "ResolveNetworkProxy";
+const char kLibCrosProxyResolveName[] = "ProxyResolved";
+const char kLibCrosProxyResolveSignalInterface[] =
+ "org.chromium.CrashReporterLibcrosProxyResolvedInterface";
+
+// 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
+const char kSessionManagerService[] = "org.chromium.SessionManager";
+const char kSessionManagerPath[] = "/org/chromium/SessionManager";
+const char kSessionManagerInterface[] = "org.chromium.SessionManagerInterface";
+const char kSessionManagerRetrievePropertyMethod[] = "RetrieveProperty";
+const char kSessionManagerProxySettingsKey[] = "cros.proxy.everywhere";
+
+
+// Number of seconds to wait for browser to send us a signal
+const int kBrowserTimeout = 5;
+
+
+#define TEST_AND_RETURN_FALSE(_x) \
+ do { \
+ bool _success = (_x); \
+ if (!_success) { \
+ LOG(ERROR) << #_x " failed."; \
+ return false; \
+ } \
+ } while (0)
+
+static bool StringHasPrefix(const std::string& str, const std::string& prefix) {
+ if (prefix.size() > str.size())
+ return false;
+ return 0 == str.compare(0, prefix.size(), prefix);
+}
+
+static const char* GetGErrorMessage(const GError* error) {
+ if (!error)
+ return "Unknown error.";
+ return error->message;
+}
+
+
+bool PrinterrAndLog(const char *format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ const gchar *buffer = g_strdup_vprintf(format, ap);
+ va_end(ap);
+ LOG(ERROR) << buffer;
+ if (!FLAGS_quiet)
+ g_printerr("%s\n", buffer);
+ return false;
+}
+
+
+// Copied from src/update_engine/chrome_browser_proxy_resolver.cc
+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
+ std::deque<std::string> ret;
+ // Some of this code taken from
+ // http://src.chromium.org/svn/trunk/src/net/proxy/proxy_server.cc and
+ // http://src.chromium.org/svn/trunk/src/net/proxy/proxy_list.cc
+ StringTokenizer entry_tok(input, ";");
+ while (entry_tok.GetNext()) {
+ std::string token = entry_tok.token();
+ TrimWhitespaceASCII(token, TRIM_ALL, &token);
+
+ // Start by finding the first space (if any).
+ std::string::iterator space;
+ for (space = token.begin(); space != token.end(); ++space) {
+ if (IsAsciiWhitespace(*space)) {
+ break;
+ }
+ }
+
+ std::string scheme = std::string(token.begin(), space);
+ StringToLowerASCII(&scheme);
+ // Chrome uses "socks" to mean socks4 and "proxy" to mean http.
+ if (scheme == "socks")
+ scheme += "4";
+ else if (scheme == "proxy")
+ scheme = "http";
+ else if (scheme != "https" &&
+ scheme != "socks4" &&
+ scheme != "socks5" &&
+ scheme != "direct")
+ continue; // Invalid proxy scheme
+
+ std::string host_and_port = std::string(space, token.end());
+ TrimWhitespaceASCII(host_and_port, TRIM_ALL, &host_and_port);
+ if (scheme != "direct" && host_and_port.empty())
+ continue; // Must supply host/port when non-direct proxy used.
+ ret.push_back(scheme + "://" + host_and_port);
+ }
+ if (ret.empty() || *ret.rbegin() != kNoProxy)
+ ret.push_back(kNoProxy);
+ return ret;
+}
+
+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
+ public:
+ explicit BrowserProxyResolvedSignalWatcher(GMainLoop *main_loop,
+ std::deque<std::string> *proxies)
+ : main_loop_(main_loop), proxies_(proxies) { }
+
+ virtual void OnSignal(DBusMessage *message) {
+ // Get args
+ char *source_url = NULL;
+ char *proxy_list = NULL;
+ char *error = NULL;
+ DBusError arg_error;
+ dbus_error_init(&arg_error);
+ if (!dbus_message_get_args(message, &arg_error,
+ DBUS_TYPE_STRING, &source_url,
+ DBUS_TYPE_STRING, &proxy_list,
+ DBUS_TYPE_STRING, &error,
+ DBUS_TYPE_INVALID)) {
+ PrinterrAndLog("Error reading D-Bus signal");
+ return;
+ }
+ if (!source_url || !proxy_list) {
+ 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.
+ return;
+ }
+
+ const std::deque<std::string> &proxies = ParseProxyString(proxy_list);
+ for (std::deque<std::string>::const_iterator it = proxies.begin();
+ it != proxies.end(); ++it) {
+ LOG(INFO) << "Browser signal add: " << (*it).c_str();
+ proxies_->push_back(*it);
+ }
+
+ g_main_loop_quit(main_loop_);
+ }
+
+ private:
+ GMainLoop *main_loop_;
+ std::deque<std::string> *proxies_;
+};
+
+static gboolean HandleBrowserTimeout(void *data) {
+ GMainLoop *main_loop = reinterpret_cast<GMainLoop *>(data);
+ PrinterrAndLog("Timeout while waiting for browser to resolve proxy");
+ g_main_loop_quit(main_loop);
+ return false; // only call once
+}
+
+static bool ShowBrowserProxies(const char *url) {
+ GMainLoop *main_loop = g_main_loop_new(NULL, false);
+
+ chromeos::dbus::BusConnection dbus = chromeos::dbus::GetSystemBusConnection();
+ chromeos::dbus::Proxy browser_proxy(dbus,
+ kLibCrosServiceName,
+ kLibCrosServicePath,
+ kLibCrosServiceInterface);
+ if (!browser_proxy.gproxy()) {
+ PrinterrAndLog("Error creating proxy to D-Bus interface '%s'",
+ kLibCrosServiceName);
+ return false;
+ }
+
+ // Watch for a proxy-resolved signal sent to us
+ std::deque<std::string> proxies;
+ BrowserProxyResolvedSignalWatcher proxy_resolver(main_loop, &proxies);
+ proxy_resolver.StartMonitoring(kLibCrosProxyResolveSignalInterface,
+ kLibCrosProxyResolveName);
+
+ // Request the proxies for our URL. The answer is sent to us via a
+ // proxy-resolved signal.
+ GError *gerror = NULL;
+ if (!dbus_g_proxy_call(browser_proxy.gproxy(),
+ kLibCrosServiceResolveNetworkProxyMethodName,
+ &gerror,
+ G_TYPE_STRING, url,
+ G_TYPE_STRING, kLibCrosProxyResolveSignalInterface,
+ G_TYPE_STRING, kLibCrosProxyResolveName,
+ G_TYPE_INVALID, G_TYPE_INVALID)) {
+ PrinterrAndLog("Error performing D-Bus proxy call '%s': %s",
+ kLibCrosServiceResolveNetworkProxyMethodName,
+ GetGErrorMessage(gerror));
+ return false;
+ }
+
+ // Setup a timeout in case the browser doesn't respond with our signal
+ g_timeout_add_seconds(kBrowserTimeout, &HandleBrowserTimeout, main_loop);
+
+ // Loop until we either get the proxy-resolved signal, or until the
+ // timeout is reached.
+ g_main_loop_run(main_loop);
+
+ for (std::deque<std::string>::const_iterator it = proxies.begin();
+ it != proxies.end(); ++it) {
+ if (!FLAGS_quiet)
+ g_print("Browser proxy: ");
+ g_print("%s\n", (*it).c_str());
+ }
+
+ return true;
+}
+
+
+namespace {
+enum ProxyMode {
+ kProxyModeDirect = 0,
+ kProxyModeAutoDetect = 1,
+ kProxyModePACScript = 2,
+ kProxyModeSingle = 3,
+ kProxyModeProxyPerScheme = 4
+};
+} // namespace {}
+
+// Copied from src/update_engine/chrome_proxy_resolver.cc
+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.
+ const char *json_settings,
+ std::deque<std::string> *out_proxies) {
+ base::JSONReader parser;
+
+ out_proxies->clear();
+
+ scoped_ptr<Value> root(
+ parser.JsonToValue(json_settings,
+ true, // check root is obj/arr
+ false)); // false = disallow trailing comma
+ if (!root.get()) {
+ PrinterrAndLog("Unable to parse \"%s\": %s", json_settings,
+ parser.GetErrorMessage().c_str());
+ return false;
+ }
+
+ 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.
+
+ DictionaryValue* root_dict = dynamic_cast<DictionaryValue*>(root.get());
+ TEST_AND_RETURN_FALSE(root_dict);
+ int mode = -1;
+ TEST_AND_RETURN_FALSE(root_dict->GetInteger("mode", &mode));
+
+ // TODO(mkrebs): This ignores any "bypass_rules" setting.
+ switch (mode) {
+ case kProxyModeDirect: {
+ // Do nothing.
+ break;
+ }
+
+ case kProxyModeSingle: {
+ LOG(INFO) << "single proxy mode";
+ std::string proxy_string;
+ if (!root_dict->GetString("single.server", &proxy_string)) {
+ PrinterrAndLog("Unable to find \"single.server\" key in "
+ "session manager proxy message");
+ return false;
+ }
+ if (proxy_string.find("://") == std::string::npos) {
+ // missing protocol, assume http.
+ proxy_string = std::string("http://") + proxy_string;
+ }
+ out_proxies->push_back(proxy_string);
+ LOG(INFO) << "single proxy: " << (*out_proxies)[0];
+ break;
+ }
+
+ case kProxyModeProxyPerScheme: {
+ // Proxy per scheme mode.
+ LOG(INFO) << "proxy per scheme mode";
+
+ // 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.
+ bool url_is_http = !url || StringHasPrefix(url, "http://");
+ if (!url_is_http)
+ TEST_AND_RETURN_FALSE(StringHasPrefix(url, "https://"));
+
+ // Using "proto_*" variables to refer to http or https
+ const std::string proto_path = url_is_http ? "http.server" :
+ "https.server";
+ const std::string socks_path = "socks.server";
+
+ std::string proto_server, socks_server;
+ if (root_dict->GetString(proto_path, &proto_server)) {
+ if (proto_server.find("://") == std::string::npos) {
+ // missing protocol, assume http.
+ proto_server = std::string("http://") + proto_server;
+ }
+ out_proxies->push_back(proto_server);
+ LOG(INFO) << "got http/https server: " << proto_server;
+ }
+ if (root_dict->GetString(socks_path, &socks_server)) {
+ out_proxies->push_back(socks_server);
+ LOG(INFO) << "got socks server: " << proto_server;
+ }
+ break;
+ }
+
+ default: {
+ LOG(INFO) << "unsupported proxy mode: " << mode;
+ break;
+ }
+ }
+
+ // Always add direct proxy.
+ out_proxies->push_back(kNoProxy);
+ return true;
+}
+
+static bool ShowSessionProxies(const char *url) {
+ chromeos::dbus::BusConnection dbus = chromeos::dbus::GetSystemBusConnection();
+ chromeos::dbus::Proxy session_proxy(dbus,
+ kSessionManagerService,
+ kSessionManagerPath,
+ kSessionManagerInterface);
+ CHECK(session_proxy.gproxy());
+
+ // ChromeProxyResolver::GetProxiesForUrl()
+ std::deque<std::string> proxies;
+ // First, query dbus for the currently stored settings
+ // ChromeProxyResolver::GetJsonProxySettings()
+ gchar *json_settings = NULL;
+ GError *gerror = NULL;
+ GArray *sig = NULL;
+ if (!dbus_g_proxy_call(session_proxy.gproxy(),
+ kSessionManagerRetrievePropertyMethod,
+ &gerror,
+ G_TYPE_STRING, kSessionManagerProxySettingsKey,
+ G_TYPE_INVALID,
+ G_TYPE_STRING, &json_settings,
+ DBUS_TYPE_G_UCHAR_ARRAY, &sig,
+ G_TYPE_INVALID)) {
+ PrinterrAndLog("Error retrieving property '%s' via D-Bus proxy call: %s",
+ kSessionManagerProxySettingsKey,
+ GetGErrorMessage(gerror));
+ return false;
+ }
+ g_array_free(sig, false);
+ LOG(INFO) << "Received session manager proxy settings: " << json_settings;
+ GetProxiesForUrlWithSettings(url, json_settings, &proxies);
+ g_free(json_settings);
+
+ for (std::deque<std::string>::const_iterator it = proxies.begin();
+ it != proxies.end(); ++it) {
+ if (!FLAGS_quiet)
+ g_print("Session manager proxy: ");
+ g_print("%s\n", (*it).c_str());
+ }
+ return true;
+}
+
+
+int main(int argc, char *argv[]) {
+ google::ParseCommandLineFlags(&argc, &argv, true);
+ FilePath my_path(argv[0]);
+ file_util::AbsolutePath(&my_path);
+ CommandLine::Init(argc, argv);
+ 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.
+ chromeos::InitLog(chromeos::kLogToSyslog);
+
+ ::g_type_init();
+
+ const char *url = (argc >= 2) ? argv[1] : NULL;
+
+ if (!FLAGS_quiet)
+ 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.
+
+ if (FLAGS_force_browser_proxies || FLAGS_force_session_proxies) {
+ if (FLAGS_force_browser_proxies)
+ ShowBrowserProxies(url);
+ if (FLAGS_force_session_proxies)
+ ShowSessionProxies(url);
+ } else {
+ if (!ShowBrowserProxies(url)) {
+ if (!ShowSessionProxies(url)) {
+ PrinterrAndLog("Error resolving proxies for URL '%s'", url);
+ if (!FLAGS_quiet)
+ g_print("Default proxy: ");
+ g_print("%s\n", kNoProxy);
+ }
+ }
+ }
+
+ return 0;
+}
« Makefile ('K') | « Makefile ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698