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

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: Fix a compile error. 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
« no previous file with comments | « 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..871038830d7a25814dcfc7219195c9282b2702ba
--- /dev/null
+++ b/get_proxies.cc
@@ -0,0 +1,431 @@
+// 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 <string.h>
+#include <unistd.h>
+
+#include <deque>
+#include <string>
+
+#include <dbus/dbus-glib-lowlevel.h>
+#include <glib.h>
+
+#include "base/command_line.h"
+#include "base/file_util.h"
+#include "base/json/json_reader.h"
+#include "base/string_tokenizer.h"
+#include "base/string_util.h"
+#include "base/values.h"
+#include "chromeos/dbus/dbus.h"
+#include "chromeos/syslog_logging.h"
+#include "gflags/gflags.h"
+
+
+#pragma GCC diagnostic ignored "-Wstrict-aliasing"
+DEFINE_bool(force_browser_proxies, false, "Force printing the list of "
+ "browser proxies");
+DEFINE_bool(force_session_proxies, false, "Force printing the list of "
+ "session proxies");
+DEFINE_bool(quiet, false, "Only print the proxies");
+DEFINE_bool(verbose, false, "Print additional messages even "
+ "when not run from a TTY");
+#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";
kmixter1 2011/04/06 04:28:53 Sort these if there is no specific sequence?
Michael Krebs 2011/04/12 00:53:38 They're in top-down order. You contact the servic
kmixter1 2011/04/12 01:17:41 I'd go for abc order, to simplify adding new const
Michael Krebs 2011/04/13 02:40:24 Done.
+const char kLibCrosServiceResolveNetworkProxyMethodName[] =
+ "ResolveNetworkProxy";
+const char kLibCrosProxyResolveName[] = "ProxyResolved";
+const char kLibCrosProxyResolveSignalInterface[] =
+ "org.chromium.CrashReporterLibcrosProxyResolvedInterface";
+
+// For ShowSessionProxies()
+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;
+
+
+static const char* GetGErrorMessage(const GError* error) {
kmixter1 2011/04/06 04:28:53 consistently use space-star not star-space here an
Michael Krebs 2011/04/12 00:53:38 Done.
+ if (!error)
+ return "Unknown error.";
+ return error->message;
+}
+
+
+// Copied from src/update_engine/chrome_browser_proxy_resolver.cc
kmixter1 2011/04/12 01:17:41 1 line between functions
Michael Krebs 2011/04/13 02:40:24 Done.
+std::deque<std::string> ParseProxyString(const std::string &input) {
+ 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/04/12 01:17:41 Add comment describing purpose of class.
Michael Krebs 2011/04/13 02:40:24 Done.
+ 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)) {
+ LOG(ERROR) << "Error reading D-Bus signal";
+ return;
+ }
+ if (!source_url || !proxy_list) {
+ LOG(ERROR) << "Error getting url, proxy list from D-Bus signal";
+ 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) << "Found proxy via browser signal: " << (*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);
+ LOG(ERROR) << "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();
+ if (!dbus.HasConnection()) {
+ LOG(ERROR) << "Error connecting to system D-Bus";
+ return false;
+ }
+ chromeos::dbus::Proxy browser_proxy(dbus,
+ kLibCrosServiceName,
+ kLibCrosServicePath,
+ kLibCrosServiceInterface);
+ if (!browser_proxy) {
+ LOG(ERROR) << "Error creating D-Bus proxy to interface "
+ << "'" << 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)) {
+ LOG(ERROR) << "Error performing D-Bus proxy call "
+ << "'" << 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) {
+ g_print("%s\n", (*it).c_str());
+ }
+
+ return true;
+}
+
+
+namespace {
+enum ProxyMode {
+ kProxyModeDirect = 0,
+ kProxyModeAutoDetect = 1,
+ kProxyModePACScript = 2,
+ kProxyModeSingle = 3,
+ kProxyModeProxyPerScheme = 4
+};
+} // namespace {}
+
+// Returns the scheme portion of a URL.
+const char *GetUrlScheme(const char *url) {
+ const char *ptr;
+ // An undefined URL or scheme defaults to "http://".
+ if (!url || !(ptr = strstr(url, "://")))
+ return strdup("http");
+ return strndup(url, ptr - url);
+}
+
+const char *GetProtocolPathFromScheme(const char *scheme) {
+ if (!strcasecmp(scheme, "http"))
+ return strdup("http.server");
+ if (!strcasecmp(scheme, "https"))
+ return strdup("https.server");
+ return NULL;
+}
+
+// Given a JSON string from the Session Manager describing the session's
+// proxies, set "out_proxies" to the appropriate proxies for a given "url".
+// Copied from src/update_engine/chrome_proxy_resolver.cc.
+static bool GetProxiesFromJsonSettings(const char *url,
+ const char *settings,
+ std::deque<std::string> *out_proxies) {
+ base::JSONReader parser;
+
+ out_proxies->clear();
+
+ scoped_ptr<Value> root(
+ parser.JsonToValue(settings,
+ true, // check root is obj/arr
+ false)); // false = disallow trailing comma
+ if (!root.get()) {
+ LOG(ERROR) << "Unable to parse JSON: " << parser.GetErrorMessage().c_str();
+ return false;
+ }
+
+ if (!root->IsType(Value::TYPE_DICTIONARY)) {
+ LOG(ERROR) << "Invalid root JSON type";
+ return false;
+ }
+
+ DictionaryValue* root_dict = dynamic_cast<DictionaryValue*>(root.get());
+ if (!root_dict) {
+ LOG(ERROR) << "Expected a DictionaryValue";
+ return false;
+ }
+ int mode = -1;
+ if (!root_dict->GetInteger("mode", &mode)) {
+ LOG(ERROR) << "Error parsing \"mode\" attribute";
+ return false;
+ }
+
+ // TODO(mkrebs): This ignores any "bypass_rules" setting.
kmixter1 2011/04/06 04:28:53 Not sure what is to be done based on this TODO.
Michael Krebs 2011/04/12 00:53:38 Moot now, because I removed the Session Manager pr
+ 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)) {
+ LOG(ERROR) << "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;
+ }
+ LOG(INFO) << "Found proxy via session manager: " << (*out_proxies)[0];
+ out_proxies->push_back(proxy_string);
+ break;
+ }
+
+ case kProxyModeProxyPerScheme: {
+ // Proxy per scheme mode.
+ LOG(INFO) << "proxy per scheme mode";
+
+ // Using "proto_*" variables to refer to http or https.
+ const char *scheme = GetUrlScheme(url);
+ const char *proto_path = GetProtocolPathFromScheme(scheme);
+ free(const_cast<char *>(scheme));
+ if (!proto_path) {
+ LOG(ERROR) << "Unknown scheme '" << scheme
+ << "' for URL '" << url << "'";
+ return false;
+ }
+ const char *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;
+ }
+
+ free(const_cast<char *>(proto_path));
+ 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();
+ if (!dbus.HasConnection()) {
+ LOG(ERROR) << "Error connecting to system D-Bus";
+ return false;
+ }
+ chromeos::dbus::Proxy session_proxy(dbus,
+ kSessionManagerService,
+ kSessionManagerPath,
+ kSessionManagerInterface);
+ if (!session_proxy) {
+ LOG(ERROR) << "Error creating D-Bus proxy to interface "
+ << "'" << kSessionManagerInterface << "'";
+ return false;
+ }
+
+ // First, query dbus for the currently stored settings.
+ 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)) {
+ LOG(ERROR) << "Error retrieving proxy settings via D-Bus proxy call: "
+ << GetGErrorMessage(gerror);
+ return false;
+ }
+ g_array_free(sig, false);
+ LOG(INFO) << "Received session manager proxy settings: " << json_settings;
+
+ std::deque<std::string> proxies;
+ if (!GetProxiesFromJsonSettings(url, json_settings, &proxies))
+ LOG(ERROR) << "Error parsing JSON '" << json_settings << "'";
+ g_free(json_settings);
+
+ for (std::deque<std::string>::const_iterator it = proxies.begin();
+ it != proxies.end(); ++it) {
+ g_print("%s\n", (*it).c_str());
+ }
+ return true;
+}
+
+
+int main(int argc, char *argv[]) {
+ google::ParseCommandLineFlags(&argc, &argv, true);
+ CommandLine::Init(argc, argv);
+
+ // Default to logging to syslog.
+ int init_flags = chromeos::kLogToSyslog;
+ // Log to stderr if a TTY (and "-quiet" wasn't passed), or if "-verbose"
+ // was passed.
+ if ((!FLAGS_quiet && isatty(STDERR_FILENO)) || FLAGS_verbose)
+ init_flags |= chromeos::kLogToStderr;
+ chromeos::InitLog(init_flags);
+
+ ::g_type_init();
+
+ const char *url = (argc >= 2) ? argv[1] : NULL;
+
+ LOG(INFO) << "Resolving proxies for URL: " << (url ? url : "<n/a>");
+
+ if (FLAGS_force_browser_proxies || FLAGS_force_session_proxies) {
+ if (FLAGS_force_browser_proxies) {
+ if (!ShowBrowserProxies(url))
+ LOG(ERROR) << "Error resolving proxies via the browser";
+ }
+ if (FLAGS_force_session_proxies) {
+ if (!ShowSessionProxies(url))
+ LOG(ERROR) << "Error resolving proxies via the session manager";
+ }
+ } else {
+ if (!ShowBrowserProxies(url)) {
+ LOG(ERROR) << "Error resolving proxies via the browser";
+ if (!ShowSessionProxies(url)) {
kmixter1 2011/04/06 04:28:53 I've heard we're moving away from global proxy set
Michael Krebs 2011/04/12 00:53:38 Removed.
+ LOG(ERROR) << "Error resolving proxies via the session manager";
+ LOG(INFO) << "Assuming direct proxy";
+ g_print("%s\n", kNoProxy);
+ }
+ }
+ }
+
+ return 0;
+}
« no previous file with comments | « Makefile ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698