| // Copyright 2017 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 <brillo/http/http_proxy.h> |
| |
| #include <memory> |
| #include <string> |
| #include <vector> |
| |
| #include <base/bind.h> |
| #include <base/callback.h> |
| #include <base/logging.h> |
| #include <base/strings/string_tokenizer.h> |
| #include <base/strings/string_util.h> |
| #include <brillo/http/http_transport.h> |
| #include <chromeos/dbus/service_constants.h> |
| #include <dbus/bus.h> |
| #include <dbus/message.h> |
| #include <dbus/object_proxy.h> |
| |
| namespace { |
| bool ParseProxyInfo(dbus::Response* response, |
| std::vector<std::string>* proxies_out) { |
| DCHECK(proxies_out); |
| if (!response) { |
| LOG(ERROR) << chromeos::kNetworkProxyServiceName << " D-Bus call to " |
| << chromeos::kNetworkProxyServiceResolveProxyMethod |
| << " failed"; |
| proxies_out->assign({brillo::http::kDirectProxy}); |
| return false; |
| } |
| dbus::MessageReader reader(response); |
| std::string proxy_info; |
| std::string proxy_err; |
| if (!reader.PopString(&proxy_info) || !reader.PopString(&proxy_err)) { |
| LOG(ERROR) << chromeos::kNetworkProxyServiceName << " D-Bus call to " |
| << chromeos::kNetworkProxyServiceResolveProxyMethod |
| << " returned an invalid D-Bus response"; |
| proxies_out->assign({brillo::http::kDirectProxy}); |
| return false; |
| } |
| if (!proxy_err.empty()) { |
| // This case occurs when on the Chrome side of things it can't connect to |
| // the proxy resolver service, we just let this fall through and will end |
| // up returning success with only the direct proxy listed. |
| LOG(WARNING) << "Got error resolving proxy: " << proxy_err; |
| } |
| |
| base::StringTokenizer toker(proxy_info, ";"); |
| while (toker.GetNext()) { |
| std::string token = toker.token(); |
| base::TrimWhitespaceASCII(token, base::TRIM_ALL, &token); |
| |
| // Start by finding the first space (if any). |
| std::string::iterator space; |
| for (space = ++token.begin(); space != token.end(); ++space) { |
| if (base::IsAsciiWhitespace(*space)) { |
| break; |
| } |
| } |
| |
| std::string scheme = base::ToLowerASCII(std::string(token.begin(), space)); |
| // 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") { |
| LOG(ERROR) << "Invalid proxy scheme found of: " << scheme; |
| continue; |
| } |
| |
| std::string host_and_port = std::string(space, token.end()); |
| base::TrimWhitespaceASCII(host_and_port, base::TRIM_ALL, &host_and_port); |
| if (scheme != "direct" && host_and_port.empty()) { |
| LOG(ERROR) << "Invalid host/port information for proxy: " << token; |
| continue; |
| } |
| proxies_out->push_back(scheme + "://" + host_and_port); |
| } |
| // Always add the direct proxy (i.e. no proxy) as a last resort if not there. |
| if (proxies_out->empty() || |
| proxies_out->back() != brillo::http::kDirectProxy) { |
| proxies_out->push_back(brillo::http::kDirectProxy); |
| } |
| return true; |
| } |
| |
| void OnResolveProxy(const brillo::http::GetChromeProxyServersCallback& callback, |
| dbus::Response* response) { |
| std::vector<std::string> proxies; |
| bool result = ParseProxyInfo(response, &proxies); |
| callback.Run(result, std::move(proxies)); |
| } |
| } // namespace |
| |
| namespace brillo { |
| namespace http { |
| |
| bool GetChromeProxyServers(scoped_refptr<dbus::Bus> bus, const std::string& url, |
| std::vector<std::string>* proxies_out) { |
| dbus::ObjectProxy* proxy = |
| bus->GetObjectProxy(chromeos::kNetworkProxyServiceName, |
| dbus::ObjectPath(chromeos::kNetworkProxyServicePath)); |
| dbus::MethodCall method_call( |
| chromeos::kNetworkProxyServiceInterface, |
| chromeos::kNetworkProxyServiceResolveProxyMethod); |
| dbus::MessageWriter writer(&method_call); |
| writer.AppendString(url); |
| std::unique_ptr<dbus::Response> response = proxy->CallMethodAndBlock( |
| &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT); |
| return ParseProxyInfo(response.get(), proxies_out); |
| } |
| |
| void GetChromeProxyServersAsync(scoped_refptr<dbus::Bus> bus, |
| const std::string& url, |
| const GetChromeProxyServersCallback& callback) { |
| dbus::ObjectProxy* proxy = bus->GetObjectProxy( |
| chromeos::kNetworkProxyServiceName, |
| dbus::ObjectPath(chromeos::kNetworkProxyServicePath)); |
| dbus::MethodCall method_call( |
| chromeos::kNetworkProxyServiceInterface, |
| chromeos::kNetworkProxyServiceResolveProxyMethod); |
| dbus::MessageWriter writer(&method_call); |
| writer.AppendString(url); |
| proxy->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::Bind(&OnResolveProxy, callback)); |
| } |
| |
| } // namespace http |
| } // namespace brillo |