Proxy.java revision 2b4378fef8906b385ee173ebdff9a91d205c7c36
1/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * 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 */
16
17package android.net;
18
19import android.annotation.SdkConstant;
20import android.annotation.SdkConstant.SdkConstantType;
21import android.content.Context;
22import android.text.TextUtils;
23import android.util.Log;
24
25import java.net.InetSocketAddress;
26import java.net.ProxySelector;
27import java.net.URI;
28import java.util.List;
29import java.util.regex.Matcher;
30import java.util.regex.Pattern;
31
32/**
33 * A convenience class for accessing the user and default proxy
34 * settings.
35 */
36public final class Proxy {
37
38    private static final String TAG = "Proxy";
39
40    private static final ProxySelector sDefaultProxySelector;
41
42    /**
43     * Used to notify an app that's caching the default connection proxy
44     * that either the default connection or its proxy has changed.
45     * The intent will have the following extra value:</p>
46     * <ul>
47     *   <li><em>EXTRA_PROXY_INFO</em> - The ProxyProperties for the proxy.  Non-null,
48     *                                   though if the proxy is undefined the host string
49     *                                   will be empty.
50     * </ul>
51     *
52     * <p class="note">This is a protected intent that can only be sent by the system
53     */
54    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
55    public static final String PROXY_CHANGE_ACTION = "android.intent.action.PROXY_CHANGE";
56    /** {@hide} **/
57    public static final String EXTRA_PROXY_INFO = "proxy";
58
59    private static ConnectivityManager sConnectivityManager = null;
60
61    // Hostname / IP REGEX validation
62    // Matches blank input, ips, and domain names
63    private static final String NAME_IP_REGEX =
64        "[a-zA-Z0-9]+(\\-[a-zA-Z0-9]+)*(\\.[a-zA-Z0-9]+(\\-[a-zA-Z0-9]+)*)*";
65
66    private static final String HOSTNAME_REGEXP = "^$|^" + NAME_IP_REGEX + "$";
67
68    private static final Pattern HOSTNAME_PATTERN;
69
70    private static final String EXCLLIST_REGEXP = "$|^(.?" + NAME_IP_REGEX
71        + ")+(,(.?" + NAME_IP_REGEX + "))*$";
72
73    private static final Pattern EXCLLIST_PATTERN;
74
75    static {
76        HOSTNAME_PATTERN = Pattern.compile(HOSTNAME_REGEXP);
77        EXCLLIST_PATTERN = Pattern.compile(EXCLLIST_REGEXP);
78        sDefaultProxySelector = ProxySelector.getDefault();
79    }
80
81    /**
82     * Return the proxy object to be used for the URL given as parameter.
83     * @param ctx A Context used to get the settings for the proxy host.
84     * @param url A URL to be accessed. Used to evaluate exclusion list.
85     * @return Proxy (java.net) object containing the host name. If the
86     *         user did not set a hostname it returns the default host.
87     *         A null value means that no host is to be used.
88     * {@hide}
89     */
90    public static final java.net.Proxy getProxy(Context ctx, String url) {
91        String host = "";
92        if (url != null) {
93            URI uri = URI.create(url);
94            host = uri.getHost();
95        }
96
97        if (!isLocalHost(host)) {
98            if (sConnectivityManager == null) {
99                sConnectivityManager = (ConnectivityManager)ctx.getSystemService(
100                        Context.CONNECTIVITY_SERVICE);
101            }
102            if (sConnectivityManager == null) return java.net.Proxy.NO_PROXY;
103
104            ProxyProperties proxyProperties = sConnectivityManager.getProxy();
105
106            if (proxyProperties != null) {
107                if (!proxyProperties.isExcluded(host)) {
108                    return proxyProperties.makeProxy();
109                }
110            }
111        }
112        return java.net.Proxy.NO_PROXY;
113    }
114
115
116    /**
117     * Return the proxy host set by the user.
118     * @param ctx A Context used to get the settings for the proxy host.
119     * @return String containing the host name. If the user did not set a host
120     *         name it returns the default host. A null value means that no
121     *         host is to be used.
122     * @deprecated Use standard java vm proxy values to find the host, port
123     *         and exclusion list.  This call ignores the exclusion list.
124     */
125    public static final String getHost(Context ctx) {
126        java.net.Proxy proxy = getProxy(ctx, null);
127        if (proxy == java.net.Proxy.NO_PROXY) return null;
128        try {
129            return ((InetSocketAddress)(proxy.address())).getHostName();
130        } catch (Exception e) {
131            return null;
132        }
133    }
134
135    /**
136     * Return the proxy port set by the user.
137     * @param ctx A Context used to get the settings for the proxy port.
138     * @return The port number to use or -1 if no proxy is to be used.
139     * @deprecated Use standard java vm proxy values to find the host, port
140     *         and exclusion list.  This call ignores the exclusion list.
141     */
142    public static final int getPort(Context ctx) {
143        java.net.Proxy proxy = getProxy(ctx, null);
144        if (proxy == java.net.Proxy.NO_PROXY) return -1;
145        try {
146            return ((InetSocketAddress)(proxy.address())).getPort();
147        } catch (Exception e) {
148            return -1;
149        }
150    }
151
152    /**
153     * Return the default proxy host specified by the carrier.
154     * @return String containing the host name or null if there is no proxy for
155     * this carrier.
156     * @deprecated Use standard java vm proxy values to find the host, port and
157     *         exclusion list.  This call ignores the exclusion list and no
158     *         longer reports only mobile-data apn-based proxy values.
159     */
160    public static final String getDefaultHost() {
161        String host = System.getProperty("http.proxyHost");
162        if (TextUtils.isEmpty(host)) return null;
163        return host;
164    }
165
166    /**
167     * Return the default proxy port specified by the carrier.
168     * @return The port number to be used with the proxy host or -1 if there is
169     * no proxy for this carrier.
170     * @deprecated Use standard java vm proxy values to find the host, port and
171     *         exclusion list.  This call ignores the exclusion list and no
172     *         longer reports only mobile-data apn-based proxy values.
173     */
174    public static final int getDefaultPort() {
175        if (getDefaultHost() == null) return -1;
176        try {
177            return Integer.parseInt(System.getProperty("http.proxyPort"));
178        } catch (NumberFormatException e) {
179            return -1;
180        }
181    }
182
183    private static final boolean isLocalHost(String host) {
184        if (host == null) {
185            return false;
186        }
187        try {
188            if (host != null) {
189                if (host.equalsIgnoreCase("localhost")) {
190                    return true;
191                }
192                if (NetworkUtils.numericToInetAddress(host).isLoopbackAddress()) {
193                    return true;
194                }
195            }
196        } catch (IllegalArgumentException iex) {
197        }
198        return false;
199    }
200
201    /**
202     * Validate syntax of hostname, port and exclusion list entries
203     * {@hide}
204     */
205    public static void validate(String hostname, String port, String exclList) {
206        Matcher match = HOSTNAME_PATTERN.matcher(hostname);
207        Matcher listMatch = EXCLLIST_PATTERN.matcher(exclList);
208
209        if (!match.matches()) {
210            throw new IllegalArgumentException();
211        }
212
213        if (!listMatch.matches()) {
214            throw new IllegalArgumentException();
215        }
216
217        if (hostname.length() > 0 && port.length() == 0) {
218            throw new IllegalArgumentException();
219        }
220
221        if (port.length() > 0) {
222            if (hostname.length() == 0) {
223                throw new IllegalArgumentException();
224            }
225            int portVal = -1;
226            try {
227                portVal = Integer.parseInt(port);
228            } catch (NumberFormatException ex) {
229                throw new IllegalArgumentException();
230            }
231            if (portVal <= 0 || portVal > 0xFFFF) {
232                throw new IllegalArgumentException();
233            }
234        }
235    }
236
237    /** @hide */
238    public static final void setHttpProxySystemProperty(ProxyProperties p) {
239        String host = null;
240        String port = null;
241        String exclList = null;
242        String pacFileUrl = null;
243        if (p != null) {
244            host = p.getHost();
245            port = Integer.toString(p.getPort());
246            exclList = p.getExclusionList();
247            pacFileUrl = p.getPacFileUrl();
248        }
249        setHttpProxySystemProperty(host, port, exclList, pacFileUrl);
250    }
251
252    /** @hide */
253    public static final void setHttpProxySystemProperty(String host, String port, String exclList,
254            String pacFileUrl) {
255        if (exclList != null) exclList = exclList.replace(",", "|");
256        if (false) Log.d(TAG, "setHttpProxySystemProperty :"+host+":"+port+" - "+exclList);
257        if (host != null) {
258            System.setProperty("http.proxyHost", host);
259            System.setProperty("https.proxyHost", host);
260        } else {
261            System.clearProperty("http.proxyHost");
262            System.clearProperty("https.proxyHost");
263        }
264        if (port != null) {
265            System.setProperty("http.proxyPort", port);
266            System.setProperty("https.proxyPort", port);
267        } else {
268            System.clearProperty("http.proxyPort");
269            System.clearProperty("https.proxyPort");
270        }
271        if (exclList != null) {
272            System.setProperty("http.nonProxyHosts", exclList);
273            System.setProperty("https.nonProxyHosts", exclList);
274        } else {
275            System.clearProperty("http.nonProxyHosts");
276            System.clearProperty("https.nonProxyHosts");
277        }
278        if (!TextUtils.isEmpty(pacFileUrl)) {
279            ProxySelector.setDefault(new PacProxySelector());
280        } else {
281            ProxySelector.setDefault(sDefaultProxySelector);
282        }
283    }
284}
285