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