Save This Page
Home » openjdk-7 » sun » net » spi » [javadoc | source]
    1   /*
    2    * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Oracle designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Oracle in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   22    * or visit www.oracle.com if you need additional information or have any
   23    * questions.
   24    */
   25   
   26   package sun.net.spi;
   27   
   28   import java.net.InetSocketAddress;
   29   import java.net.Proxy;
   30   import java.net.ProxySelector;
   31   import java.net.SocketAddress;
   32   import java.net.URI;
   33   import java.util.ArrayList;
   34   import java.util.List;
   35   import java.util.StringTokenizer;
   36   import java.io.IOException;
   37   import sun.misc.RegexpPool;
   38   import java.security.AccessController;
   39   import java.security.PrivilegedAction;
   40   import sun.net.NetProperties;
   41   import sun.net.SocksProxy;
   42   
   43   /**
   44    * Supports proxy settings using system properties This proxy selector
   45    * provides backward compatibility with the old http protocol handler
   46    * as far as how proxy is set
   47    *
   48    * Most of the implementation copied from the old http protocol handler
   49    *
   50    * Supports http/https/ftp.proxyHost, http/https/ftp.proxyPort,
   51    * proxyHost, proxyPort, and http/https/ftp.nonProxyHost, and socks.
   52    * NOTE: need to do gopher as well
   53    */
   54   public class DefaultProxySelector extends ProxySelector {
   55   
   56       /**
   57        * This is where we define all the valid System Properties we have to
   58        * support for each given protocol.
   59        * The format of this 2 dimensional array is :
   60        * - 1 row per protocol (http, ftp, ...)
   61        * - 1st element of each row is the protocol name
   62        * - subsequent elements are prefixes for Host & Port properties
   63        *   listed in order of priority.
   64        * Example:
   65        * {"ftp", "ftp.proxy", "ftpProxy", "proxy", "socksProxy"},
   66        * means for FTP we try in that oder:
   67        *          + ftp.proxyHost & ftp.proxyPort
   68        *          + ftpProxyHost & ftpProxyPort
   69        *          + proxyHost & proxyPort
   70        *          + socksProxyHost & socksProxyPort
   71        *
   72        * Note that the socksProxy should *always* be the last on the list
   73        */
   74       final static String[][] props = {
   75           /*
   76            * protocol, Property prefix 1, Property prefix 2, ...
   77            */
   78           {"http", "http.proxy", "proxy", "socksProxy"},
   79           {"https", "https.proxy", "proxy", "socksProxy"},
   80           {"ftp", "ftp.proxy", "ftpProxy", "proxy", "socksProxy"},
   81           {"gopher", "gopherProxy", "socksProxy"},
   82           {"socket", "socksProxy"}
   83       };
   84   
   85       private static final String SOCKS_PROXY_VERSION = "socksProxyVersion";
   86   
   87       private static boolean hasSystemProxies = false;
   88   
   89       static {
   90           final String key = "java.net.useSystemProxies";
   91           Boolean b = AccessController.doPrivileged(
   92               new PrivilegedAction<Boolean>() {
   93                   public Boolean run() {
   94                       return NetProperties.getBoolean(key);
   95                   }});
   96           if (b != null && b.booleanValue()) {
   97               java.security.AccessController.doPrivileged(
   98                         new sun.security.action.LoadLibraryAction("net"));
   99               hasSystemProxies = init();
  100           }
  101       }
  102   
  103       /**
  104        * How to deal with "non proxy hosts":
  105        * since we do have to generate a RegexpPool we don't want to do that if
  106        * it's not necessary. Therefore we do cache the result, on a per-protocol
  107        * basis, and change it only when the "source", i.e. the system property,
  108        * did change.
  109        */
  110   
  111       static class NonProxyInfo {
  112           // Default value for nonProxyHosts, this provides backward compatibility
  113           // by excluding localhost and its litteral notations.
  114           static final String defStringVal = "localhost|127.*|[::1]";
  115   
  116           String hostsSource;
  117           RegexpPool hostsPool;
  118           final String property;
  119           final String defaultVal;
  120           static NonProxyInfo ftpNonProxyInfo = new NonProxyInfo("ftp.nonProxyHosts", null, null, defStringVal);
  121           static NonProxyInfo httpNonProxyInfo = new NonProxyInfo("http.nonProxyHosts", null, null, defStringVal);
  122   
  123           NonProxyInfo(String p, String s, RegexpPool pool, String d) {
  124               property = p;
  125               hostsSource = s;
  126               hostsPool = pool;
  127               defaultVal = d;
  128           }
  129       }
  130   
  131   
  132       /**
  133        * select() method. Where all the hard work is done.
  134        * Build a list of proxies depending on URI.
  135        * Since we're only providing compatibility with the system properties
  136        * from previous releases (see list above), that list will always
  137        * contain 1 single proxy, default being NO_PROXY.
  138        */
  139       public java.util.List<Proxy> select(URI uri) {
  140           if (uri == null) {
  141               throw new IllegalArgumentException("URI can't be null.");
  142           }
  143           String protocol = uri.getScheme();
  144           String host = uri.getHost();
  145   
  146           if (host == null) {
  147               // This is a hack to ensure backward compatibility in two
  148               // cases: 1. hostnames contain non-ascii characters,
  149               // internationalized domain names. in which case, URI will
  150               // return null, see BugID 4957669; 2. Some hostnames can
  151               // contain '_' chars even though it's not supposed to be
  152               // legal, in which case URI will return null for getHost,
  153               // but not for getAuthority() See BugID 4913253
  154               String auth = uri.getAuthority();
  155               if (auth != null) {
  156                   int i;
  157                   i = auth.indexOf('@');
  158                   if (i >= 0) {
  159                       auth = auth.substring(i+1);
  160                   }
  161                   i = auth.lastIndexOf(':');
  162                   if (i >= 0) {
  163                       auth = auth.substring(0,i);
  164                   }
  165                   host = auth;
  166               }
  167           }
  168   
  169           if (protocol == null || host == null) {
  170               throw new IllegalArgumentException("protocol = "+protocol+" host = "+host);
  171           }
  172           List<Proxy> proxyl = new ArrayList<Proxy>(1);
  173   
  174           NonProxyInfo pinfo = null;
  175   
  176           if ("http".equalsIgnoreCase(protocol)) {
  177               pinfo = NonProxyInfo.httpNonProxyInfo;
  178           } else if ("https".equalsIgnoreCase(protocol)) {
  179               // HTTPS uses the same property as HTTP, for backward
  180               // compatibility
  181               pinfo = NonProxyInfo.httpNonProxyInfo;
  182           } else if ("ftp".equalsIgnoreCase(protocol)) {
  183               pinfo = NonProxyInfo.ftpNonProxyInfo;
  184           }
  185   
  186           /**
  187            * Let's check the System properties for that protocol
  188            */
  189           final String proto = protocol;
  190           final NonProxyInfo nprop = pinfo;
  191           final String urlhost = host.toLowerCase();
  192   
  193           /**
  194            * This is one big doPrivileged call, but we're trying to optimize
  195            * the code as much as possible. Since we're checking quite a few
  196            * System properties it does help having only 1 call to doPrivileged.
  197            * Be mindful what you do in here though!
  198            */
  199           Proxy p = AccessController.doPrivileged(
  200               new PrivilegedAction<Proxy>() {
  201                   public Proxy run() {
  202                       int i, j;
  203                       String phost =  null;
  204                       int pport = 0;
  205                       String nphosts =  null;
  206                       InetSocketAddress saddr = null;
  207   
  208                       // Then let's walk the list of protocols in our array
  209                       for (i=0; i<props.length; i++) {
  210                           if (props[i][0].equalsIgnoreCase(proto)) {
  211                               for (j = 1; j < props[i].length; j++) {
  212                                   /* System.getProp() will give us an empty
  213                                    * String, "" for a defined but "empty"
  214                                    * property.
  215                                    */
  216                                   phost =  NetProperties.get(props[i][j]+"Host");
  217                                   if (phost != null && phost.length() != 0)
  218                                       break;
  219                               }
  220                               if (phost == null || phost.length() == 0) {
  221                                   /**
  222                                    * No system property defined for that
  223                                    * protocol. Let's check System Proxy
  224                                    * settings (Gnome & Windows) if we were
  225                                    * instructed to.
  226                                    */
  227                                   if (hasSystemProxies) {
  228                                       String sproto;
  229                                       if (proto.equalsIgnoreCase("socket"))
  230                                           sproto = "socks";
  231                                       else
  232                                           sproto = proto;
  233                                       Proxy sproxy = getSystemProxy(sproto, urlhost);
  234                                       if (sproxy != null) {
  235                                           return sproxy;
  236                                       }
  237                                   }
  238                                   return Proxy.NO_PROXY;
  239                               }
  240                               // If a Proxy Host is defined for that protocol
  241                               // Let's get the NonProxyHosts property
  242                               if (nprop != null) {
  243                                   nphosts = NetProperties.get(nprop.property);
  244                                   synchronized (nprop) {
  245                                       if (nphosts == null) {
  246                                           if (nprop.defaultVal != null) {
  247                                               nphosts = nprop.defaultVal;
  248                                           } else {
  249                                               nprop.hostsSource = null;
  250                                               nprop.hostsPool = null;
  251                                           }
  252                                       }
  253                                       if (nphosts != null) {
  254                                           if (!nphosts.equals(nprop.hostsSource)) {
  255                                               RegexpPool pool = new RegexpPool();
  256                                               StringTokenizer st = new StringTokenizer(nphosts, "|", false);
  257                                               try {
  258                                                   while (st.hasMoreTokens()) {
  259                                                       pool.add(st.nextToken().toLowerCase(), Boolean.TRUE);
  260                                                   }
  261                                               } catch (sun.misc.REException ex) {
  262                                               }
  263                                               nprop.hostsPool = pool;
  264                                               nprop.hostsSource = nphosts;
  265                                           }
  266                                       }
  267                                       if (nprop.hostsPool != null &&
  268                                           nprop.hostsPool.match(urlhost) != null) {
  269                                           return Proxy.NO_PROXY;
  270                                       }
  271                                   }
  272                               }
  273                               // We got a host, let's check for port
  274   
  275                               pport = NetProperties.getInteger(props[i][j]+"Port", 0).intValue();
  276                               if (pport == 0 && j < (props[i].length - 1)) {
  277                                   // Can't find a port with same prefix as Host
  278                                   // AND it's not a SOCKS proxy
  279                                   // Let's try the other prefixes for that proto
  280                                   for (int k = 1; k < (props[i].length - 1); k++) {
  281                                       if ((k != j) && (pport == 0))
  282                                           pport = NetProperties.getInteger(props[i][k]+"Port", 0).intValue();
  283                                   }
  284                               }
  285   
  286                               // Still couldn't find a port, let's use default
  287                               if (pport == 0) {
  288                                   if (j == (props[i].length - 1)) // SOCKS
  289                                       pport = defaultPort("socket");
  290                                   else
  291                                       pport = defaultPort(proto);
  292                               }
  293                               // We did find a proxy definition.
  294                               // Let's create the address, but don't resolve it
  295                               // as this will be done at connection time
  296                               saddr = InetSocketAddress.createUnresolved(phost, pport);
  297                               // Socks is *always* the last on the list.
  298                               if (j == (props[i].length - 1)) {
  299                                   int version = NetProperties.getInteger(SOCKS_PROXY_VERSION, 5).intValue();
  300                                   return SocksProxy.create(saddr, version);
  301                               } else {
  302                                   return new Proxy(Proxy.Type.HTTP, saddr);
  303                               }
  304                           }
  305                       }
  306                       return Proxy.NO_PROXY;
  307                   }});
  308   
  309           proxyl.add(p);
  310   
  311           /*
  312            * If no specific property was set for that URI, we should be
  313            * returning an iterator to an empty List.
  314            */
  315           return proxyl;
  316       }
  317   
  318       public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
  319           if (uri == null || sa == null || ioe == null) {
  320               throw new IllegalArgumentException("Arguments can't be null.");
  321           }
  322           // ignored
  323       }
  324   
  325   
  326       private int defaultPort(String protocol) {
  327           if ("http".equalsIgnoreCase(protocol)) {
  328               return 80;
  329           } else if ("https".equalsIgnoreCase(protocol)) {
  330               return 443;
  331           } else if ("ftp".equalsIgnoreCase(protocol)) {
  332               return 80;
  333           } else if ("socket".equalsIgnoreCase(protocol)) {
  334               return 1080;
  335           } else if ("gopher".equalsIgnoreCase(protocol)) {
  336               return 80;
  337           } else {
  338               return -1;
  339           }
  340       }
  341   
  342       private native static boolean init();
  343       private native Proxy getSystemProxy(String protocol, String host);
  344   }

Save This Page
Home » openjdk-7 » sun » net » spi » [javadoc | source]