1 //
2 // Copyright (C) 2011 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16
17 #include "update_engine/chrome_browser_proxy_resolver.h"
18
19 #include <utility>
20
21 #include <base/bind.h>
22 #include <base/memory/ptr_util.h>
23 #include <base/strings/string_tokenizer.h>
24 #include <base/strings/string_util.h>
25
26 #include "network_proxy/dbus-proxies.h"
27
28 namespace chromeos_update_engine {
29
30 using base::StringTokenizer;
31 using std::deque;
32 using std::string;
33
34 namespace {
35
36 // Timeout for D-Bus calls in milliseconds.
37 constexpr int kTimeoutMs = 5000;
38
39 } // namespace
40
ChromeBrowserProxyResolver(org::chromium::NetworkProxyServiceInterfaceProxyInterface * dbus_proxy)41 ChromeBrowserProxyResolver::ChromeBrowserProxyResolver(
42 org::chromium::NetworkProxyServiceInterfaceProxyInterface* dbus_proxy)
43 : dbus_proxy_(dbus_proxy),
44 next_request_id_(kProxyRequestIdNull + 1),
45 weak_ptr_factory_(this) {}
46
47 ChromeBrowserProxyResolver::~ChromeBrowserProxyResolver() = default;
48
49 // static
ParseProxyString(const string & input)50 deque<string> ChromeBrowserProxyResolver::ParseProxyString(
51 const string& input) {
52 deque<string> ret;
53 // Some of this code taken from
54 // http://src.chromium.org/svn/trunk/src/net/proxy/proxy_server.cc and
55 // http://src.chromium.org/svn/trunk/src/net/proxy/proxy_list.cc
56 StringTokenizer entry_tok(input, ";");
57 while (entry_tok.GetNext()) {
58 string token = entry_tok.token();
59 base::TrimWhitespaceASCII(token, base::TRIM_ALL, &token);
60
61 // Start by finding the first space (if any).
62 string::iterator space;
63 for (space = token.begin(); space != token.end(); ++space) {
64 if (base::IsAsciiWhitespace(*space)) {
65 break;
66 }
67 }
68
69 string scheme = base::ToLowerASCII(string(token.begin(), space));
70 // Chrome uses "socks" to mean socks4 and "proxy" to mean http.
71 if (scheme == "socks")
72 scheme += "4";
73 else if (scheme == "proxy")
74 scheme = "http";
75 else if (scheme != "https" &&
76 scheme != "socks4" &&
77 scheme != "socks5" &&
78 scheme != "direct")
79 continue; // Invalid proxy scheme
80
81 string host_and_port = string(space, token.end());
82 base::TrimWhitespaceASCII(host_and_port, base::TRIM_ALL, &host_and_port);
83 if (scheme != "direct" && host_and_port.empty())
84 continue; // Must supply host/port when non-direct proxy used.
85 ret.push_back(scheme + "://" + host_and_port);
86 }
87 if (ret.empty() || *ret.rbegin() != kNoProxy)
88 ret.push_back(kNoProxy);
89 return ret;
90 }
91
GetProxiesForUrl(const string & url,const ProxiesResolvedFn & callback)92 ProxyRequestId ChromeBrowserProxyResolver::GetProxiesForUrl(
93 const string& url, const ProxiesResolvedFn& callback) {
94 const ProxyRequestId id = next_request_id_++;
95 dbus_proxy_->ResolveProxyAsync(
96 url,
97 base::Bind(&ChromeBrowserProxyResolver::OnResolveProxyResponse,
98 weak_ptr_factory_.GetWeakPtr(), id),
99 base::Bind(&ChromeBrowserProxyResolver::OnResolveProxyError,
100 weak_ptr_factory_.GetWeakPtr(), id),
101 kTimeoutMs);
102 pending_callbacks_[id] = callback;
103 return id;
104 }
105
CancelProxyRequest(ProxyRequestId request)106 bool ChromeBrowserProxyResolver::CancelProxyRequest(ProxyRequestId request) {
107 return pending_callbacks_.erase(request) != 0;
108 }
109
OnResolveProxyResponse(ProxyRequestId request_id,const std::string & proxy_info,const std::string & error_message)110 void ChromeBrowserProxyResolver::OnResolveProxyResponse(
111 ProxyRequestId request_id,
112 const std::string& proxy_info,
113 const std::string& error_message) {
114 if (!error_message.empty())
115 LOG(WARNING) << "Got error resolving proxy: " << error_message;
116 RunCallback(request_id, ParseProxyString(proxy_info));
117 }
118
OnResolveProxyError(ProxyRequestId request_id,brillo::Error * error)119 void ChromeBrowserProxyResolver::OnResolveProxyError(ProxyRequestId request_id,
120 brillo::Error* error) {
121 LOG(WARNING) << "Failed to resolve proxy: "
122 << (error ? error->GetMessage() : "[null]");
123 RunCallback(request_id, deque<string>{kNoProxy});
124 }
125
RunCallback(ProxyRequestId request_id,const std::deque<std::string> & proxies)126 void ChromeBrowserProxyResolver::RunCallback(
127 ProxyRequestId request_id,
128 const std::deque<std::string>& proxies) {
129 auto it = pending_callbacks_.find(request_id);
130 if (it == pending_callbacks_.end())
131 return;
132
133 ProxiesResolvedFn callback = it->second;
134 pending_callbacks_.erase(it);
135 callback.Run(proxies);
136 }
137
138 } // namespace chromeos_update_engine
139