1/* 2 * Copyright (C) 2013 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 17package android.net; 18 19import android.os.ServiceManager; 20import android.util.Log; 21 22import com.android.net.IProxyService; 23import com.google.android.collect.Lists; 24 25import java.io.IOException; 26import java.net.InetSocketAddress; 27import java.net.MalformedURLException; 28import java.net.Proxy; 29import java.net.Proxy.Type; 30import java.net.ProxySelector; 31import java.net.SocketAddress; 32import java.net.URI; 33import java.net.URISyntaxException; 34import java.util.List; 35 36/** 37 * @hide 38 */ 39public class PacProxySelector extends ProxySelector { 40 private static final String TAG = "PacProxySelector"; 41 public static final String PROXY_SERVICE = "com.android.net.IProxyService"; 42 private static final String SOCKS = "SOCKS "; 43 private static final String PROXY = "PROXY "; 44 45 private IProxyService mProxyService; 46 private final List<Proxy> mDefaultList; 47 48 public PacProxySelector() { 49 mProxyService = IProxyService.Stub.asInterface( 50 ServiceManager.getService(PROXY_SERVICE)); 51 if (mProxyService == null) { 52 // Added because of b10267814 where mako is restarting. 53 Log.e(TAG, "PacManager: no proxy service"); 54 } 55 mDefaultList = Lists.newArrayList(java.net.Proxy.NO_PROXY); 56 } 57 58 @Override 59 public List<Proxy> select(URI uri) { 60 if (mProxyService == null) { 61 mProxyService = IProxyService.Stub.asInterface( 62 ServiceManager.getService(PROXY_SERVICE)); 63 } 64 if (mProxyService == null) { 65 Log.e(TAG, "select: no proxy service return NO_PROXY"); 66 return Lists.newArrayList(java.net.Proxy.NO_PROXY); 67 } 68 String response = null; 69 String urlString; 70 try { 71 // Strip path and username/password from URI so it's not visible to PAC script. The 72 // path often contains credentials the app does not want exposed to a potentially 73 // malicious PAC script. 74 if (!"http".equalsIgnoreCase(uri.getScheme())) { 75 uri = new URI(uri.getScheme(), null, uri.getHost(), uri.getPort(), "/", null, null); 76 } 77 urlString = uri.toURL().toString(); 78 } catch (URISyntaxException e) { 79 urlString = uri.getHost(); 80 } catch (MalformedURLException e) { 81 urlString = uri.getHost(); 82 } 83 try { 84 response = mProxyService.resolvePacFile(uri.getHost(), urlString); 85 } catch (Exception e) { 86 Log.e(TAG, "Error resolving PAC File", e); 87 } 88 if (response == null) { 89 return mDefaultList; 90 } 91 92 return parseResponse(response); 93 } 94 95 private static List<Proxy> parseResponse(String response) { 96 String[] split = response.split(";"); 97 List<Proxy> ret = Lists.newArrayList(); 98 for (String s : split) { 99 String trimmed = s.trim(); 100 if (trimmed.equals("DIRECT")) { 101 ret.add(java.net.Proxy.NO_PROXY); 102 } else if (trimmed.startsWith(PROXY)) { 103 Proxy proxy = proxyFromHostPort(Type.HTTP, trimmed.substring(PROXY.length())); 104 if (proxy != null) { 105 ret.add(proxy); 106 } 107 } else if (trimmed.startsWith(SOCKS)) { 108 Proxy proxy = proxyFromHostPort(Type.SOCKS, trimmed.substring(SOCKS.length())); 109 if (proxy != null) { 110 ret.add(proxy); 111 } 112 } 113 } 114 if (ret.size() == 0) { 115 ret.add(java.net.Proxy.NO_PROXY); 116 } 117 return ret; 118 } 119 120 private static Proxy proxyFromHostPort(Proxy.Type type, String hostPortString) { 121 try { 122 String[] hostPort = hostPortString.split(":"); 123 String host = hostPort[0]; 124 int port = Integer.parseInt(hostPort[1]); 125 return new Proxy(type, InetSocketAddress.createUnresolved(host, port)); 126 } catch (NumberFormatException|ArrayIndexOutOfBoundsException e) { 127 Log.d(TAG, "Unable to parse proxy " + hostPortString + " " + e); 128 return null; 129 } 130 } 131 132 @Override 133 public void connectFailed(URI uri, SocketAddress address, IOException failure) { 134 135 } 136 137} 138