Home | History | Annotate | Download | only in net
      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 
     17 package android.net;
     18 
     19 import android.annotation.SdkConstant;
     20 import android.annotation.SdkConstant.SdkConstantType;
     21 import android.content.Context;
     22 import android.text.TextUtils;
     23 import android.util.Log;
     24 
     25 
     26 import org.apache.http.HttpHost;
     27 import org.apache.http.HttpRequest;
     28 import org.apache.http.conn.routing.HttpRoute;
     29 import org.apache.http.conn.routing.HttpRoutePlanner;
     30 import org.apache.http.conn.scheme.SchemeRegistry;
     31 import org.apache.http.protocol.HttpContext;
     32 
     33 import java.net.InetSocketAddress;
     34 import java.net.ProxySelector;
     35 import java.net.URI;
     36 import java.util.List;
     37 import java.util.regex.Matcher;
     38 import java.util.regex.Pattern;
     39 
     40 /**
     41  * A convenience class for accessing the user and default proxy
     42  * settings.
     43  */
     44 public final class Proxy {
     45 
     46     // Set to true to enable extra debugging.
     47     private static final boolean DEBUG = false;
     48     private static final String TAG = "Proxy";
     49 
     50     private static final ProxySelector sDefaultProxySelector;
     51 
     52     /**
     53      * Used to notify an app that's caching the default connection proxy
     54      * that either the default connection or its proxy has changed.
     55      * The intent will have the following extra value:</p>
     56      * <ul>
     57      *   <li><em>EXTRA_PROXY_INFO</em> - The ProxyProperties for the proxy.  Non-null,
     58      *                                   though if the proxy is undefined the host string
     59      *                                   will be empty.
     60      * </ul>
     61      *
     62      * <p class="note">This is a protected intent that can only be sent by the system
     63      */
     64     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     65     public static final String PROXY_CHANGE_ACTION = "android.intent.action.PROXY_CHANGE";
     66     /** {@hide} **/
     67     public static final String EXTRA_PROXY_INFO = "proxy";
     68 
     69     private static ConnectivityManager sConnectivityManager = null;
     70 
     71     // Hostname / IP REGEX validation
     72     // Matches blank input, ips, and domain names
     73     private static final String NAME_IP_REGEX =
     74         "[a-zA-Z0-9]+(\\-[a-zA-Z0-9]+)*(\\.[a-zA-Z0-9]+(\\-[a-zA-Z0-9]+)*)*";
     75 
     76     private static final String HOSTNAME_REGEXP = "^$|^" + NAME_IP_REGEX + "$";
     77 
     78     private static final Pattern HOSTNAME_PATTERN;
     79 
     80     private static final String EXCLLIST_REGEXP = "$|^(.?" + NAME_IP_REGEX
     81         + ")+(,(.?" + NAME_IP_REGEX + "))*$";
     82 
     83     private static final Pattern EXCLLIST_PATTERN;
     84 
     85     static {
     86         HOSTNAME_PATTERN = Pattern.compile(HOSTNAME_REGEXP);
     87         EXCLLIST_PATTERN = Pattern.compile(EXCLLIST_REGEXP);
     88         sDefaultProxySelector = ProxySelector.getDefault();
     89     }
     90 
     91     /**
     92      * Return the proxy object to be used for the URL given as parameter.
     93      * @param ctx A Context used to get the settings for the proxy host.
     94      * @param url A URL to be accessed. Used to evaluate exclusion list.
     95      * @return Proxy (java.net) object containing the host name. If the
     96      *         user did not set a hostname it returns the default host.
     97      *         A null value means that no host is to be used.
     98      * {@hide}
     99      */
    100     public static final java.net.Proxy getProxy(Context ctx, String url) {
    101         String host = "";
    102         if (url != null) {
    103             URI uri = URI.create(url);
    104             host = uri.getHost();
    105         }
    106 
    107         if (!isLocalHost(host)) {
    108             if (sConnectivityManager == null) {
    109                 sConnectivityManager = (ConnectivityManager)ctx.getSystemService(
    110                         Context.CONNECTIVITY_SERVICE);
    111             }
    112             if (sConnectivityManager == null) return java.net.Proxy.NO_PROXY;
    113 
    114             ProxyProperties proxyProperties = sConnectivityManager.getProxy();
    115 
    116             if (proxyProperties != null) {
    117                 if (!proxyProperties.isExcluded(host)) {
    118                     return proxyProperties.makeProxy();
    119                 }
    120             }
    121         }
    122         return java.net.Proxy.NO_PROXY;
    123     }
    124 
    125 
    126     /**
    127      * Return the proxy host set by the user.
    128      * @param ctx A Context used to get the settings for the proxy host.
    129      * @return String containing the host name. If the user did not set a host
    130      *         name it returns the default host. A null value means that no
    131      *         host is to be used.
    132      * @deprecated Use standard java vm proxy values to find the host, port
    133      *         and exclusion list.  This call ignores the exclusion list.
    134      */
    135     public static final String getHost(Context ctx) {
    136         java.net.Proxy proxy = getProxy(ctx, null);
    137         if (proxy == java.net.Proxy.NO_PROXY) return null;
    138         try {
    139             return ((InetSocketAddress)(proxy.address())).getHostName();
    140         } catch (Exception e) {
    141             return null;
    142         }
    143     }
    144 
    145     /**
    146      * Return the proxy port set by the user.
    147      * @param ctx A Context used to get the settings for the proxy port.
    148      * @return The port number to use or -1 if no proxy is to be used.
    149      * @deprecated Use standard java vm proxy values to find the host, port
    150      *         and exclusion list.  This call ignores the exclusion list.
    151      */
    152     public static final int getPort(Context ctx) {
    153         java.net.Proxy proxy = getProxy(ctx, null);
    154         if (proxy == java.net.Proxy.NO_PROXY) return -1;
    155         try {
    156             return ((InetSocketAddress)(proxy.address())).getPort();
    157         } catch (Exception e) {
    158             return -1;
    159         }
    160     }
    161 
    162     /**
    163      * Return the default proxy host specified by the carrier.
    164      * @return String containing the host name or null if there is no proxy for
    165      * this carrier.
    166      * @deprecated Use standard java vm proxy values to find the host, port and
    167      *         exclusion list.  This call ignores the exclusion list and no
    168      *         longer reports only mobile-data apn-based proxy values.
    169      */
    170     public static final String getDefaultHost() {
    171         String host = System.getProperty("http.proxyHost");
    172         if (TextUtils.isEmpty(host)) return null;
    173         return host;
    174     }
    175 
    176     /**
    177      * Return the default proxy port specified by the carrier.
    178      * @return The port number to be used with the proxy host or -1 if there is
    179      * no proxy for this carrier.
    180      * @deprecated Use standard java vm proxy values to find the host, port and
    181      *         exclusion list.  This call ignores the exclusion list and no
    182      *         longer reports only mobile-data apn-based proxy values.
    183      */
    184     public static final int getDefaultPort() {
    185         if (getDefaultHost() == null) return -1;
    186         try {
    187             return Integer.parseInt(System.getProperty("http.proxyPort"));
    188         } catch (NumberFormatException e) {
    189             return -1;
    190         }
    191     }
    192 
    193     /**
    194      * Returns the preferred proxy to be used by clients. This is a wrapper
    195      * around {@link android.net.Proxy#getHost()}.
    196      *
    197      * @param context the context which will be passed to
    198      * {@link android.net.Proxy#getHost()}
    199      * @param url the target URL for the request
    200      * @note Calling this method requires permission
    201      * android.permission.ACCESS_NETWORK_STATE
    202      * @return The preferred proxy to be used by clients, or null if there
    203      * is no proxy.
    204      * {@hide}
    205      */
    206     public static final HttpHost getPreferredHttpHost(Context context,
    207             String url) {
    208         java.net.Proxy prefProxy = getProxy(context, url);
    209         if (prefProxy.equals(java.net.Proxy.NO_PROXY)) {
    210             return null;
    211         } else {
    212             InetSocketAddress sa = (InetSocketAddress)prefProxy.address();
    213             return new HttpHost(sa.getHostName(), sa.getPort(), "http");
    214         }
    215     }
    216 
    217     private static final boolean isLocalHost(String host) {
    218         if (host == null) {
    219             return false;
    220         }
    221         try {
    222             if (host != null) {
    223                 if (host.equalsIgnoreCase("localhost")) {
    224                     return true;
    225                 }
    226                 if (NetworkUtils.numericToInetAddress(host).isLoopbackAddress()) {
    227                     return true;
    228                 }
    229             }
    230         } catch (IllegalArgumentException iex) {
    231         }
    232         return false;
    233     }
    234 
    235     /**
    236      * Validate syntax of hostname, port and exclusion list entries
    237      * {@hide}
    238      */
    239     public static void validate(String hostname, String port, String exclList) {
    240         Matcher match = HOSTNAME_PATTERN.matcher(hostname);
    241         Matcher listMatch = EXCLLIST_PATTERN.matcher(exclList);
    242 
    243         if (!match.matches()) {
    244             throw new IllegalArgumentException();
    245         }
    246 
    247         if (!listMatch.matches()) {
    248             throw new IllegalArgumentException();
    249         }
    250 
    251         if (hostname.length() > 0 && port.length() == 0) {
    252             throw new IllegalArgumentException();
    253         }
    254 
    255         if (port.length() > 0) {
    256             if (hostname.length() == 0) {
    257                 throw new IllegalArgumentException();
    258             }
    259             int portVal = -1;
    260             try {
    261                 portVal = Integer.parseInt(port);
    262             } catch (NumberFormatException ex) {
    263                 throw new IllegalArgumentException();
    264             }
    265             if (portVal <= 0 || portVal > 0xFFFF) {
    266                 throw new IllegalArgumentException();
    267             }
    268         }
    269     }
    270 
    271     static class AndroidProxySelectorRoutePlanner
    272             extends org.apache.http.impl.conn.ProxySelectorRoutePlanner {
    273 
    274         private Context mContext;
    275 
    276         public AndroidProxySelectorRoutePlanner(SchemeRegistry schreg, ProxySelector prosel,
    277                 Context context) {
    278             super(schreg, prosel);
    279             mContext = context;
    280         }
    281 
    282         @Override
    283         protected java.net.Proxy chooseProxy(List<java.net.Proxy> proxies, HttpHost target,
    284                 HttpRequest request, HttpContext context) {
    285             return getProxy(mContext, target.getHostName());
    286         }
    287 
    288         @Override
    289         protected HttpHost determineProxy(HttpHost target, HttpRequest request,
    290                 HttpContext context) {
    291             return getPreferredHttpHost(mContext, target.getHostName());
    292         }
    293 
    294         @Override
    295         public HttpRoute determineRoute(HttpHost target, HttpRequest request,
    296                 HttpContext context) {
    297             HttpHost proxy = getPreferredHttpHost(mContext, target.getHostName());
    298             if (proxy == null) {
    299                 return new HttpRoute(target);
    300             } else {
    301                 return new HttpRoute(target, null, proxy, false);
    302             }
    303         }
    304     }
    305 
    306     /** @hide */
    307     public static final HttpRoutePlanner getAndroidProxySelectorRoutePlanner(Context context) {
    308         AndroidProxySelectorRoutePlanner ret = new AndroidProxySelectorRoutePlanner(
    309                 new SchemeRegistry(), ProxySelector.getDefault(), context);
    310         return ret;
    311     }
    312 
    313     /** @hide */
    314     public static final void setHttpProxySystemProperty(ProxyProperties p) {
    315         String host = null;
    316         String port = null;
    317         String exclList = null;
    318         String pacFileUrl = null;
    319         if (p != null) {
    320             host = p.getHost();
    321             port = Integer.toString(p.getPort());
    322             exclList = p.getExclusionList();
    323             pacFileUrl = p.getPacFileUrl();
    324         }
    325         setHttpProxySystemProperty(host, port, exclList, pacFileUrl);
    326     }
    327 
    328     /** @hide */
    329     public static final void setHttpProxySystemProperty(String host, String port, String exclList,
    330             String pacFileUrl) {
    331         if (exclList != null) exclList = exclList.replace(",", "|");
    332         if (false) Log.d(TAG, "setHttpProxySystemProperty :"+host+":"+port+" - "+exclList);
    333         if (host != null) {
    334             System.setProperty("http.proxyHost", host);
    335             System.setProperty("https.proxyHost", host);
    336         } else {
    337             System.clearProperty("http.proxyHost");
    338             System.clearProperty("https.proxyHost");
    339         }
    340         if (port != null) {
    341             System.setProperty("http.proxyPort", port);
    342             System.setProperty("https.proxyPort", port);
    343         } else {
    344             System.clearProperty("http.proxyPort");
    345             System.clearProperty("https.proxyPort");
    346         }
    347         if (exclList != null) {
    348             System.setProperty("http.nonProxyHosts", exclList);
    349             System.setProperty("https.nonProxyHosts", exclList);
    350         } else {
    351             System.clearProperty("http.nonProxyHosts");
    352             System.clearProperty("https.nonProxyHosts");
    353         }
    354         if (!TextUtils.isEmpty(pacFileUrl)) {
    355             ProxySelector.setDefault(new PacProxySelector());
    356         } else {
    357             ProxySelector.setDefault(sDefaultProxySelector);
    358         }
    359     }
    360 }
    361