/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package java.net; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.io.IOException; import java.security.AccessController; import java.util.ArrayList; import java.util.List; import java.util.Properties; import org.apache.harmony.luni.util.Msg; import org.apache.harmony.luni.util.PriviAction; /** * Default implementation for {@code ProxySelector}. */ @SuppressWarnings("unchecked") class ProxySelectorImpl extends ProxySelector { private static final int HTTP_PROXY_PORT = 80; private static final int HTTPS_PROXY_PORT = 443; private static final int FTP_PROXY_PORT = 80; private static final int SOCKS_PROXY_PORT = 1080; // Net properties read from net.properties file. private static Properties netProps = null; // read net.properties file static { AccessController.doPrivileged(new java.security.PrivilegedAction() { public Object run() { File f = new File(System.getProperty("java.home") //$NON-NLS-1$ + File.separator + "lib" + File.separator //$NON-NLS-1$ + "net.properties"); //$NON-NLS-1$ if (f.exists()) { try { FileInputStream fis = new FileInputStream(f); // BEGIN android-modified InputStream is = new BufferedInputStream(fis, 8192); // END android-modified netProps = new Properties(); netProps.load(is); is.close(); } catch (IOException e) { } } return null; } }); } public ProxySelectorImpl() { super(); } @Override public void connectFailed(URI uri, SocketAddress sa, IOException ioe) { if (null == uri || null == sa || null == ioe) { // "KA001=Argument must not be null" throw new IllegalArgumentException(Msg.getString("KA001")); //$NON-NLS-1$ } } @Override public List<Proxy> select(URI uri) { // argument check if (null == uri) { // KA001=Argument must not be null throw new IllegalArgumentException(Msg.getString("KA001")); //$NON-NLS-1$ } // check scheme String scheme = uri.getScheme(); if (null == scheme) { throw new IllegalArgumentException(); } String host = uri.getHost(); Proxy proxy = Proxy.NO_PROXY; if ("http".equals(scheme)) { //$NON-NLS-1$ proxy = selectHttpProxy(host); } else if ("https".equals(scheme)) { //$NON-NLS-1$ proxy = selectHttpsProxy(); } else if ("ftp".equals(scheme)) { //$NON-NLS-1$ proxy = selectFtpProxy(host); } else if ("socket".equals(scheme)) { //$NON-NLS-1$ proxy = selectSocksProxy(); } List<Proxy> proxyList = new ArrayList<Proxy>(1); proxyList.add(proxy); return proxyList; } /* * Gets proxy for http request. 1. gets from "http.proxyHost", then gets * port from "http.proxyPort", or from "proxyPort" if "http.proxyPort" is * unavailable. 2. gets from "proxyHost" if 1 is unavailable,then get port * from "proxyPort", or from "http.proxyPort" if "proxyPort" is unavailable. * 3. gets from "socksProxyHost" if 2 is unavailable. */ private Proxy selectHttpProxy(String uriHost) { String host; String port = null; Proxy.Type type = Proxy.Type.DIRECT; String nonProxyHosts = getSystemProperty("http.nonProxyHosts"); //$NON-NLS-1$ // if host is in non proxy host list, returns Proxy.NO_PROXY if (isNonProxyHost(uriHost, nonProxyHosts)) { return Proxy.NO_PROXY; } host = getSystemProperty("http.proxyHost"); //$NON-NLS-1$ if (null != host) { // case 1: http.proxyHost is set, use exact http proxy type = Proxy.Type.HTTP; port = getSystemPropertyOrAlternative("http.proxyPort", //$NON-NLS-1$ "proxyPort", String.valueOf(HTTP_PROXY_PORT)); //$NON-NLS-1$ } else if ((host = getSystemProperty("proxyHost", null)) != null) { //$NON-NLS-1$ // case 2: proxyHost is set, use exact http proxy type = Proxy.Type.HTTP; port = getSystemPropertyOrAlternative("proxyPort", //$NON-NLS-1$ "http.proxyPort", String.valueOf(HTTP_PROXY_PORT)); //$NON-NLS-1$ } else if ((host = getSystemProperty("socksProxyHost")) != null) { //$NON-NLS-1$ // case 3: use socks proxy instead type = Proxy.Type.SOCKS; port = getSystemProperty( "socksProxyPort", String.valueOf(SOCKS_PROXY_PORT)); //$NON-NLS-1$ } int defaultPort = (type == Proxy.Type.SOCKS) ? SOCKS_PROXY_PORT : HTTP_PROXY_PORT; return createProxy(type, host, port, defaultPort); } /* * Gets proxy for https request. */ private Proxy selectHttpsProxy() { String host; String port = null; Proxy.Type type = Proxy.Type.DIRECT; host = getSystemProperty("https.proxyHost"); //$NON-NLS-1$ if (null != host) { // case 1: use exact https proxy type = Proxy.Type.HTTP; port = getSystemProperty( "https.proxyPort", String.valueOf(HTTPS_PROXY_PORT)); //$NON-NLS-1$ } else { host = getSystemProperty("socksProxyHost"); //$NON-NLS-1$ if (null != host) { // case 2: use socks proxy instead type = Proxy.Type.SOCKS; port = getSystemProperty( "socksProxyPort", String.valueOf(SOCKS_PROXY_PORT)); //$NON-NLS-1$ } } int defaultPort = (type == Proxy.Type.SOCKS) ? SOCKS_PROXY_PORT : HTTPS_PROXY_PORT; return createProxy(type, host, port, defaultPort); } /* * Gets proxy for ftp request. */ private Proxy selectFtpProxy(String uriHost) { String host; String port = null; Proxy.Type type = Proxy.Type.DIRECT; String nonProxyHosts = getSystemProperty("ftp.nonProxyHosts"); //$NON-NLS-1$ // if host is in non proxy host list, returns Proxy.NO_PROXY if (isNonProxyHost(uriHost, nonProxyHosts)) { return Proxy.NO_PROXY; } host = getSystemProperty("ftp.proxyHost"); //$NON-NLS-1$ if (null != host) { // case 1: use exact ftp proxy type = Proxy.Type.HTTP; port = getSystemProperty( "ftp.proxyPort", String.valueOf(FTP_PROXY_PORT)); //$NON-NLS-1$ } else { host = getSystemProperty("socksProxyHost"); //$NON-NLS-1$ if (null != host) { // case 2: use socks proxy instead type = Proxy.Type.SOCKS; port = getSystemProperty( "socksProxyPort", String.valueOf(SOCKS_PROXY_PORT)); //$NON-NLS-1$ } } int defaultPort = (type == Proxy.Type.SOCKS) ? SOCKS_PROXY_PORT : FTP_PROXY_PORT; return createProxy(type, host, port, defaultPort); } /* * Gets proxy for socks request. */ private Proxy selectSocksProxy() { String host; String port = null; Proxy.Type type = Proxy.Type.DIRECT; host = getSystemProperty("socksProxyHost"); //$NON-NLS-1$ if (null != host) { type = Proxy.Type.SOCKS; port = getSystemProperty( "socksProxyPort", String.valueOf(SOCKS_PROXY_PORT)); //$NON-NLS-1$ } return createProxy(type, host, port, SOCKS_PROXY_PORT); } /* * checks whether the host needs proxy. return true if it doesn't need a * proxy. */ private boolean isNonProxyHost(String host, String nonProxyHosts) { // nonProxyHosts is not set if (null == host || null == nonProxyHosts) { return false; } // Construct regex expression of nonProxyHosts int length = nonProxyHosts.length(); char ch; StringBuilder buf = new StringBuilder(length); for (int i = 0; i < nonProxyHosts.length(); i++) { ch = nonProxyHosts.charAt(i); switch (ch) { case '.': buf.append("\\."); //$NON-NLS-1$ break; case '*': buf.append(".*"); //$NON-NLS-1$ break; default: buf.append(ch); } } String nonProxyHostsReg = buf.toString(); // check whether the host is the nonProxyHosts. return host.matches(nonProxyHostsReg); } /* * Create Proxy by "type","host" and "port". */ private Proxy createProxy(Proxy.Type type, String host, String port, int defaultPort) { Proxy proxy; if (type == Proxy.Type.DIRECT) { proxy = Proxy.NO_PROXY; } else { int iPort; try { // BEGIN android-changed iPort = Integer.parseInt(port); // END android-changed } catch (NumberFormatException e) { iPort = defaultPort; } proxy = new Proxy(type, InetSocketAddress.createUnresolved(host, iPort)); } return proxy; } /* * gets system property, privileged operation. If the value of the property * is null or empty String, it returns defaultValue. */ private String getSystemProperty(final String property) { return getSystemProperty(property, null); } /* * gets system property, privileged operation. If the value of the property * is null or empty String, it returns defaultValue. */ private String getSystemProperty(final String property, final String defaultValue) { String value = AccessController.doPrivileged(new PriviAction<String>( property)); if (null == value || "".equals(value)) { //$NON-NLS-1$ value = (netProps != null) ? netProps.getProperty(property, defaultValue) : defaultValue; } return value; } /* * gets system property, privileged operation. If the value of "key" * property is null, then retrieve value from "alternative" property. * Finally, if the value is null or empty String, it returns defaultValue. */ private String getSystemPropertyOrAlternative(final String key, final String alternativeKey, final String defaultValue) { String value = getSystemProperty(key); if (value == null) { value = getSystemProperty(alternativeKey); if (null == value) { value = defaultValue; } } return value; } }