15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/proxy/proxy_config_service_android.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/system_properties.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/android/jni_string.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/callback.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/compiler_specific.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/location.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/ref_counted.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/observer_list.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/sequenced_task_runner.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_tokenizer.h"
207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "base/strings/string_util.h"
211e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "base/strings/stringprintf.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "jni/ProxyChangeListener_jni.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/host_port_pair.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/proxy/proxy_config.h"
257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "url/url_parse.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::android::AttachCurrentThread;
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::android::ConvertUTF8ToJavaString;
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::android::ConvertJavaStringToUTF8;
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::android::CheckException;
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::android::ClearException;
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::android::ScopedJavaGlobalRef;
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net {
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef ProxyConfigServiceAndroid::GetPropertyCallback GetPropertyCallback;
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns whether the provided string was successfully converted to a port.
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ConvertStringToPort(const std::string& port, int* output) {
425c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  url::Component component(0, port.size());
435c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  int result = url::ParsePort(port.c_str(), component);
445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (result == url::PORT_INVALID || result == url::PORT_UNSPECIFIED)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *output = result;
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ProxyServer ConstructProxyServer(ProxyServer::Scheme scheme,
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 const std::string& proxy_host,
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 const std::string& proxy_port) {
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!proxy_host.empty());
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int port_as_int = 0;
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (proxy_port.empty())
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    port_as_int = ProxyServer::GetDefaultPortForScheme(scheme);
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else if (!ConvertStringToPort(proxy_port, &port_as_int))
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ProxyServer();
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(port_as_int > 0);
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ProxyServer(
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      scheme,
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      HostPortPair(proxy_host, static_cast<uint16>(port_as_int)));
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ProxyServer LookupProxy(const std::string& prefix,
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        const GetPropertyCallback& get_property,
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        ProxyServer::Scheme scheme) {
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!prefix.empty());
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string proxy_host = get_property.Run(prefix + ".proxyHost");
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!proxy_host.empty()) {
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string proxy_port = get_property.Run(prefix + ".proxyPort");
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ConstructProxyServer(scheme, proxy_host, proxy_port);
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Fall back to default proxy, if any.
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  proxy_host = get_property.Run("proxyHost");
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!proxy_host.empty()) {
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string proxy_port = get_property.Run("proxyPort");
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ConstructProxyServer(scheme, proxy_host, proxy_port);
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ProxyServer();
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ProxyServer LookupSocksProxy(const GetPropertyCallback& get_property) {
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string proxy_host = get_property.Run("socksProxyHost");
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!proxy_host.empty()) {
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string proxy_port = get_property.Run("socksProxyPort");
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ConstructProxyServer(ProxyServer::SCHEME_SOCKS5, proxy_host,
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                proxy_port);
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ProxyServer();
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AddBypassRules(const std::string& scheme,
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    const GetPropertyCallback& get_property,
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    ProxyBypassRules* bypass_rules) {
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The format of a hostname pattern is a list of hostnames that are separated
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // by | and that use * as a wildcard. For example, setting the
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // http.nonProxyHosts property to *.android.com|*.kernel.org will cause
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // requests to http://developer.android.com to be made without a proxy.
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string non_proxy_hosts =
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      get_property.Run(scheme + ".nonProxyHosts");
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (non_proxy_hosts.empty())
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::StringTokenizer tokenizer(non_proxy_hosts, "|");
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (tokenizer.GetNext()) {
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string token = tokenizer.token();
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string pattern;
108a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    base::TrimWhitespaceASCII(token, base::TRIM_ALL, &pattern);
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (pattern.empty())
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // '?' is not one of the specified pattern characters above.
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_EQ(std::string::npos, pattern.find('?'));
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bypass_rules->AddRuleForHostname(scheme, pattern, -1);
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns true if a valid proxy was found.
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetProxyRules(const GetPropertyCallback& get_property,
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   ProxyConfig::ProxyRules* rules) {
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // See libcore/luni/src/main/java/java/net/ProxySelectorImpl.java for the
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // mostly equivalent Android implementation.  There is one intentional
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // difference: by default Chromium uses the HTTP port (80) for HTTPS
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // connections via proxy.  This default is identical on other platforms.
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // On the opposite, Java spec suggests to use HTTPS port (443) by default (the
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // default value of https.proxyPort).
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  rules->type = ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME;
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  rules->proxies_for_http.SetSingleProxyServer(
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      LookupProxy("http", get_property, ProxyServer::SCHEME_HTTP));
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  rules->proxies_for_https.SetSingleProxyServer(
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      LookupProxy("https", get_property, ProxyServer::SCHEME_HTTP));
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  rules->proxies_for_ftp.SetSingleProxyServer(
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      LookupProxy("ftp", get_property, ProxyServer::SCHEME_HTTP));
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  rules->fallback_proxies.SetSingleProxyServer(LookupSocksProxy(get_property));
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  rules->bypass_rules.Clear();
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddBypassRules("ftp", get_property, &rules->bypass_rules);
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddBypassRules("http", get_property, &rules->bypass_rules);
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddBypassRules("https", get_property, &rules->bypass_rules);
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // We know a proxy was found if not all of the proxy lists are empty.
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return !(rules->proxies_for_http.IsEmpty() &&
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      rules->proxies_for_https.IsEmpty() &&
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      rules->proxies_for_ftp.IsEmpty() &&
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      rules->fallback_proxies.IsEmpty());
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GetLatestProxyConfigInternal(const GetPropertyCallback& get_property,
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  ProxyConfig* config) {
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!GetProxyRules(get_property, &config->proxy_rules()))
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *config = ProxyConfig::CreateDirect();
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string GetJavaProperty(const std::string& property) {
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Use Java System.getProperty to get configuration information.
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(pliard): Conversion to/from UTF8 ok here?
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  JNIEnv* env = AttachCurrentThread();
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedJavaLocalRef<jstring> str = ConvertUTF8ToJavaString(env, property);
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedJavaLocalRef<jstring> result =
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Java_ProxyChangeListener_getProperty(env, str.obj());
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result.is_null() ?
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::string() : ConvertJavaStringToUTF8(env, result.obj());
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1621e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void CreateStaticProxyConfig(const std::string& host, int port,
1631e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                             ProxyConfig* config) {
1641e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (port != 0) {
1651e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    std::string rules = base::StringPrintf("%s:%d", host.c_str(), port);
1661e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    config->proxy_rules().ParseFromString(rules);
1671e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  } else {
1681e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    *config = ProxyConfig::CreateDirect();
1691e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
1701e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
1711e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ProxyConfigServiceAndroid::Delegate
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : public base::RefCountedThreadSafe<Delegate> {
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Delegate(base::SequencedTaskRunner* network_task_runner,
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           base::SequencedTaskRunner* jni_task_runner,
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           const GetPropertyCallback& get_property_callback)
180c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      : jni_delegate_(this),
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        network_task_runner_(network_task_runner),
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        jni_task_runner_(jni_task_runner),
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        get_property_callback_(get_property_callback) {
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void SetupJNI() {
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(OnJNIThread());
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    JNIEnv* env = AttachCurrentThread();
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (java_proxy_change_listener_.is_null()) {
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      java_proxy_change_listener_.Reset(
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          Java_ProxyChangeListener_create(
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              env, base::android::GetApplicationContext()));
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CHECK(!java_proxy_change_listener_.is_null());
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Java_ProxyChangeListener_start(
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        env,
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        java_proxy_change_listener_.obj(),
198f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        reinterpret_cast<intptr_t>(&jni_delegate_));
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void FetchInitialConfig() {
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(OnJNIThread());
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ProxyConfig proxy_config;
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GetLatestProxyConfigInternal(get_property_callback_, &proxy_config);
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    network_task_runner_->PostTask(
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE,
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&Delegate::SetNewConfigOnNetworkThread, this, proxy_config));
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Shutdown() {
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (OnJNIThread()) {
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ShutdownOnJNIThread();
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      jni_task_runner_->PostTask(
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          FROM_HERE,
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          base::Bind(&Delegate::ShutdownOnJNIThread, this));
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Called only on the network thread.
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void AddObserver(Observer* observer) {
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(OnNetworkThread());
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    observers_.AddObserver(observer);
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void RemoveObserver(Observer* observer) {
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(OnNetworkThread());
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    observers_.RemoveObserver(observer);
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ConfigAvailability GetLatestProxyConfig(ProxyConfig* config) {
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(OnNetworkThread());
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!config)
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return ProxyConfigService::CONFIG_UNSET;
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *config = proxy_config_;
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ProxyConfigService::CONFIG_VALID;
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Called on the JNI thread.
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void ProxySettingsChanged() {
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(OnJNIThread());
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ProxyConfig proxy_config;
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GetLatestProxyConfigInternal(get_property_callback_, &proxy_config);
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    network_task_runner_->PostTask(
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE,
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            &Delegate::SetNewConfigOnNetworkThread, this, proxy_config));
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2501e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // Called on the JNI thread.
2511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  void ProxySettingsChangedTo(const std::string& host, int port) {
2521e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    DCHECK(OnJNIThread());
2531e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    ProxyConfig proxy_config;
2541e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    CreateStaticProxyConfig(host, port, &proxy_config);
2551e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    network_task_runner_->PostTask(
2561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        FROM_HERE,
2571e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        base::Bind(
2581e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)            &Delegate::SetNewConfigOnNetworkThread, this, proxy_config));
2591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
2601e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  friend class base::RefCountedThreadSafe<Delegate>;
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  class JNIDelegateImpl : public ProxyConfigServiceAndroid::JNIDelegate {
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   public:
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    explicit JNIDelegateImpl(Delegate* delegate) : delegate_(delegate) {}
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // ProxyConfigServiceAndroid::JNIDelegate overrides.
2691e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    virtual void ProxySettingsChangedTo(JNIEnv* env, jobject jself,
2701e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                                      jstring jhost, jint jport) OVERRIDE {
2711e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      std::string host = ConvertJavaStringToUTF8(env, jhost);
2721e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      delegate_->ProxySettingsChangedTo(host, jport);
2731e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    }
2741e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2751e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    virtual void ProxySettingsChanged(JNIEnv* env, jobject self) OVERRIDE {
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delegate_->ProxySettingsChanged();
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   private:
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Delegate* const delegate_;
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~Delegate() {}
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void ShutdownOnJNIThread() {
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (java_proxy_change_listener_.is_null())
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    JNIEnv* env = AttachCurrentThread();
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Java_ProxyChangeListener_stop(env, java_proxy_change_listener_.obj());
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Called on the network thread.
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void SetNewConfigOnNetworkThread(const ProxyConfig& proxy_config) {
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(OnNetworkThread());
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    proxy_config_ = proxy_config;
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FOR_EACH_OBSERVER(Observer, observers_,
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      OnProxyConfigChanged(proxy_config,
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           ProxyConfigService::CONFIG_VALID));
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool OnJNIThread() const {
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return jni_task_runner_->RunsTasksOnCurrentThread();
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool OnNetworkThread() const {
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return network_task_runner_->RunsTasksOnCurrentThread();
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedJavaGlobalRef<jobject> java_proxy_change_listener_;
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  JNIDelegateImpl jni_delegate_;
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ObserverList<Observer> observers_;
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<base::SequencedTaskRunner> network_task_runner_;
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<base::SequencedTaskRunner> jni_task_runner_;
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetPropertyCallback get_property_callback_;
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProxyConfig proxy_config_;
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(Delegate);
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ProxyConfigServiceAndroid::ProxyConfigServiceAndroid(
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::SequencedTaskRunner* network_task_runner,
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::SequencedTaskRunner* jni_task_runner)
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : delegate_(new Delegate(
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        network_task_runner, jni_task_runner, base::Bind(&GetJavaProperty))) {
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delegate_->SetupJNI();
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delegate_->FetchInitialConfig();
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ProxyConfigServiceAndroid::~ProxyConfigServiceAndroid() {
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delegate_->Shutdown();
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ProxyConfigServiceAndroid::Register(JNIEnv* env) {
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return RegisterNativesImpl(env);
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProxyConfigServiceAndroid::AddObserver(Observer* observer) {
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delegate_->AddObserver(observer);
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProxyConfigServiceAndroid::RemoveObserver(Observer* observer) {
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delegate_->RemoveObserver(observer);
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ProxyConfigService::ConfigAvailability
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ProxyConfigServiceAndroid::GetLatestProxyConfig(ProxyConfig* config) {
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return delegate_->GetLatestProxyConfig(config);
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ProxyConfigServiceAndroid::ProxyConfigServiceAndroid(
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::SequencedTaskRunner* network_task_runner,
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::SequencedTaskRunner* jni_task_runner,
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GetPropertyCallback get_property_callback)
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : delegate_(new Delegate(
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        network_task_runner, jni_task_runner, get_property_callback)) {
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delegate_->SetupJNI();
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delegate_->FetchInitialConfig();
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProxyConfigServiceAndroid::ProxySettingsChanged() {
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delegate_->ProxySettingsChanged();
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace net
367