19ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk/* 29ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk * Copyright (C) 2013 The Android Open Source Project 39ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk * 49ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk * Licensed under the Apache License, Version 2.0 (the "License"); 59ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk * you may not use this file except in compliance with the License. 69ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk * You may obtain a copy of the License at 79ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk * 89ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk * http://www.apache.org/licenses/LICENSE-2.0 99ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk * 109ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk * Unless required by applicable law or agreed to in writing, software 119ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk * distributed under the License is distributed on an "AS IS" BASIS, 129ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk * See the License for the specific language governing permissions and 149ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk * limitations under the License. 159ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk */ 16602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 17602b232a06ede86999aa362a12eb28cbc782dc1dJason Monkpackage android.net; 18602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 19602b232a06ede86999aa362a12eb28cbc782dc1dJason Monkimport android.os.ServiceManager; 20a48ad8bd858d6ffe77838a282dbf71e01967957cWink Savilleimport android.util.Log; 21602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 22602b232a06ede86999aa362a12eb28cbc782dc1dJason Monkimport com.android.net.IProxyService; 23602b232a06ede86999aa362a12eb28cbc782dc1dJason Monkimport com.google.android.collect.Lists; 24602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 25602b232a06ede86999aa362a12eb28cbc782dc1dJason Monkimport java.io.IOException; 26602b232a06ede86999aa362a12eb28cbc782dc1dJason Monkimport java.net.InetSocketAddress; 27602b232a06ede86999aa362a12eb28cbc782dc1dJason Monkimport java.net.MalformedURLException; 28602b232a06ede86999aa362a12eb28cbc782dc1dJason Monkimport java.net.Proxy; 29602b232a06ede86999aa362a12eb28cbc782dc1dJason Monkimport java.net.Proxy.Type; 30602b232a06ede86999aa362a12eb28cbc782dc1dJason Monkimport java.net.ProxySelector; 31602b232a06ede86999aa362a12eb28cbc782dc1dJason Monkimport java.net.SocketAddress; 32602b232a06ede86999aa362a12eb28cbc782dc1dJason Monkimport java.net.URI; 3308ec0e53b8ab0c3c6ab605c237fcc6df4cad2fcdPaul Jensenimport java.net.URISyntaxException; 34602b232a06ede86999aa362a12eb28cbc782dc1dJason Monkimport java.util.List; 35602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 36602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk/** 37602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk * @hide 38602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk */ 39602b232a06ede86999aa362a12eb28cbc782dc1dJason Monkpublic class PacProxySelector extends ProxySelector { 40a48ad8bd858d6ffe77838a282dbf71e01967957cWink Saville private static final String TAG = "PacProxySelector"; 41602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk public static final String PROXY_SERVICE = "com.android.net.IProxyService"; 424385af32eff1b99802e6ce233a2b10d002bf4eb1Jason Monk private static final String SOCKS = "SOCKS "; 434385af32eff1b99802e6ce233a2b10d002bf4eb1Jason Monk private static final String PROXY = "PROXY "; 444385af32eff1b99802e6ce233a2b10d002bf4eb1Jason Monk 45602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk private IProxyService mProxyService; 469ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk private final List<Proxy> mDefaultList; 47602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 48602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk public PacProxySelector() { 49602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk mProxyService = IProxyService.Stub.asInterface( 50602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk ServiceManager.getService(PROXY_SERVICE)); 51a48ad8bd858d6ffe77838a282dbf71e01967957cWink Saville if (mProxyService == null) { 52a48ad8bd858d6ffe77838a282dbf71e01967957cWink Saville // Added because of b10267814 where mako is restarting. 539ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk Log.e(TAG, "PacManager: no proxy service"); 54a48ad8bd858d6ffe77838a282dbf71e01967957cWink Saville } 559ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk mDefaultList = Lists.newArrayList(java.net.Proxy.NO_PROXY); 56602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 57602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 58602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk @Override 59602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk public List<Proxy> select(URI uri) { 60a48ad8bd858d6ffe77838a282dbf71e01967957cWink Saville if (mProxyService == null) { 619ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk mProxyService = IProxyService.Stub.asInterface( 629ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk ServiceManager.getService(PROXY_SERVICE)); 639ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk } 649ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk if (mProxyService == null) { 65a48ad8bd858d6ffe77838a282dbf71e01967957cWink Saville Log.e(TAG, "select: no proxy service return NO_PROXY"); 66a48ad8bd858d6ffe77838a282dbf71e01967957cWink Saville return Lists.newArrayList(java.net.Proxy.NO_PROXY); 67a48ad8bd858d6ffe77838a282dbf71e01967957cWink Saville } 68602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk String response = null; 69602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk String urlString; 70602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk try { 7108ec0e53b8ab0c3c6ab605c237fcc6df4cad2fcdPaul Jensen // Strip path and username/password from URI so it's not visible to PAC script. The 7208ec0e53b8ab0c3c6ab605c237fcc6df4cad2fcdPaul Jensen // path often contains credentials the app does not want exposed to a potentially 7308ec0e53b8ab0c3c6ab605c237fcc6df4cad2fcdPaul Jensen // malicious PAC script. 7408ec0e53b8ab0c3c6ab605c237fcc6df4cad2fcdPaul Jensen if (!"http".equalsIgnoreCase(uri.getScheme())) { 7508ec0e53b8ab0c3c6ab605c237fcc6df4cad2fcdPaul Jensen uri = new URI(uri.getScheme(), null, uri.getHost(), uri.getPort(), "/", null, null); 7608ec0e53b8ab0c3c6ab605c237fcc6df4cad2fcdPaul Jensen } 77602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk urlString = uri.toURL().toString(); 7808ec0e53b8ab0c3c6ab605c237fcc6df4cad2fcdPaul Jensen } catch (URISyntaxException e) { 7908ec0e53b8ab0c3c6ab605c237fcc6df4cad2fcdPaul Jensen urlString = uri.getHost(); 80602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } catch (MalformedURLException e) { 81602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk urlString = uri.getHost(); 82602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 83602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk try { 84602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk response = mProxyService.resolvePacFile(uri.getHost(), urlString); 8544c02590374bda5928669be0d14110b12c271461Andrei Kapishnikov } catch (Exception e) { 8644c02590374bda5928669be0d14110b12c271461Andrei Kapishnikov Log.e(TAG, "Error resolving PAC File", e); 87602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 889ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk if (response == null) { 899ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk return mDefaultList; 909ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk } 91602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 92602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk return parseResponse(response); 93602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 94602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 95602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk private static List<Proxy> parseResponse(String response) { 96602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk String[] split = response.split(";"); 97602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk List<Proxy> ret = Lists.newArrayList(); 98602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk for (String s : split) { 99602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk String trimmed = s.trim(); 100602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk if (trimmed.equals("DIRECT")) { 101602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk ret.add(java.net.Proxy.NO_PROXY); 1024385af32eff1b99802e6ce233a2b10d002bf4eb1Jason Monk } else if (trimmed.startsWith(PROXY)) { 1034385af32eff1b99802e6ce233a2b10d002bf4eb1Jason Monk Proxy proxy = proxyFromHostPort(Type.HTTP, trimmed.substring(PROXY.length())); 1044385af32eff1b99802e6ce233a2b10d002bf4eb1Jason Monk if (proxy != null) { 1054385af32eff1b99802e6ce233a2b10d002bf4eb1Jason Monk ret.add(proxy); 1064385af32eff1b99802e6ce233a2b10d002bf4eb1Jason Monk } 1074385af32eff1b99802e6ce233a2b10d002bf4eb1Jason Monk } else if (trimmed.startsWith(SOCKS)) { 1084385af32eff1b99802e6ce233a2b10d002bf4eb1Jason Monk Proxy proxy = proxyFromHostPort(Type.SOCKS, trimmed.substring(SOCKS.length())); 1094385af32eff1b99802e6ce233a2b10d002bf4eb1Jason Monk if (proxy != null) { 1104385af32eff1b99802e6ce233a2b10d002bf4eb1Jason Monk ret.add(proxy); 111602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 112602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 113602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 114602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk if (ret.size() == 0) { 115602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk ret.add(java.net.Proxy.NO_PROXY); 116602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 117602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk return ret; 118602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 119602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 1204385af32eff1b99802e6ce233a2b10d002bf4eb1Jason Monk private static Proxy proxyFromHostPort(Proxy.Type type, String hostPortString) { 1214385af32eff1b99802e6ce233a2b10d002bf4eb1Jason Monk try { 1224385af32eff1b99802e6ce233a2b10d002bf4eb1Jason Monk String[] hostPort = hostPortString.split(":"); 1234385af32eff1b99802e6ce233a2b10d002bf4eb1Jason Monk String host = hostPort[0]; 1244385af32eff1b99802e6ce233a2b10d002bf4eb1Jason Monk int port = Integer.parseInt(hostPort[1]); 1254385af32eff1b99802e6ce233a2b10d002bf4eb1Jason Monk return new Proxy(type, InetSocketAddress.createUnresolved(host, port)); 1264385af32eff1b99802e6ce233a2b10d002bf4eb1Jason Monk } catch (NumberFormatException|ArrayIndexOutOfBoundsException e) { 1274385af32eff1b99802e6ce233a2b10d002bf4eb1Jason Monk Log.d(TAG, "Unable to parse proxy " + hostPortString + " " + e); 1284385af32eff1b99802e6ce233a2b10d002bf4eb1Jason Monk return null; 1294385af32eff1b99802e6ce233a2b10d002bf4eb1Jason Monk } 1304385af32eff1b99802e6ce233a2b10d002bf4eb1Jason Monk } 1314385af32eff1b99802e6ce233a2b10d002bf4eb1Jason Monk 132602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk @Override 133602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk public void connectFailed(URI uri, SocketAddress address, IOException failure) { 134602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 135602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 136602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 137602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk} 138