blob: a7ba7c211a9ba58e4a7c7f11c677236ef7e8b0ec [file] [log] [blame]
Alex Deymoaea4c1c2015-08-19 20:24:43 -07001//
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//
Andrew de los Reyes000d8952011-03-02 15:21:14 -080016
17#include "update_engine/chrome_browser_proxy_resolver.h"
18
Alex Vakulenkod2779df2014-06-16 13:19:00 -070019#include <deque>
Andrew de los Reyes000d8952011-03-02 15:21:14 -080020#include <map>
21#include <string>
Alex Vakulenkod2779df2014-06-16 13:19:00 -070022#include <utility>
Andrew de los Reyes000d8952011-03-02 15:21:14 -080023
Alex Vakulenko4906c1c2014-08-21 13:17:44 -070024#include <base/bind.h>
Chris Sosafc661a12013-02-26 14:43:21 -080025#include <base/strings/string_tokenizer.h>
Alex Deymoc4acdf42014-05-28 21:07:10 -070026#include <base/strings/string_util.h>
Andrew de los Reyes000d8952011-03-02 15:21:14 -080027
Andrew de los Reyes000d8952011-03-02 15:21:14 -080028#include "update_engine/utils.h"
29
30namespace chromeos_update_engine {
31
Chris Sosafc661a12013-02-26 14:43:21 -080032using base::StringTokenizer;
Alex Deymo60ca1a72015-06-18 18:19:15 -070033using base::TimeDelta;
34using chromeos::MessageLoop;
Andrew de los Reyes000d8952011-03-02 15:21:14 -080035using std::deque;
36using std::make_pair;
Andrew de los Reyes000d8952011-03-02 15:21:14 -080037using std::pair;
38using std::string;
39
Andrew de los Reyes000d8952011-03-02 15:21:14 -080040const char kLibCrosServiceName[] = "org.chromium.LibCrosService";
Alex Deymo30534502015-07-20 15:06:33 -070041const char kLibCrosProxyResolveName[] = "ProxyResolved";
Andrew de los Reyes000d8952011-03-02 15:21:14 -080042const char kLibCrosProxyResolveSignalInterface[] =
Alex Deymo30534502015-07-20 15:06:33 -070043 "org.chromium.UpdateEngineLibcrosProxyResolvedInterface";
Andrew de los Reyes000d8952011-03-02 15:21:14 -080044
45namespace {
Gilad Arnoldb752fb32014-03-03 12:23:39 -080046
Andrew de los Reyes000d8952011-03-02 15:21:14 -080047const int kTimeout = 5; // seconds
48
Alex Vakulenkod2779df2014-06-16 13:19:00 -070049} // namespace
Andrew de los Reyes000d8952011-03-02 15:21:14 -080050
Gilad Arnold1b9d6ae2014-03-03 13:46:07 -080051ChromeBrowserProxyResolver::ChromeBrowserProxyResolver(
Alex Deymo30534502015-07-20 15:06:33 -070052 LibCrosProxy* libcros_proxy)
53 : libcros_proxy_(libcros_proxy), timeout_(kTimeout) {}
Andrew de los Reyes000d8952011-03-02 15:21:14 -080054
55bool ChromeBrowserProxyResolver::Init() {
Alex Deymo30534502015-07-20 15:06:33 -070056 libcros_proxy_->ue_proxy_resolved_interface()
57 ->RegisterProxyResolvedSignalHandler(
58 base::Bind(&ChromeBrowserProxyResolver::OnProxyResolvedSignal,
59 base::Unretained(this)),
60 base::Bind(&ChromeBrowserProxyResolver::OnSignalConnected,
61 base::Unretained(this)));
Andrew de los Reyes000d8952011-03-02 15:21:14 -080062 return true;
63}
64
65ChromeBrowserProxyResolver::~ChromeBrowserProxyResolver() {
Alex Deymo30534502015-07-20 15:06:33 -070066 // Kill outstanding timers.
Alex Deymo020600d2014-11-05 21:05:55 -080067 for (auto& timer : timers_) {
Alex Deymo60ca1a72015-06-18 18:19:15 -070068 MessageLoop::current()->CancelTask(timer.second);
69 timer.second = MessageLoop::kTaskIdNull;
Andrew de los Reyes000d8952011-03-02 15:21:14 -080070 }
71}
72
73bool ChromeBrowserProxyResolver::GetProxiesForUrl(const string& url,
74 ProxiesResolvedFn callback,
75 void* data) {
Alex Deymo30534502015-07-20 15:06:33 -070076 int timeout = timeout_;
77 chromeos::ErrorPtr error;
78 if (!libcros_proxy_->service_interface_proxy()->ResolveNetworkProxy(
79 url.c_str(),
80 kLibCrosProxyResolveSignalInterface,
81 kLibCrosProxyResolveName,
82 &error)) {
83 LOG(WARNING) << "Can't resolve the proxy. Continuing with no proxy.";
Andrew de los Reyes518502a2011-03-14 14:19:39 -070084 timeout = 0;
Andrew de los Reyes000d8952011-03-02 15:21:14 -080085 }
Gilad Arnold1877c392012-02-10 11:34:33 -080086
Andrew de los Reyes000d8952011-03-02 15:21:14 -080087 callbacks_.insert(make_pair(url, make_pair(callback, data)));
Alex Deymo60ca1a72015-06-18 18:19:15 -070088 MessageLoop::TaskId timer = MessageLoop::current()->PostDelayedTask(
89 FROM_HERE,
90 base::Bind(&ChromeBrowserProxyResolver::HandleTimeout,
91 base::Unretained(this),
92 url),
93 TimeDelta::FromSeconds(timeout));
Andrew de los Reyes000d8952011-03-02 15:21:14 -080094 timers_.insert(make_pair(url, timer));
95 return true;
96}
97
Andrew de los Reyes000d8952011-03-02 15:21:14 -080098bool ChromeBrowserProxyResolver::DeleteUrlState(
99 const string& source_url,
100 bool delete_timer,
101 pair<ProxiesResolvedFn, void*>* callback) {
102 {
103 CallbacksMap::iterator it = callbacks_.lower_bound(source_url);
104 TEST_AND_RETURN_FALSE(it != callbacks_.end());
105 TEST_AND_RETURN_FALSE(it->first == source_url);
106 if (callback)
107 *callback = it->second;
108 callbacks_.erase(it);
109 }
110 {
111 TimeoutsMap::iterator it = timers_.lower_bound(source_url);
112 TEST_AND_RETURN_FALSE(it != timers_.end());
113 TEST_AND_RETURN_FALSE(it->first == source_url);
114 if (delete_timer)
Alex Deymo60ca1a72015-06-18 18:19:15 -0700115 MessageLoop::current()->CancelTask(it->second);
Andrew de los Reyes000d8952011-03-02 15:21:14 -0800116 timers_.erase(it);
117 }
118 return true;
119}
120
Alex Deymo30534502015-07-20 15:06:33 -0700121void ChromeBrowserProxyResolver::OnSignalConnected(const string& interface_name,
122 const string& signal_name,
123 bool successful) {
124 if (!successful) {
125 LOG(ERROR) << "Couldn't connect to the signal " << interface_name << "."
126 << signal_name;
127 }
128}
129
130void ChromeBrowserProxyResolver::OnProxyResolvedSignal(
131 const string& source_url,
132 const string& proxy_info,
133 const string& error_message) {
Andrew de los Reyes000d8952011-03-02 15:21:14 -0800134 pair<ProxiesResolvedFn, void*> callback;
135 TEST_AND_RETURN(DeleteUrlState(source_url, true, &callback));
Alex Deymo30534502015-07-20 15:06:33 -0700136 if (!error_message.empty()) {
137 LOG(WARNING) << "ProxyResolved error: " << error_message;
138 }
139 (*callback.first)(ParseProxyString(proxy_info), callback.second);
Andrew de los Reyes000d8952011-03-02 15:21:14 -0800140}
141
142void ChromeBrowserProxyResolver::HandleTimeout(string source_url) {
143 LOG(INFO) << "Timeout handler called. Seems Chrome isn't responding.";
144 pair<ProxiesResolvedFn, void*> callback;
145 TEST_AND_RETURN(DeleteUrlState(source_url, false, &callback));
146 deque<string> proxies;
147 proxies.push_back(kNoProxy);
148 (*callback.first)(proxies, callback.second);
149}
150
151deque<string> ChromeBrowserProxyResolver::ParseProxyString(
152 const string& input) {
153 deque<string> ret;
154 // Some of this code taken from
155 // http://src.chromium.org/svn/trunk/src/net/proxy/proxy_server.cc and
156 // http://src.chromium.org/svn/trunk/src/net/proxy/proxy_list.cc
157 StringTokenizer entry_tok(input, ";");
158 while (entry_tok.GetNext()) {
159 string token = entry_tok.token();
Ben Chan736fcb52014-05-21 18:28:22 -0700160 base::TrimWhitespaceASCII(token, base::TRIM_ALL, &token);
Andrew de los Reyes000d8952011-03-02 15:21:14 -0800161
162 // Start by finding the first space (if any).
Alex Deymof329b932014-10-30 01:37:48 -0700163 string::iterator space;
Andrew de los Reyes000d8952011-03-02 15:21:14 -0800164 for (space = token.begin(); space != token.end(); ++space) {
165 if (IsAsciiWhitespace(*space)) {
166 break;
167 }
168 }
169
170 string scheme = string(token.begin(), space);
Ben Chan93aabd02014-09-05 08:20:59 -0700171 base::StringToLowerASCII(&scheme);
Andrew de los Reyes000d8952011-03-02 15:21:14 -0800172 // Chrome uses "socks" to mean socks4 and "proxy" to mean http.
173 if (scheme == "socks")
174 scheme += "4";
175 else if (scheme == "proxy")
176 scheme = "http";
177 else if (scheme != "https" &&
178 scheme != "socks4" &&
179 scheme != "socks5" &&
180 scheme != "direct")
181 continue; // Invalid proxy scheme
182
183 string host_and_port = string(space, token.end());
Ben Chan736fcb52014-05-21 18:28:22 -0700184 base::TrimWhitespaceASCII(host_and_port, base::TRIM_ALL, &host_and_port);
Andrew de los Reyes000d8952011-03-02 15:21:14 -0800185 if (scheme != "direct" && host_and_port.empty())
186 continue; // Must supply host/port when non-direct proxy used.
187 ret.push_back(scheme + "://" + host_and_port);
188 }
189 if (ret.empty() || *ret.rbegin() != kNoProxy)
190 ret.push_back(kNoProxy);
191 return ret;
192}
193
194} // namespace chromeos_update_engine