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