Home » openjdk-7 » java » net » [javadoc | source]

    1   /*
    2    * Copyright (c) 1995, 2006, 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 java.net;
   27   
   28   import java.io.IOException;
   29   import java.io.InputStream;
   30   import java.io.File;
   31   import java.io.OutputStream;
   32   import java.util.Hashtable;
   33   import sun.net.util.IPAddressUtil;
   34   import sun.net.www.ParseUtil;
   35   
   36   /**
   37    * The abstract class <code>URLStreamHandler</code> is the common
   38    * superclass for all stream protocol handlers. A stream protocol
   39    * handler knows how to make a connection for a particular protocol
   40    * type, such as <code>http</code>, <code>ftp</code>, or
   41    * <code>gopher</code>.
   42    * <p>
   43    * In most cases, an instance of a <code>URLStreamHandler</code>
   44    * subclass is not created directly by an application. Rather, the
   45    * first time a protocol name is encountered when constructing a
   46    * <code>URL</code>, the appropriate stream protocol handler is
   47    * automatically loaded.
   48    *
   49    * @author  James Gosling
   50    * @see     java.net.URL#URL(java.lang.String, java.lang.String, int, java.lang.String)
   51    * @since   JDK1.0
   52    */
   53   public abstract class URLStreamHandler {
   54       /**
   55        * Opens a connection to the object referenced by the
   56        * <code>URL</code> argument.
   57        * This method should be overridden by a subclass.
   58        *
   59        * <p>If for the handler's protocol (such as HTTP or JAR), there
   60        * exists a public, specialized URLConnection subclass belonging
   61        * to one of the following packages or one of their subpackages:
   62        * java.lang, java.io, java.util, java.net, the connection
   63        * returned will be of that subclass. For example, for HTTP an
   64        * HttpURLConnection will be returned, and for JAR a
   65        * JarURLConnection will be returned.
   66        *
   67        * @param      u   the URL that this connects to.
   68        * @return     a <code>URLConnection</code> object for the <code>URL</code>.
   69        * @exception  IOException  if an I/O error occurs while opening the
   70        *               connection.
   71        */
   72       abstract protected URLConnection openConnection(URL u) throws IOException;
   73   
   74       /**
   75        * Same as openConnection(URL), except that the connection will be
   76        * made through the specified proxy; Protocol handlers that do not
   77        * support proxying will ignore the proxy parameter and make a
   78        * normal connection.
   79        *
   80        * Calling this method preempts the system's default ProxySelector
   81        * settings.
   82        *
   83        * @param      u   the URL that this connects to.
   84        * @param      p   the proxy through which the connection will be made.
   85        *                 If direct connection is desired, Proxy.NO_PROXY
   86        *                 should be specified.
   87        * @return     a <code>URLConnection</code> object for the <code>URL</code>.
   88        * @exception  IOException  if an I/O error occurs while opening the
   89        *               connection.
   90        * @exception  IllegalArgumentException if either u or p is null,
   91        *               or p has the wrong type.
   92        * @exception  UnsupportedOperationException if the subclass that
   93        *               implements the protocol doesn't support this method.
   94        * @since      1.5
   95        */
   96       protected URLConnection openConnection(URL u, Proxy p) throws IOException {
   97           throw new UnsupportedOperationException("Method not implemented.");
   98       }
   99   
  100       /**
  101        * Parses the string representation of a <code>URL</code> into a
  102        * <code>URL</code> object.
  103        * <p>
  104        * If there is any inherited context, then it has already been
  105        * copied into the <code>URL</code> argument.
  106        * <p>
  107        * The <code>parseURL</code> method of <code>URLStreamHandler</code>
  108        * parses the string representation as if it were an
  109        * <code>http</code> specification. Most URL protocol families have a
  110        * similar parsing. A stream protocol handler for a protocol that has
  111        * a different syntax must override this routine.
  112        *
  113        * @param   u       the <code>URL</code> to receive the result of parsing
  114        *                  the spec.
  115        * @param   spec    the <code>String</code> representing the URL that
  116        *                  must be parsed.
  117        * @param   start   the character index at which to begin parsing. This is
  118        *                  just past the '<code>:</code>' (if there is one) that
  119        *                  specifies the determination of the protocol name.
  120        * @param   limit   the character position to stop parsing at. This is the
  121        *                  end of the string or the position of the
  122        *                  "<code>#</code>" character, if present. All information
  123        *                  after the sharp sign indicates an anchor.
  124        */
  125       protected void parseURL(URL u, String spec, int start, int limit) {
  126           // These fields may receive context content if this was relative URL
  127           String protocol = u.getProtocol();
  128           String authority = u.getAuthority();
  129           String userInfo = u.getUserInfo();
  130           String host = u.getHost();
  131           int port = u.getPort();
  132           String path = u.getPath();
  133           String query = u.getQuery();
  134   
  135           // This field has already been parsed
  136           String ref = u.getRef();
  137   
  138           boolean isRelPath = false;
  139           boolean queryOnly = false;
  140   
  141   // FIX: should not assume query if opaque
  142           // Strip off the query part
  143           if (start < limit) {
  144               int queryStart = spec.indexOf('?');
  145               queryOnly = queryStart == start;
  146               if ((queryStart != -1) && (queryStart < limit)) {
  147                   query = spec.substring(queryStart+1, limit);
  148                   if (limit > queryStart)
  149                       limit = queryStart;
  150                   spec = spec.substring(0, queryStart);
  151               }
  152           }
  153   
  154           int i = 0;
  155           // Parse the authority part if any
  156           boolean isUNCName = (start <= limit - 4) &&
  157                           (spec.charAt(start) == '/') &&
  158                           (spec.charAt(start + 1) == '/') &&
  159                           (spec.charAt(start + 2) == '/') &&
  160                           (spec.charAt(start + 3) == '/');
  161           if (!isUNCName && (start <= limit - 2) && (spec.charAt(start) == '/') &&
  162               (spec.charAt(start + 1) == '/')) {
  163               start += 2;
  164               i = spec.indexOf('/', start);
  165               if (i < 0) {
  166                   i = spec.indexOf('?', start);
  167                   if (i < 0)
  168                       i = limit;
  169               }
  170   
  171               host = authority = spec.substring(start, i);
  172   
  173               int ind = authority.indexOf('@');
  174               if (ind != -1) {
  175                   userInfo = authority.substring(0, ind);
  176                   host = authority.substring(ind+1);
  177               } else {
  178                   userInfo = null;
  179               }
  180               if (host != null) {
  181                   // If the host is surrounded by [ and ] then its an IPv6
  182                   // literal address as specified in RFC2732
  183                   if (host.length()>0 && (host.charAt(0) == '[')) {
  184                       if ((ind = host.indexOf(']')) > 2) {
  185   
  186                           String nhost = host ;
  187                           host = nhost.substring(0,ind+1);
  188                           if (!IPAddressUtil.
  189                               isIPv6LiteralAddress(host.substring(1, ind))) {
  190                               throw new IllegalArgumentException(
  191                                   "Invalid host: "+ host);
  192                           }
  193   
  194                           port = -1 ;
  195                           if (nhost.length() > ind+1) {
  196                               if (nhost.charAt(ind+1) == ':') {
  197                                   ++ind ;
  198                                   // port can be null according to RFC2396
  199                                   if (nhost.length() > (ind + 1)) {
  200                                       port = Integer.parseInt(nhost.substring(ind+1));
  201                                   }
  202                               } else {
  203                                   throw new IllegalArgumentException(
  204                                       "Invalid authority field: " + authority);
  205                               }
  206                           }
  207                       } else {
  208                           throw new IllegalArgumentException(
  209                               "Invalid authority field: " + authority);
  210                       }
  211                   } else {
  212                       ind = host.indexOf(':');
  213                       port = -1;
  214                       if (ind >= 0) {
  215                           // port can be null according to RFC2396
  216                           if (host.length() > (ind + 1)) {
  217                               port = Integer.parseInt(host.substring(ind + 1));
  218                           }
  219                           host = host.substring(0, ind);
  220                       }
  221                   }
  222               } else {
  223                   host = "";
  224               }
  225               if (port < -1)
  226                   throw new IllegalArgumentException("Invalid port number :" +
  227                                                      port);
  228               start = i;
  229               // If the authority is defined then the path is defined by the
  230               // spec only; See RFC 2396 Section 5.2.4.
  231               if (authority != null && authority.length() > 0)
  232                   path = "";
  233           }
  234   
  235           if (host == null) {
  236               host = "";
  237           }
  238   
  239           // Parse the file path if any
  240           if (start < limit) {
  241               if (spec.charAt(start) == '/') {
  242                   path = spec.substring(start, limit);
  243               } else if (path != null && path.length() > 0) {
  244                   isRelPath = true;
  245                   int ind = path.lastIndexOf('/');
  246                   String seperator = "";
  247                   if (ind == -1 && authority != null)
  248                       seperator = "/";
  249                   path = path.substring(0, ind + 1) + seperator +
  250                            spec.substring(start, limit);
  251   
  252               } else {
  253                   String seperator = (authority != null) ? "/" : "";
  254                   path = seperator + spec.substring(start, limit);
  255               }
  256           } else if (queryOnly && path != null) {
  257               int ind = path.lastIndexOf('/');
  258               if (ind < 0)
  259                   ind = 0;
  260               path = path.substring(0, ind) + "/";
  261           }
  262           if (path == null)
  263               path = "";
  264   
  265           if (isRelPath) {
  266               // Remove embedded /./
  267               while ((i = path.indexOf("/./")) >= 0) {
  268                   path = path.substring(0, i) + path.substring(i + 2);
  269               }
  270               // Remove embedded /../ if possible
  271               i = 0;
  272               while ((i = path.indexOf("/../", i)) >= 0) {
  273                   /*
  274                    * A "/../" will cancel the previous segment and itself,
  275                    * unless that segment is a "/../" itself
  276                    * i.e. "/a/b/../c" becomes "/a/c"
  277                    * but "/../../a" should stay unchanged
  278                    */
  279                   if (i > 0 && (limit = path.lastIndexOf('/', i - 1)) >= 0 &&
  280                       (path.indexOf("/../", limit) != 0)) {
  281                       path = path.substring(0, limit) + path.substring(i + 3);
  282                       i = 0;
  283                   } else {
  284                       i = i + 3;
  285                   }
  286               }
  287               // Remove trailing .. if possible
  288               while (path.endsWith("/..")) {
  289                   i = path.indexOf("/..");
  290                   if ((limit = path.lastIndexOf('/', i - 1)) >= 0) {
  291                       path = path.substring(0, limit+1);
  292                   } else {
  293                       break;
  294                   }
  295               }
  296               // Remove starting .
  297               if (path.startsWith("./") && path.length() > 2)
  298                   path = path.substring(2);
  299   
  300               // Remove trailing .
  301               if (path.endsWith("/."))
  302                   path = path.substring(0, path.length() -1);
  303           }
  304   
  305           setURL(u, protocol, host, port, authority, userInfo, path, query, ref);
  306       }
  307   
  308       /**
  309        * Returns the default port for a URL parsed by this handler. This method
  310        * is meant to be overidden by handlers with default port numbers.
  311        * @return the default port for a <code>URL</code> parsed by this handler.
  312        * @since 1.3
  313        */
  314       protected int getDefaultPort() {
  315           return -1;
  316       }
  317   
  318       /**
  319        * Provides the default equals calculation. May be overidden by handlers
  320        * for other protocols that have different requirements for equals().
  321        * This method requires that none of its arguments is null. This is
  322        * guaranteed by the fact that it is only called by java.net.URL class.
  323        * @param u1 a URL object
  324        * @param u2 a URL object
  325        * @return <tt>true</tt> if the two urls are
  326        * considered equal, ie. they refer to the same
  327        * fragment in the same file.
  328        * @since 1.3
  329        */
  330       protected boolean equals(URL u1, URL u2) {
  331           String ref1 = u1.getRef();
  332           String ref2 = u2.getRef();
  333           return (ref1 == ref2 || (ref1 != null && ref1.equals(ref2))) &&
  334                  sameFile(u1, u2);
  335       }
  336   
  337       /**
  338        * Provides the default hash calculation. May be overidden by handlers for
  339        * other protocols that have different requirements for hashCode
  340        * calculation.
  341        * @param u a URL object
  342        * @return an <tt>int</tt> suitable for hash table indexing
  343        * @since 1.3
  344        */
  345       protected int hashCode(URL u) {
  346           int h = 0;
  347   
  348           // Generate the protocol part.
  349           String protocol = u.getProtocol();
  350           if (protocol != null)
  351               h += protocol.hashCode();
  352   
  353           // Generate the host part.
  354           InetAddress addr = getHostAddress(u);
  355           if (addr != null) {
  356               h += addr.hashCode();
  357           } else {
  358               String host = u.getHost();
  359               if (host != null)
  360                   h += host.toLowerCase().hashCode();
  361           }
  362   
  363           // Generate the file part.
  364           String file = u.getFile();
  365           if (file != null)
  366               h += file.hashCode();
  367   
  368           // Generate the port part.
  369           if (u.getPort() == -1)
  370               h += getDefaultPort();
  371           else
  372               h += u.getPort();
  373   
  374           // Generate the ref part.
  375           String ref = u.getRef();
  376           if (ref != null)
  377               h += ref.hashCode();
  378   
  379           return h;
  380       }
  381   
  382       /**
  383        * Compare two urls to see whether they refer to the same file,
  384        * i.e., having the same protocol, host, port, and path.
  385        * This method requires that none of its arguments is null. This is
  386        * guaranteed by the fact that it is only called indirectly
  387        * by java.net.URL class.
  388        * @param u1 a URL object
  389        * @param u2 a URL object
  390        * @return true if u1 and u2 refer to the same file
  391        * @since 1.3
  392        */
  393       protected boolean sameFile(URL u1, URL u2) {
  394           // Compare the protocols.
  395           if (!((u1.getProtocol() == u2.getProtocol()) ||
  396                 (u1.getProtocol() != null &&
  397                  u1.getProtocol().equalsIgnoreCase(u2.getProtocol()))))
  398               return false;
  399   
  400           // Compare the files.
  401           if (!(u1.getFile() == u2.getFile() ||
  402                 (u1.getFile() != null && u1.getFile().equals(u2.getFile()))))
  403               return false;
  404   
  405           // Compare the ports.
  406           int port1, port2;
  407           port1 = (u1.getPort() != -1) ? u1.getPort() : u1.handler.getDefaultPort();
  408           port2 = (u2.getPort() != -1) ? u2.getPort() : u2.handler.getDefaultPort();
  409           if (port1 != port2)
  410               return false;
  411   
  412           // Compare the hosts.
  413           if (!hostsEqual(u1, u2))
  414               return false;
  415   
  416           return true;
  417       }
  418   
  419       /**
  420        * Get the IP address of our host. An empty host field or a DNS failure
  421        * will result in a null return.
  422        *
  423        * @param u a URL object
  424        * @return an <code>InetAddress</code> representing the host
  425        * IP address.
  426        * @since 1.3
  427        */
  428       protected synchronized InetAddress getHostAddress(URL u) {
  429           if (u.hostAddress != null)
  430               return u.hostAddress;
  431   
  432           String host = u.getHost();
  433           if (host == null || host.equals("")) {
  434               return null;
  435           } else {
  436               try {
  437                   u.hostAddress = InetAddress.getByName(host);
  438               } catch (UnknownHostException ex) {
  439                   return null;
  440               } catch (SecurityException se) {
  441                   return null;
  442               }
  443           }
  444           return u.hostAddress;
  445       }
  446   
  447       /**
  448        * Compares the host components of two URLs.
  449        * @param u1 the URL of the first host to compare
  450        * @param u2 the URL of the second host to compare
  451        * @return  <tt>true</tt> if and only if they
  452        * are equal, <tt>false</tt> otherwise.
  453        * @since 1.3
  454        */
  455       protected boolean hostsEqual(URL u1, URL u2) {
  456           InetAddress a1 = getHostAddress(u1);
  457           InetAddress a2 = getHostAddress(u2);
  458           // if we have internet address for both, compare them
  459           if (a1 != null && a2 != null) {
  460               return a1.equals(a2);
  461           // else, if both have host names, compare them
  462           } else if (u1.getHost() != null && u2.getHost() != null)
  463               return u1.getHost().equalsIgnoreCase(u2.getHost());
  464            else
  465               return u1.getHost() == null && u2.getHost() == null;
  466       }
  467   
  468       /**
  469        * Converts a <code>URL</code> of a specific protocol to a
  470        * <code>String</code>.
  471        *
  472        * @param   u   the URL.
  473        * @return  a string representation of the <code>URL</code> argument.
  474        */
  475       protected String toExternalForm(URL u) {
  476   
  477           // pre-compute length of StringBuffer
  478           int len = u.getProtocol().length() + 1;
  479           if (u.getAuthority() != null && u.getAuthority().length() > 0)
  480               len += 2 + u.getAuthority().length();
  481           if (u.getPath() != null) {
  482               len += u.getPath().length();
  483           }
  484           if (u.getQuery() != null) {
  485               len += 1 + u.getQuery().length();
  486           }
  487           if (u.getRef() != null)
  488               len += 1 + u.getRef().length();
  489   
  490           StringBuffer result = new StringBuffer(len);
  491           result.append(u.getProtocol());
  492           result.append(":");
  493           if (u.getAuthority() != null && u.getAuthority().length() > 0) {
  494               result.append("//");
  495               result.append(u.getAuthority());
  496           }
  497           if (u.getPath() != null) {
  498               result.append(u.getPath());
  499           }
  500           if (u.getQuery() != null) {
  501               result.append('?');
  502               result.append(u.getQuery());
  503           }
  504           if (u.getRef() != null) {
  505               result.append("#");
  506               result.append(u.getRef());
  507           }
  508           return result.toString();
  509       }
  510   
  511       /**
  512        * Sets the fields of the <code>URL</code> argument to the indicated values.
  513        * Only classes derived from URLStreamHandler are supposed to be able
  514        * to call the set method on a URL.
  515        *
  516        * @param   u         the URL to modify.
  517        * @param   protocol  the protocol name.
  518        * @param   host      the remote host value for the URL.
  519        * @param   port      the port on the remote machine.
  520        * @param   authority the authority part for the URL.
  521        * @param   userInfo the userInfo part of the URL.
  522        * @param   path      the path component of the URL.
  523        * @param   query     the query part for the URL.
  524        * @param   ref       the reference.
  525        * @exception       SecurityException       if the protocol handler of the URL is
  526        *                                  different from this one
  527        * @see     java.net.URL#set(java.lang.String, java.lang.String, int, java.lang.String, java.lang.String)
  528        * @since 1.3
  529        */
  530          protected void setURL(URL u, String protocol, String host, int port,
  531                                String authority, String userInfo, String path,
  532                                String query, String ref) {
  533           if (this != u.handler) {
  534               throw new SecurityException("handler for url different from " +
  535                                           "this handler");
  536           }
  537           // ensure that no one can reset the protocol on a given URL.
  538           u.set(u.getProtocol(), host, port, authority, userInfo, path, query, ref);
  539       }
  540   
  541       /**
  542        * Sets the fields of the <code>URL</code> argument to the indicated values.
  543        * Only classes derived from URLStreamHandler are supposed to be able
  544        * to call the set method on a URL.
  545        *
  546        * @param   u         the URL to modify.
  547        * @param   protocol  the protocol name. This value is ignored since 1.2.
  548        * @param   host      the remote host value for the URL.
  549        * @param   port      the port on the remote machine.
  550        * @param   file      the file.
  551        * @param   ref       the reference.
  552        * @exception       SecurityException       if the protocol handler of the URL is
  553        *                                  different from this one
  554        * @deprecated Use setURL(URL, String, String, int, String, String, String,
  555        *             String);
  556        */
  557       @Deprecated
  558       protected void setURL(URL u, String protocol, String host, int port,
  559                             String file, String ref) {
  560           /*
  561            * Only old URL handlers call this, so assume that the host
  562            * field might contain "user:passwd@host". Fix as necessary.
  563            */
  564           String authority = null;
  565           String userInfo = null;
  566           if (host != null && host.length() != 0) {
  567               authority = (port == -1) ? host : host + ":" + port;
  568               int at = host.lastIndexOf('@');
  569               if (at != -1) {
  570                   userInfo = host.substring(0, at);
  571                   host = host.substring(at+1);
  572               }
  573           }
  574   
  575           /*
  576            * Assume file might contain query part. Fix as necessary.
  577            */
  578           String path = null;
  579           String query = null;
  580           if (file != null) {
  581               int q = file.lastIndexOf('?');
  582               if (q != -1) {
  583                   query = file.substring(q+1);
  584                   path = file.substring(0, q);
  585               } else
  586                   path = file;
  587           }
  588           setURL(u, protocol, host, port, authority, userInfo, path, query, ref);
  589       }
  590   }

Home » openjdk-7 » java » net » [javadoc | source]