ProxySelectorImpl.java revision 4fefecee9d4a5d2a4510f516b4015607b19e8d09
1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements.  See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License.  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 */
16package java.net;
17
18import java.io.BufferedInputStream;
19import java.io.File;
20import java.io.FileInputStream;
21import java.io.InputStream;
22import java.io.IOException;
23import java.security.AccessController;
24import java.util.ArrayList;
25import java.util.List;
26import java.util.Properties;
27
28import org.apache.harmony.luni.util.Msg;
29import org.apache.harmony.luni.util.PriviAction;
30
31/**
32 * Default implementation for {@code ProxySelector}.
33 */
34@SuppressWarnings("unchecked")
35class ProxySelectorImpl extends ProxySelector {
36
37    private static final int HTTP_PROXY_PORT = 80;
38
39    private static final int HTTPS_PROXY_PORT = 443;
40
41    private static final int FTP_PROXY_PORT = 80;
42
43    private static final int SOCKS_PROXY_PORT = 1080;
44
45    // Net properties read from net.properties file.
46    private static Properties netProps = null;
47
48    // read net.properties file
49    static {
50        AccessController.doPrivileged(new java.security.PrivilegedAction() {
51            public Object run() {
52                File f = new File(System.getProperty("java.home") //$NON-NLS-1$
53                        + File.separator + "lib" + File.separator //$NON-NLS-1$
54                        + "net.properties"); //$NON-NLS-1$
55
56                if (f.exists()) {
57                    try {
58                        FileInputStream fis = new FileInputStream(f);
59                        // BEGIN android-modified
60                        InputStream is = new BufferedInputStream(fis, 8192);
61                        // END android-modified
62                        netProps = new Properties();
63                        netProps.load(is);
64                        is.close();
65                    } catch (IOException e) {
66                    }
67                }
68                return null;
69            }
70        });
71    }
72
73    public ProxySelectorImpl() {
74        super();
75    }
76
77    @Override
78    public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
79        if (null == uri || null == sa || null == ioe) {
80            // "KA001=Argument must not be null"
81            throw new IllegalArgumentException(Msg.getString("KA001")); //$NON-NLS-1$
82        }
83    }
84
85    @Override
86    public List<Proxy> select(URI uri) {
87        // argument check
88        if (null == uri) {
89            // KA001=Argument must not be null
90            throw new IllegalArgumentException(Msg.getString("KA001")); //$NON-NLS-1$
91        }
92        // check scheme
93        String scheme = uri.getScheme();
94        if (null == scheme) {
95            throw new IllegalArgumentException();
96        }
97
98        String host = uri.getHost();
99        Proxy proxy = Proxy.NO_PROXY;
100
101        if ("http".equals(scheme)) { //$NON-NLS-1$
102            proxy = selectHttpProxy(host);
103        } else if ("https".equals(scheme)) { //$NON-NLS-1$
104            proxy = selectHttpsProxy();
105        } else if ("ftp".equals(scheme)) { //$NON-NLS-1$
106            proxy = selectFtpProxy(host);
107        } else if ("socket".equals(scheme)) { //$NON-NLS-1$
108            proxy = selectSocksProxy();
109        }
110        List<Proxy> proxyList = new ArrayList<Proxy>(1);
111        proxyList.add(proxy);
112        return proxyList;
113    }
114
115    /*
116     * Gets proxy for http request. 1. gets from "http.proxyHost", then gets
117     * port from "http.proxyPort", or from "proxyPort" if "http.proxyPort" is
118     * unavailable. 2. gets from "proxyHost" if 1 is unavailable,then get port
119     * from "proxyPort", or from "http.proxyPort" if "proxyPort" is unavailable.
120     * 3. gets from "socksProxyHost" if 2 is unavailable.
121     */
122
123    private Proxy selectHttpProxy(String uriHost) {
124        String host;
125        String port = null;
126        Proxy.Type type = Proxy.Type.DIRECT;
127
128        String nonProxyHosts = getSystemProperty("http.nonProxyHosts"); //$NON-NLS-1$
129        // if host is in non proxy host list, returns Proxy.NO_PROXY
130        if (isNonProxyHost(uriHost, nonProxyHosts)) {
131            return Proxy.NO_PROXY;
132        }
133
134        host = getSystemProperty("http.proxyHost"); //$NON-NLS-1$
135        if (null != host) {
136            // case 1: http.proxyHost is set, use exact http proxy
137            type = Proxy.Type.HTTP;
138            port = getSystemPropertyOrAlternative("http.proxyPort", //$NON-NLS-1$
139                    "proxyPort", String.valueOf(HTTP_PROXY_PORT)); //$NON-NLS-1$
140        } else if ((host = getSystemProperty("proxyHost", null)) != null) { //$NON-NLS-1$
141            // case 2: proxyHost is set, use exact http proxy
142            type = Proxy.Type.HTTP;
143            port = getSystemPropertyOrAlternative("proxyPort", //$NON-NLS-1$
144                    "http.proxyPort", String.valueOf(HTTP_PROXY_PORT)); //$NON-NLS-1$
145
146        } else if ((host = getSystemProperty("socksProxyHost")) != null) { //$NON-NLS-1$
147            // case 3: use socks proxy instead
148            type = Proxy.Type.SOCKS;
149            port = getSystemProperty(
150                    "socksProxyPort", String.valueOf(SOCKS_PROXY_PORT)); //$NON-NLS-1$
151        }
152        int defaultPort = (type == Proxy.Type.SOCKS) ? SOCKS_PROXY_PORT
153                : HTTP_PROXY_PORT;
154        return createProxy(type, host, port, defaultPort);
155    }
156
157    /*
158     * Gets proxy for https request.
159     */
160    private Proxy selectHttpsProxy() {
161        String host;
162        String port = null;
163        Proxy.Type type = Proxy.Type.DIRECT;
164
165        host = getSystemProperty("https.proxyHost"); //$NON-NLS-1$
166        if (null != host) {
167            // case 1: use exact https proxy
168            type = Proxy.Type.HTTP;
169            port = getSystemProperty(
170                    "https.proxyPort", String.valueOf(HTTPS_PROXY_PORT)); //$NON-NLS-1$
171        } else {
172            host = getSystemProperty("socksProxyHost"); //$NON-NLS-1$
173            if (null != host) {
174                // case 2: use socks proxy instead
175                type = Proxy.Type.SOCKS;
176                port = getSystemProperty(
177                        "socksProxyPort", String.valueOf(SOCKS_PROXY_PORT)); //$NON-NLS-1$
178            }
179        }
180        int defaultPort = (type == Proxy.Type.SOCKS) ? SOCKS_PROXY_PORT
181                : HTTPS_PROXY_PORT;
182        return createProxy(type, host, port, defaultPort);
183    }
184
185    /*
186     * Gets proxy for ftp request.
187     */
188    private Proxy selectFtpProxy(String uriHost) {
189        String host;
190        String port = null;
191        Proxy.Type type = Proxy.Type.DIRECT;
192        String nonProxyHosts = getSystemProperty("ftp.nonProxyHosts"); //$NON-NLS-1$
193        // if host is in non proxy host list, returns Proxy.NO_PROXY
194        if (isNonProxyHost(uriHost, nonProxyHosts)) {
195            return Proxy.NO_PROXY;
196        }
197
198        host = getSystemProperty("ftp.proxyHost"); //$NON-NLS-1$
199        if (null != host) {
200            // case 1: use exact ftp proxy
201            type = Proxy.Type.HTTP;
202            port = getSystemProperty(
203                    "ftp.proxyPort", String.valueOf(FTP_PROXY_PORT)); //$NON-NLS-1$
204        } else {
205            host = getSystemProperty("socksProxyHost"); //$NON-NLS-1$
206            if (null != host) {
207                // case 2: use socks proxy instead
208                type = Proxy.Type.SOCKS;
209                port = getSystemProperty(
210                        "socksProxyPort", String.valueOf(SOCKS_PROXY_PORT)); //$NON-NLS-1$
211            }
212        }
213        int defaultPort = (type == Proxy.Type.SOCKS) ? SOCKS_PROXY_PORT
214                : FTP_PROXY_PORT;
215        return createProxy(type, host, port, defaultPort);
216    }
217
218    /*
219     * Gets proxy for socks request.
220     */
221    private Proxy selectSocksProxy() {
222        String host;
223        String port = null;
224        Proxy.Type type = Proxy.Type.DIRECT;
225
226        host = getSystemProperty("socksProxyHost"); //$NON-NLS-1$
227        if (null != host) {
228            type = Proxy.Type.SOCKS;
229            port = getSystemProperty(
230                    "socksProxyPort", String.valueOf(SOCKS_PROXY_PORT)); //$NON-NLS-1$
231        }
232        return createProxy(type, host, port, SOCKS_PROXY_PORT);
233    }
234
235    /*
236     * checks whether the host needs proxy. return true if it doesn't need a
237     * proxy.
238     */
239    private boolean isNonProxyHost(String host, String nonProxyHosts) {
240        // nonProxyHosts is not set
241        if (null == host || null == nonProxyHosts) {
242            return false;
243        }
244        // Construct regex expression of nonProxyHosts
245        int length = nonProxyHosts.length();
246        char ch;
247        StringBuilder buf = new StringBuilder(length);
248        for (int i = 0; i < nonProxyHosts.length(); i++) {
249            ch = nonProxyHosts.charAt(i);
250            switch (ch) {
251                case '.':
252                    buf.append("\\."); //$NON-NLS-1$
253                    break;
254                case '*':
255                    buf.append(".*"); //$NON-NLS-1$
256                    break;
257                default:
258                    buf.append(ch);
259            }
260        }
261        String nonProxyHostsReg = buf.toString();
262        // check whether the host is the nonProxyHosts.
263        return host.matches(nonProxyHostsReg);
264    }
265
266    /*
267     * Create Proxy by "type","host" and "port".
268     */
269    private Proxy createProxy(Proxy.Type type, String host, String port,
270            int defaultPort) {
271        Proxy proxy;
272        if (type == Proxy.Type.DIRECT) {
273            proxy = Proxy.NO_PROXY;
274        } else {
275            int iPort;
276            try {
277                // BEGIN android-changed
278                iPort = Integer.parseInt(port);
279                // END android-changed
280            } catch (NumberFormatException e) {
281                iPort = defaultPort;
282            }
283            proxy = new Proxy(type, InetSocketAddress.createUnresolved(host,
284                    iPort));
285        }
286        return proxy;
287    }
288
289    /*
290     * gets system property, privileged operation. If the value of the property
291     * is null or empty String, it returns defaultValue.
292     */
293    private String getSystemProperty(final String property) {
294        return getSystemProperty(property, null);
295    }
296
297    /*
298     * gets system property, privileged operation. If the value of the property
299     * is null or empty String, it returns defaultValue.
300     */
301    private String getSystemProperty(final String property,
302            final String defaultValue) {
303        String value = AccessController.doPrivileged(new PriviAction<String>(
304                property));
305        if (null == value || "".equals(value)) { //$NON-NLS-1$
306            value = (netProps != null)
307                    ? netProps.getProperty(property, defaultValue)
308                    : defaultValue;
309        }
310        return value;
311    }
312
313    /*
314     * gets system property, privileged operation. If the value of "key"
315     * property is null, then retrieve value from "alternative" property.
316     * Finally, if the value is null or empty String, it returns defaultValue.
317     */
318    private String getSystemPropertyOrAlternative(final String key,
319            final String alternativeKey, final String defaultValue) {
320        String value = getSystemProperty(key);
321        if (value == null) {
322            value = getSystemProperty(alternativeKey);
323            if (null == value) {
324                value = defaultValue;
325            }
326        }
327        return value;
328    }
329}
330