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.
5 #include "net/proxy/proxy_config_service_android.h"
7 #include <sys/system_properties.h>
9 #include "base/android/jni_string.h"
10 #include "base/basictypes.h"
11 #include "base/bind.h"
12 #include "base/callback.h"
13 #include "base/compiler_specific.h"
14 #include "base/location.h"
15 #include "base/logging.h"
16 #include "base/memory/ref_counted.h"
17 #include "base/observer_list.h"
18 #include "base/sequenced_task_runner.h"
19 #include "base/strings/string_tokenizer.h"
20 #include "base/strings/string_util.h"
21 #include "jni/ProxyChangeListener_jni.h"
22 #include "net/base/host_port_pair.h"
23 #include "net/proxy/proxy_config.h"
24 #include "url/url_parse.h"
26 using base::android::AttachCurrentThread
;
27 using base::android::ConvertUTF8ToJavaString
;
28 using base::android::ConvertJavaStringToUTF8
;
29 using base::android::CheckException
;
30 using base::android::ClearException
;
31 using base::android::ScopedJavaGlobalRef
;
37 typedef ProxyConfigServiceAndroid::GetPropertyCallback GetPropertyCallback
;
39 // Returns whether the provided string was successfully converted to a port.
40 bool ConvertStringToPort(const std::string
& port
, int* output
) {
41 url_parse::Component
component(0, port
.size());
42 int result
= url_parse::ParsePort(port
.c_str(), component
);
43 if (result
== url_parse::PORT_INVALID
||
44 result
== url_parse::PORT_UNSPECIFIED
)
50 ProxyServer
ConstructProxyServer(ProxyServer::Scheme scheme
,
51 const std::string
& proxy_host
,
52 const std::string
& proxy_port
) {
53 DCHECK(!proxy_host
.empty());
55 if (proxy_port
.empty())
56 port_as_int
= ProxyServer::GetDefaultPortForScheme(scheme
);
57 else if (!ConvertStringToPort(proxy_port
, &port_as_int
))
59 DCHECK(port_as_int
> 0);
62 HostPortPair(proxy_host
, static_cast<uint16
>(port_as_int
)));
65 ProxyServer
LookupProxy(const std::string
& prefix
,
66 const GetPropertyCallback
& get_property
,
67 ProxyServer::Scheme scheme
) {
68 DCHECK(!prefix
.empty());
69 std::string proxy_host
= get_property
.Run(prefix
+ ".proxyHost");
70 if (!proxy_host
.empty()) {
71 std::string proxy_port
= get_property
.Run(prefix
+ ".proxyPort");
72 return ConstructProxyServer(scheme
, proxy_host
, proxy_port
);
74 // Fall back to default proxy, if any.
75 proxy_host
= get_property
.Run("proxyHost");
76 if (!proxy_host
.empty()) {
77 std::string proxy_port
= get_property
.Run("proxyPort");
78 return ConstructProxyServer(scheme
, proxy_host
, proxy_port
);
83 ProxyServer
LookupSocksProxy(const GetPropertyCallback
& get_property
) {
84 std::string proxy_host
= get_property
.Run("socksProxyHost");
85 if (!proxy_host
.empty()) {
86 std::string proxy_port
= get_property
.Run("socksProxyPort");
87 return ConstructProxyServer(ProxyServer::SCHEME_SOCKS5
, proxy_host
,
93 void AddBypassRules(const std::string
& scheme
,
94 const GetPropertyCallback
& get_property
,
95 ProxyBypassRules
* bypass_rules
) {
96 // The format of a hostname pattern is a list of hostnames that are separated
97 // by | and that use * as a wildcard. For example, setting the
98 // http.nonProxyHosts property to *.android.com|*.kernel.org will cause
99 // requests to http://developer.android.com to be made without a proxy.
100 std::string non_proxy_hosts
=
101 get_property
.Run(scheme
+ ".nonProxyHosts");
102 if (non_proxy_hosts
.empty())
104 base::StringTokenizer
tokenizer(non_proxy_hosts
, "|");
105 while (tokenizer
.GetNext()) {
106 std::string token
= tokenizer
.token();
108 TrimWhitespaceASCII(token
, TRIM_ALL
, &pattern
);
111 // '?' is not one of the specified pattern characters above.
112 DCHECK_EQ(std::string::npos
, pattern
.find('?'));
113 bypass_rules
->AddRuleForHostname(scheme
, pattern
, -1);
117 // Returns true if a valid proxy was found.
118 bool GetProxyRules(const GetPropertyCallback
& get_property
,
119 ProxyConfig::ProxyRules
* rules
) {
120 // See libcore/luni/src/main/java/java/net/ProxySelectorImpl.java for the
121 // mostly equivalent Android implementation. There is one intentional
122 // difference: by default Chromium uses the HTTP port (80) for HTTPS
123 // connections via proxy. This default is identical on other platforms.
124 // On the opposite, Java spec suggests to use HTTPS port (443) by default (the
125 // default value of https.proxyPort).
126 rules
->type
= ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME
;
127 rules
->proxies_for_http
.SetSingleProxyServer(
128 LookupProxy("http", get_property
, ProxyServer::SCHEME_HTTP
));
129 rules
->proxies_for_https
.SetSingleProxyServer(
130 LookupProxy("https", get_property
, ProxyServer::SCHEME_HTTP
));
131 rules
->proxies_for_ftp
.SetSingleProxyServer(
132 LookupProxy("ftp", get_property
, ProxyServer::SCHEME_HTTP
));
133 rules
->fallback_proxies
.SetSingleProxyServer(LookupSocksProxy(get_property
));
134 rules
->bypass_rules
.Clear();
135 AddBypassRules("ftp", get_property
, &rules
->bypass_rules
);
136 AddBypassRules("http", get_property
, &rules
->bypass_rules
);
137 AddBypassRules("https", get_property
, &rules
->bypass_rules
);
138 // We know a proxy was found if not all of the proxy lists are empty.
139 return !(rules
->proxies_for_http
.IsEmpty() &&
140 rules
->proxies_for_https
.IsEmpty() &&
141 rules
->proxies_for_ftp
.IsEmpty() &&
142 rules
->fallback_proxies
.IsEmpty());
145 void GetLatestProxyConfigInternal(const GetPropertyCallback
& get_property
,
146 ProxyConfig
* config
) {
147 if (!GetProxyRules(get_property
, &config
->proxy_rules()))
148 *config
= ProxyConfig::CreateDirect();
151 std::string
GetJavaProperty(const std::string
& property
) {
152 // Use Java System.getProperty to get configuration information.
153 // TODO(pliard): Conversion to/from UTF8 ok here?
154 JNIEnv
* env
= AttachCurrentThread();
155 ScopedJavaLocalRef
<jstring
> str
= ConvertUTF8ToJavaString(env
, property
);
156 ScopedJavaLocalRef
<jstring
> result
=
157 Java_ProxyChangeListener_getProperty(env
, str
.obj());
158 return result
.is_null() ?
159 std::string() : ConvertJavaStringToUTF8(env
, result
.obj());
164 class ProxyConfigServiceAndroid::Delegate
165 : public base::RefCountedThreadSafe
<Delegate
> {
167 Delegate(base::SequencedTaskRunner
* network_task_runner
,
168 base::SequencedTaskRunner
* jni_task_runner
,
169 const GetPropertyCallback
& get_property_callback
)
170 : jni_delegate_(this),
171 network_task_runner_(network_task_runner
),
172 jni_task_runner_(jni_task_runner
),
173 get_property_callback_(get_property_callback
) {
177 DCHECK(OnJNIThread());
178 JNIEnv
* env
= AttachCurrentThread();
179 if (java_proxy_change_listener_
.is_null()) {
180 java_proxy_change_listener_
.Reset(
181 Java_ProxyChangeListener_create(
182 env
, base::android::GetApplicationContext()));
183 CHECK(!java_proxy_change_listener_
.is_null());
185 Java_ProxyChangeListener_start(
187 java_proxy_change_listener_
.obj(),
188 reinterpret_cast<jint
>(&jni_delegate_
));
191 void FetchInitialConfig() {
192 DCHECK(OnJNIThread());
193 ProxyConfig proxy_config
;
194 GetLatestProxyConfigInternal(get_property_callback_
, &proxy_config
);
195 network_task_runner_
->PostTask(
197 base::Bind(&Delegate::SetNewConfigOnNetworkThread
, this, proxy_config
));
202 ShutdownOnJNIThread();
204 jni_task_runner_
->PostTask(
206 base::Bind(&Delegate::ShutdownOnJNIThread
, this));
210 // Called only on the network thread.
211 void AddObserver(Observer
* observer
) {
212 DCHECK(OnNetworkThread());
213 observers_
.AddObserver(observer
);
216 void RemoveObserver(Observer
* observer
) {
217 DCHECK(OnNetworkThread());
218 observers_
.RemoveObserver(observer
);
221 ConfigAvailability
GetLatestProxyConfig(ProxyConfig
* config
) {
222 DCHECK(OnNetworkThread());
224 return ProxyConfigService::CONFIG_UNSET
;
225 *config
= proxy_config_
;
226 return ProxyConfigService::CONFIG_VALID
;
229 // Called on the JNI thread.
230 void ProxySettingsChanged() {
231 DCHECK(OnJNIThread());
232 ProxyConfig proxy_config
;
233 GetLatestProxyConfigInternal(get_property_callback_
, &proxy_config
);
234 network_task_runner_
->PostTask(
237 &Delegate::SetNewConfigOnNetworkThread
, this, proxy_config
));
241 friend class base::RefCountedThreadSafe
<Delegate
>;
243 class JNIDelegateImpl
: public ProxyConfigServiceAndroid::JNIDelegate
{
245 explicit JNIDelegateImpl(Delegate
* delegate
) : delegate_(delegate
) {}
247 // ProxyConfigServiceAndroid::JNIDelegate overrides.
248 virtual void ProxySettingsChanged(JNIEnv
*, jobject
) OVERRIDE
{
249 delegate_
->ProxySettingsChanged();
253 Delegate
* const delegate_
;
256 virtual ~Delegate() {}
258 void ShutdownOnJNIThread() {
259 if (java_proxy_change_listener_
.is_null())
261 JNIEnv
* env
= AttachCurrentThread();
262 Java_ProxyChangeListener_stop(env
, java_proxy_change_listener_
.obj());
265 // Called on the network thread.
266 void SetNewConfigOnNetworkThread(const ProxyConfig
& proxy_config
) {
267 DCHECK(OnNetworkThread());
268 proxy_config_
= proxy_config
;
269 FOR_EACH_OBSERVER(Observer
, observers_
,
270 OnProxyConfigChanged(proxy_config
,
271 ProxyConfigService::CONFIG_VALID
));
274 bool OnJNIThread() const {
275 return jni_task_runner_
->RunsTasksOnCurrentThread();
278 bool OnNetworkThread() const {
279 return network_task_runner_
->RunsTasksOnCurrentThread();
282 ScopedJavaGlobalRef
<jobject
> java_proxy_change_listener_
;
284 JNIDelegateImpl jni_delegate_
;
285 ObserverList
<Observer
> observers_
;
286 scoped_refptr
<base::SequencedTaskRunner
> network_task_runner_
;
287 scoped_refptr
<base::SequencedTaskRunner
> jni_task_runner_
;
288 GetPropertyCallback get_property_callback_
;
289 ProxyConfig proxy_config_
;
291 DISALLOW_COPY_AND_ASSIGN(Delegate
);
294 ProxyConfigServiceAndroid::ProxyConfigServiceAndroid(
295 base::SequencedTaskRunner
* network_task_runner
,
296 base::SequencedTaskRunner
* jni_task_runner
)
297 : delegate_(new Delegate(
298 network_task_runner
, jni_task_runner
, base::Bind(&GetJavaProperty
))) {
299 delegate_
->SetupJNI();
300 delegate_
->FetchInitialConfig();
303 ProxyConfigServiceAndroid::~ProxyConfigServiceAndroid() {
304 delegate_
->Shutdown();
308 bool ProxyConfigServiceAndroid::Register(JNIEnv
* env
) {
309 return RegisterNativesImpl(env
);
312 void ProxyConfigServiceAndroid::AddObserver(Observer
* observer
) {
313 delegate_
->AddObserver(observer
);
316 void ProxyConfigServiceAndroid::RemoveObserver(Observer
* observer
) {
317 delegate_
->RemoveObserver(observer
);
320 ProxyConfigService::ConfigAvailability
321 ProxyConfigServiceAndroid::GetLatestProxyConfig(ProxyConfig
* config
) {
322 return delegate_
->GetLatestProxyConfig(config
);
325 ProxyConfigServiceAndroid::ProxyConfigServiceAndroid(
326 base::SequencedTaskRunner
* network_task_runner
,
327 base::SequencedTaskRunner
* jni_task_runner
,
328 GetPropertyCallback get_property_callback
)
329 : delegate_(new Delegate(
330 network_task_runner
, jni_task_runner
, get_property_callback
)) {
331 delegate_
->SetupJNI();
332 delegate_
->FetchInitialConfig();
335 void ProxyConfigServiceAndroid::ProxySettingsChanged() {
336 delegate_
->ProxySettingsChanged();