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