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

Side by Side Diff: net/proxy/proxy_config_service_android.cc

Issue 10206014: Upstream Android proxy config service. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Address Ryan's comments Created 8 years, 7 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/proxy/proxy_config_service_android.h"
6
7 #include <sys/system_properties.h>
8
9 #include "base/android/jni_android.h"
10 #include "base/android/jni_string.h"
11 #include "base/android/scoped_java_ref.h"
12 #include "base/basictypes.h"
13 #include "base/bind.h"
14 #include "base/compiler_specific.h"
15 #include "base/location.h"
16 #include "base/logging.h"
17 #include "base/memory/ref_counted.h"
18 #include "base/observer_list.h"
19 #include "base/single_thread_task_runner.h"
20 #include "base/string_tokenizer.h"
21 #include "base/string_util.h"
22 #include "googleurl/src/url_parse.h"
23 #include "jni/proxy_change_listener_jni.h"
24 #include "net/base/host_port_pair.h"
25 #include "net/proxy/proxy_config.h"
26
27 using base::android::AttachCurrentThread;
28 using base::android::ConvertUTF8ToJavaString;
29 using base::android::ConvertJavaStringToUTF8;
30 using base::android::CheckException;
31 using base::android::ClearException;
32 using base::android::GetMethodID;
33
34 namespace net {
35
36 namespace {
37
38 // Returns whether the provided string was successfully converted to a port.
39 bool ConvertStringToPort(const std::string& port, int* output) {
40 url_parse::Component component(0, port.size());
41 int result = url_parse::ParsePort(port.c_str(), component);
42 if (result == url_parse::PORT_INVALID ||
43 result == url_parse::PORT_UNSPECIFIED)
44 return false;
45 *output = result;
46 return true;
47 }
48
49 ProxyServer ConstructProxyServer(ProxyServer::Scheme scheme,
50 const std::string& proxy_host,
51 const std::string& proxy_port) {
52 DCHECK(!proxy_host.empty());
53 int port_as_int = 0;
54 if (proxy_port.empty())
55 port_as_int = ProxyServer::GetDefaultPortForScheme(scheme);
56 else if (!ConvertStringToPort(proxy_port, &port_as_int))
57 return ProxyServer();
58 DCHECK(port_as_int > 0);
59 return ProxyServer(
60 scheme,
61 HostPortPair(proxy_host, static_cast<uint16>(port_as_int)));
62 }
63
64 ProxyServer LookupProxy(
65 const std::string& prefix,
66 ProxyConfigServiceAndroid::Delegate* delegate,
67 ProxyServer::Scheme scheme) {
68 DCHECK(!prefix.empty());
69 std::string proxy_host = delegate->GetProperty(prefix + ".proxyHost");
70 if (!proxy_host.empty()) {
71 std::string proxy_port = delegate->GetProperty(prefix + ".proxyPort");
72 return ConstructProxyServer(scheme, proxy_host, proxy_port);
73 }
74 // Fall back to default proxy, if any.
75 proxy_host = delegate->GetProperty("proxyHost");
76 if (!proxy_host.empty()) {
77 std::string proxy_port = delegate->GetProperty("proxyPort");
78 return ConstructProxyServer(scheme, proxy_host, proxy_port);
79 }
80 return ProxyServer();
81 }
82
83 ProxyServer LookupSocksProxy(
84 ProxyConfigServiceAndroid::Delegate* delegate) {
85 std::string proxy_host = delegate->GetProperty("socksProxyHost");
86 if (!proxy_host.empty()) {
87 std::string proxy_port = delegate->GetProperty("socksProxyPort");
88 return ConstructProxyServer(ProxyServer::SCHEME_SOCKS5, proxy_host,
89 proxy_port);
90 }
91 return ProxyServer();
92 }
93
94 void AddBypassRules(
95 const std::string& scheme,
96 ProxyConfigServiceAndroid::Delegate* delegate,
97 ProxyBypassRules* bypass_rules) {
98 // The format of a hostname pattern is a list of hostnames that are separated
99 // by | and that use * as a wildcard. For example, setting the
100 // http.nonProxyHosts property to *.android.com|*.kernel.org will cause
101 // requests to http://developer.android.com to be made without a proxy.
102 std::string non_proxy_hosts =
103 delegate->GetProperty(scheme + ".nonProxyHosts");
104 if (non_proxy_hosts.empty())
105 return;
106 StringTokenizer tokenizer(non_proxy_hosts, "|");
107 while (tokenizer.GetNext()) {
108 std::string token = tokenizer.token();
109 std::string pattern;
110 TrimWhitespaceASCII(token, TRIM_ALL, &pattern);
111 if (pattern.empty())
112 continue;
113 // '?' is not one of the specified pattern characters above.
114 DCHECK_EQ(std::string::npos, pattern.find('?'));
115 bypass_rules->AddRuleForHostname(scheme, pattern, -1);
116 }
117 }
118
119 // Returns true if a valid proxy was found.
120 bool GetProxyRules(
121 ProxyConfigServiceAndroid::Delegate* delegate,
122 ProxyConfig::ProxyRules* rules) {
123 // See libcore/luni/src/main/java/java/net/ProxySelectorImpl.java for the
124 // equivalent Android implementation.
125 rules->type = ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME;
126 rules->proxy_for_http = LookupProxy("http", delegate,
127 ProxyServer::SCHEME_HTTP);
128 rules->proxy_for_https = LookupProxy("https", delegate,
129 ProxyServer::SCHEME_HTTPS);
130 rules->proxy_for_ftp = LookupProxy("ftp", delegate, ProxyServer::SCHEME_HTTP);
131 rules->fallback_proxy = LookupSocksProxy(delegate);
132 rules->bypass_rules.Clear();
133 AddBypassRules("ftp", delegate, &rules->bypass_rules);
134 AddBypassRules("http", delegate, &rules->bypass_rules);
135 AddBypassRules("https", delegate, &rules->bypass_rules);
136 return rules->proxy_for_http.is_valid() ||
137 rules->proxy_for_https.is_valid() ||
138 rules->proxy_for_ftp.is_valid() ||
139 rules->fallback_proxy.is_valid();
140 };
141
142 void GetLatestProxyConfigInternal(
143 ProxyConfigServiceAndroid::Delegate* delegate,
144 ProxyConfig* config) {
145 if (!GetProxyRules(delegate, &config->proxy_rules()))
146 *config = ProxyConfig::CreateDirect();
147 }
148
149 // This class implements the link to Android's proxy broadcast mechanism.
150 class DelegateImpl : public ProxyConfigServiceAndroid::Delegate {
151 public:
152 virtual void Start(ProxyConfigServiceAndroid* service) OVERRIDE {
153 JNIEnv* env = AttachCurrentThread();
154 if (java_proxy_change_listener_android_.is_null()) {
155 java_proxy_change_listener_android_.Reset(
156 Java_ProxyChangeListener_create(
157 env, base::android::GetApplicationContext()));
158 CHECK(!java_proxy_change_listener_android_.is_null());
159 }
160 Java_ProxyChangeListener_start(
161 env,
162 java_proxy_change_listener_android_.obj(),
163 reinterpret_cast<jint>(service));
164 }
165
166 virtual void Stop() OVERRIDE {
167 // The java object will be NULL if Stop() was already called (e.g. after a
168 // Start()), or if Start() was never called. Stop() is called from the
169 // destructor of ProxyConfigServiceAndroid.
170 if (java_proxy_change_listener_android_.is_null())
171 return;
172 JNIEnv* env = AttachCurrentThread();
173 Java_ProxyChangeListener_stop(env,
174 java_proxy_change_listener_android_.obj());
175 }
176
177 virtual std::string GetProperty(const std::string& property) OVERRIDE {
178 // Use Java System.getProperty to get configuration information.
179 // TODO(pliard): Conversion to/from UTF8 ok here?
180 JNIEnv* env = AttachCurrentThread();
181 ScopedJavaLocalRef<jstring> str = ConvertUTF8ToJavaString(env, property);
182 ScopedJavaLocalRef<jstring> result =
183 Java_ProxyChangeListener_getProperty(env, str.obj());
184 return result.is_null() ?
185 std::string() : ConvertJavaStringToUTF8(env, result.obj());
186 }
187
188 private:
189 base::android::ScopedJavaGlobalRef<jobject>
190 java_proxy_change_listener_android_;
191 };
192
193 } // namespace
194
195 class ProxyConfigServiceAndroid::SharedObserverList
196 : public base::RefCountedThreadSafe<SharedObserverList> {
197 public:
198 SharedObserverList() {}
199
200 ObserverList<Observer> value;
201
202 private:
203 friend class base::RefCountedThreadSafe<SharedObserverList>;
204 ~SharedObserverList() {}
205
206 DISALLOW_COPY_AND_ASSIGN(SharedObserverList);
207 };
208
209 ProxyConfigServiceAndroid::ProxyConfigServiceAndroid(
210 base::SingleThreadTaskRunner* network_task_runner,
211 base::SingleThreadTaskRunner* jni_task_runner)
212 : delegate_(new DelegateImpl()),
213 observers_(new SharedObserverList()),
214 network_task_runner_(network_task_runner),
215 jni_task_runner_(jni_task_runner) {
216 DCHECK(network_task_runner_.get());
217 DCHECK(jni_task_runner_.get());
218 }
219
220 ProxyConfigServiceAndroid::~ProxyConfigServiceAndroid() {
221 jni_task_runner_->PostTask(FROM_HERE, base::Bind(&Delegate::Stop, delegate_));
222 }
223
224 // static
225 bool ProxyConfigServiceAndroid::Register(JNIEnv* env) {
226 return RegisterNativesImpl(env);
227 }
228
229 void ProxyConfigServiceAndroid::AddObserver(Observer* observer) {
230 DCHECK(OnNetworkThread());
231 if (observers_->value.size() == 0)
232 jni_task_runner_->PostTask(
233 FROM_HERE, base::Bind(&Delegate::Start, delegate_, this));
234 observers_->value.AddObserver(observer);
235 }
236
237 void ProxyConfigServiceAndroid::RemoveObserver(Observer* observer) {
238 DCHECK(OnNetworkThread());
239 observers_->value.RemoveObserver(observer);
240 if (observers_->value.size() == 0)
241 jni_task_runner_->PostTask(
242 FROM_HERE, base::Bind(&Delegate::Stop, delegate_));
243 }
244
245 ProxyConfigService::ConfigAvailability
246 ProxyConfigServiceAndroid::GetLatestProxyConfig(ProxyConfig* config) {
247 if (!config)
248 return ProxyConfigService::CONFIG_UNSET;
249 base::AutoLock lock(lock_);
250 *config = latest_proxy_config_;
251 return ProxyConfigService::CONFIG_VALID;
252 }
253
254 void ProxyConfigServiceAndroid::ProxySettingsChangedInternal() {
255 ProxyConfig proxy_config;
256 GetLatestProxyConfigInternal(delegate_.get(), &proxy_config);
257 network_task_runner_->PostTask(
258 FROM_HERE,
259 base::Bind(&ProxySettingsChangedCallback, observers_, proxy_config));
260 base::AutoLock lock(lock_);
261 latest_proxy_config_ = proxy_config;
262 }
263
264 ProxyConfigServiceAndroid::ProxyConfigServiceAndroid(
265 base::SingleThreadTaskRunner* network_task_runner,
266 base::SingleThreadTaskRunner* jni_task_runner,
267 ProxyConfigServiceAndroid::Delegate* delegate)
268 : delegate_(delegate),
269 observers_(new SharedObserverList()),
270 network_task_runner_(network_task_runner),
271 jni_task_runner_(jni_task_runner) {
272 }
273
274 // static
275 void ProxyConfigServiceAndroid::ProxySettingsChangedCallback(
276 const scoped_refptr<SharedObserverList>& observers,
277 const ProxyConfig& proxy_config) {
278 FOR_EACH_OBSERVER(Observer, observers->value,
279 OnProxyConfigChanged(proxy_config,
280 ProxyConfigService::CONFIG_VALID));
281 }
282
283 bool ProxyConfigServiceAndroid::OnNetworkThread() const {
284 return network_task_runner_->BelongsToCurrentThread();
285 }
286
287 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698