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 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 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 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 106 bool ChromeBrowserProxyResolver::CancelProxyRequest(ProxyRequestId request) { 107 return pending_callbacks_.erase(request) != 0; 108 } 109 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 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 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