Save This Page
Home » openjdk-7 » java » net » [javadoc | source]
    1   /*
    2    * Copyright (c) 1995, 2008, 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.OutputStream;
   31   import java.util.Hashtable;
   32   import java.util.StringTokenizer;
   33   import sun.security.util.SecurityConstants;
   34   
   35   /**
   36    * Class <code>URL</code> represents a Uniform Resource
   37    * Locator, a pointer to a "resource" on the World
   38    * Wide Web. A resource can be something as simple as a file or a
   39    * directory, or it can be a reference to a more complicated object,
   40    * such as a query to a database or to a search engine. More
   41    * information on the types of URLs and their formats can be found at:
   42    * <blockquote>
   43    *     <a href="http://www.socs.uts.edu.au/MosaicDocs-old/url-primer.html">
   44    *    <i>http://www.socs.uts.edu.au/MosaicDocs-old/url-primer.html</i></a>
   45    * </blockquote>
   46    * <p>
   47    * In general, a URL can be broken into several parts. The previous
   48    * example of a URL indicates that the protocol to use is
   49    * <code>http</code> (HyperText Transfer Protocol) and that the
   50    * information resides on a host machine named
   51    * <code>www.socs.uts.edu.au</code>. The information on that host
   52    * machine is named <code>/MosaicDocs-old/url-primer.html</code>. The exact
   53    * meaning of this name on the host machine is both protocol
   54    * dependent and host dependent. The information normally resides in
   55    * a file, but it could be generated on the fly. This component of
   56    * the URL is called the <i>path</i> component.
   57    * <p>
   58    * A URL can optionally specify a "port", which is the
   59    * port number to which the TCP connection is made on the remote host
   60    * machine. If the port is not specified, the default port for
   61    * the protocol is used instead. For example, the default port for
   62    * <code>http</code> is <code>80</code>. An alternative port could be
   63    * specified as:
   64    * <blockquote><pre>
   65    *     http://www.socs.uts.edu.au:80/MosaicDocs-old/url-primer.html
   66    * </pre></blockquote>
   67    * <p>
   68    * The syntax of <code>URL</code> is defined by  <a
   69    * href="http://www.ietf.org/rfc/rfc2396.txt"><i>RFC&nbsp;2396: Uniform
   70    * Resource Identifiers (URI): Generic Syntax</i></a>, amended by <a
   71    * href="http://www.ietf.org/rfc/rfc2732.txt"><i>RFC&nbsp;2732: Format for
   72    * Literal IPv6 Addresses in URLs</i></a>. The Literal IPv6 address format
   73    * also supports scope_ids. The syntax and usage of scope_ids is described
   74    * <a href="Inet6Address.html#scoped">here</a>.
   75    * <p>
   76    * A URL may have appended to it a "fragment", also known
   77    * as a "ref" or a "reference". The fragment is indicated by the sharp
   78    * sign character "#" followed by more characters. For example,
   79    * <blockquote><pre>
   80    *     http://java.sun.com/index.html#chapter1
   81    * </pre></blockquote>
   82    * <p>
   83    * This fragment is not technically part of the URL. Rather, it
   84    * indicates that after the specified resource is retrieved, the
   85    * application is specifically interested in that part of the
   86    * document that has the tag <code>chapter1</code> attached to it. The
   87    * meaning of a tag is resource specific.
   88    * <p>
   89    * An application can also specify a "relative URL",
   90    * which contains only enough information to reach the resource
   91    * relative to another URL. Relative URLs are frequently used within
   92    * HTML pages. For example, if the contents of the URL:
   93    * <blockquote><pre>
   94    *     http://java.sun.com/index.html
   95    * </pre></blockquote>
   96    * contained within it the relative URL:
   97    * <blockquote><pre>
   98    *     FAQ.html
   99    * </pre></blockquote>
  100    * it would be a shorthand for:
  101    * <blockquote><pre>
  102    *     http://java.sun.com/FAQ.html
  103    * </pre></blockquote>
  104    * <p>
  105    * The relative URL need not specify all the components of a URL. If
  106    * the protocol, host name, or port number is missing, the value is
  107    * inherited from the fully specified URL. The file component must be
  108    * specified. The optional fragment is not inherited.
  109    * <p>
  110    * The URL class does not itself encode or decode any URL components
  111    * according to the escaping mechanism defined in RFC2396. It is the
  112    * responsibility of the caller to encode any fields, which need to be
  113    * escaped prior to calling URL, and also to decode any escaped fields,
  114    * that are returned from URL. Furthermore, because URL has no knowledge
  115    * of URL escaping, it does not recognise equivalence between the encoded
  116    * or decoded form of the same URL. For example, the two URLs:<br>
  117    * <pre>    http://foo.com/hello world/ and http://foo.com/hello%20world</pre>
  118    * would be considered not equal to each other.
  119    * <p>
  120    * Note, the {@link java.net.URI} class does perform escaping of its
  121    * component fields in certain circumstances. The recommended way
  122    * to manage the encoding and decoding of URLs is to use {@link java.net.URI},
  123    * and to convert between these two classes using {@link #toURI()} and
  124    * {@link URI#toURL()}.
  125    * <p>
  126    * The {@link URLEncoder} and {@link URLDecoder} classes can also be
  127    * used, but only for HTML form encoding, which is not the same
  128    * as the encoding scheme defined in RFC2396.
  129    *
  130    * @author  James Gosling
  131    * @since JDK1.0
  132    */
  133   public final class URL implements java.io.Serializable {
  134   
  135       static final long serialVersionUID = -7627629688361524110L;
  136   
  137       /**
  138        * The property which specifies the package prefix list to be scanned
  139        * for protocol handlers.  The value of this property (if any) should
  140        * be a vertical bar delimited list of package names to search through
  141        * for a protocol handler to load.  The policy of this class is that
  142        * all protocol handlers will be in a class called <protocolname>.Handler,
  143        * and each package in the list is examined in turn for a matching
  144        * handler.  If none are found (or the property is not specified), the
  145        * default package prefix, sun.net.www.protocol, is used.  The search
  146        * proceeds from the first package in the list to the last and stops
  147        * when a match is found.
  148        */
  149       private static final String protocolPathProp = "java.protocol.handler.pkgs";
  150   
  151       /**
  152        * The protocol to use (ftp, http, nntp, ... etc.) .
  153        * @serial
  154        */
  155       private String protocol;
  156   
  157       /**
  158        * The host name to connect to.
  159        * @serial
  160        */
  161       private String host;
  162   
  163       /**
  164        * The protocol port to connect to.
  165        * @serial
  166        */
  167       private int port = -1;
  168   
  169       /**
  170        * The specified file name on that host. <code>file</code> is
  171        * defined as <code>path[?query]</code>
  172        * @serial
  173        */
  174       private String file;
  175   
  176       /**
  177        * The query part of this URL.
  178        */
  179       private transient String query;
  180   
  181       /**
  182        * The authority part of this URL.
  183        * @serial
  184        */
  185       private String authority;
  186   
  187       /**
  188        * The path part of this URL.
  189        */
  190       private transient String path;
  191   
  192       /**
  193        * The userinfo part of this URL.
  194        */
  195       private transient String userInfo;
  196   
  197       /**
  198        * # reference.
  199        * @serial
  200        */
  201       private String ref;
  202   
  203       /**
  204        * The host's IP address, used in equals and hashCode.
  205        * Computed on demand. An uninitialized or unknown hostAddress is null.
  206        */
  207       transient InetAddress hostAddress;
  208   
  209       /**
  210        * The URLStreamHandler for this URL.
  211        */
  212       transient URLStreamHandler handler;
  213   
  214       /* Our hash code.
  215        * @serial
  216        */
  217       private int hashCode = -1;
  218   
  219       /**
  220        * Creates a <code>URL</code> object from the specified
  221        * <code>protocol</code>, <code>host</code>, <code>port</code>
  222        * number, and <code>file</code>.<p>
  223        *
  224        * <code>host</code> can be expressed as a host name or a literal
  225        * IP address. If IPv6 literal address is used, it should be
  226        * enclosed in square brackets (<tt>'['</tt> and <tt>']'</tt>), as
  227        * specified by <a
  228        * href="http://www.ietf.org/rfc/rfc2732.txt">RFC&nbsp;2732</a>;
  229        * However, the literal IPv6 address format defined in <a
  230        * href="http://www.ietf.org/rfc/rfc2373.txt"><i>RFC&nbsp;2373: IP
  231        * Version 6 Addressing Architecture</i></a> is also accepted.<p>
  232        *
  233        * Specifying a <code>port</code> number of <code>-1</code>
  234        * indicates that the URL should use the default port for the
  235        * protocol.<p>
  236        *
  237        * If this is the first URL object being created with the specified
  238        * protocol, a <i>stream protocol handler</i> object, an instance of
  239        * class <code>URLStreamHandler</code>, is created for that protocol:
  240        * <ol>
  241        * <li>If the application has previously set up an instance of
  242        *     <code>URLStreamHandlerFactory</code> as the stream handler factory,
  243        *     then the <code>createURLStreamHandler</code> method of that instance
  244        *     is called with the protocol string as an argument to create the
  245        *     stream protocol handler.
  246        * <li>If no <code>URLStreamHandlerFactory</code> has yet been set up,
  247        *     or if the factory's <code>createURLStreamHandler</code> method
  248        *     returns <code>null</code>, then the constructor finds the
  249        *     value of the system property:
  250        *     <blockquote><pre>
  251        *         java.protocol.handler.pkgs
  252        *     </pre></blockquote>
  253        *     If the value of that system property is not <code>null</code>,
  254        *     it is interpreted as a list of packages separated by a vertical
  255        *     slash character '<code>|</code>'. The constructor tries to load
  256        *     the class named:
  257        *     <blockquote><pre>
  258        *         &lt;<i>package</i>&gt;.&lt;<i>protocol</i>&gt;.Handler
  259        *     </pre></blockquote>
  260        *     where &lt;<i>package</i>&gt; is replaced by the name of the package
  261        *     and &lt;<i>protocol</i>&gt; is replaced by the name of the protocol.
  262        *     If this class does not exist, or if the class exists but it is not
  263        *     a subclass of <code>URLStreamHandler</code>, then the next package
  264        *     in the list is tried.
  265        * <li>If the previous step fails to find a protocol handler, then the
  266        *     constructor tries to load from a system default package.
  267        *     <blockquote><pre>
  268        *         &lt;<i>system default package</i>&gt;.&lt;<i>protocol</i>&gt;.Handler
  269        *     </pre></blockquote>
  270        *     If this class does not exist, or if the class exists but it is not a
  271        *     subclass of <code>URLStreamHandler</code>, then a
  272        *     <code>MalformedURLException</code> is thrown.
  273        * </ol>
  274        *
  275        * <p>Protocol handlers for the following protocols are guaranteed
  276        * to exist on the search path :-
  277        * <blockquote><pre>
  278        *     http, https, ftp, file, and jar
  279        * </pre></blockquote>
  280        * Protocol handlers for additional protocols may also be
  281        * available.
  282        *
  283        * <p>No validation of the inputs is performed by this constructor.
  284        *
  285        * @param      protocol   the name of the protocol to use.
  286        * @param      host       the name of the host.
  287        * @param      port       the port number on the host.
  288        * @param      file       the file on the host
  289        * @exception  MalformedURLException  if an unknown protocol is specified.
  290        * @see        java.lang.System#getProperty(java.lang.String)
  291        * @see        java.net.URL#setURLStreamHandlerFactory(
  292        *                  java.net.URLStreamHandlerFactory)
  293        * @see        java.net.URLStreamHandler
  294        * @see        java.net.URLStreamHandlerFactory#createURLStreamHandler(
  295        *                  java.lang.String)
  296        */
  297       public URL(String protocol, String host, int port, String file)
  298           throws MalformedURLException
  299       {
  300           this(protocol, host, port, file, null);
  301       }
  302   
  303       /**
  304        * Creates a URL from the specified <code>protocol</code>
  305        * name, <code>host</code> name, and <code>file</code> name. The
  306        * default port for the specified protocol is used.
  307        * <p>
  308        * This method is equivalent to calling the four-argument
  309        * constructor with the arguments being <code>protocol</code>,
  310        * <code>host</code>, <code>-1</code>, and <code>file</code>.
  311        *
  312        * No validation of the inputs is performed by this constructor.
  313        *
  314        * @param      protocol   the name of the protocol to use.
  315        * @param      host       the name of the host.
  316        * @param      file       the file on the host.
  317        * @exception  MalformedURLException  if an unknown protocol is specified.
  318        * @see        java.net.URL#URL(java.lang.String, java.lang.String,
  319        *                  int, java.lang.String)
  320        */
  321       public URL(String protocol, String host, String file)
  322               throws MalformedURLException {
  323           this(protocol, host, -1, file);
  324       }
  325   
  326       /**
  327        * Creates a <code>URL</code> object from the specified
  328        * <code>protocol</code>, <code>host</code>, <code>port</code>
  329        * number, <code>file</code>, and <code>handler</code>. Specifying
  330        * a <code>port</code> number of <code>-1</code> indicates that
  331        * the URL should use the default port for the protocol. Specifying
  332        * a <code>handler</code> of <code>null</code> indicates that the URL
  333        * should use a default stream handler for the protocol, as outlined
  334        * for:
  335        *     java.net.URL#URL(java.lang.String, java.lang.String, int,
  336        *                      java.lang.String)
  337        *
  338        * <p>If the handler is not null and there is a security manager,
  339        * the security manager's <code>checkPermission</code>
  340        * method is called with a
  341        * <code>NetPermission("specifyStreamHandler")</code> permission.
  342        * This may result in a SecurityException.
  343        *
  344        * No validation of the inputs is performed by this constructor.
  345        *
  346        * @param      protocol   the name of the protocol to use.
  347        * @param      host       the name of the host.
  348        * @param      port       the port number on the host.
  349        * @param      file       the file on the host
  350        * @param      handler    the stream handler for the URL.
  351        * @exception  MalformedURLException  if an unknown protocol is specified.
  352        * @exception  SecurityException
  353        *        if a security manager exists and its
  354        *        <code>checkPermission</code> method doesn't allow
  355        *        specifying a stream handler explicitly.
  356        * @see        java.lang.System#getProperty(java.lang.String)
  357        * @see        java.net.URL#setURLStreamHandlerFactory(
  358        *                  java.net.URLStreamHandlerFactory)
  359        * @see        java.net.URLStreamHandler
  360        * @see        java.net.URLStreamHandlerFactory#createURLStreamHandler(
  361        *                  java.lang.String)
  362        * @see        SecurityManager#checkPermission
  363        * @see        java.net.NetPermission
  364        */
  365       public URL(String protocol, String host, int port, String file,
  366                  URLStreamHandler handler) throws MalformedURLException {
  367           if (handler != null) {
  368               SecurityManager sm = System.getSecurityManager();
  369               if (sm != null) {
  370                   // check for permission to specify a handler
  371                   checkSpecifyHandler(sm);
  372               }
  373           }
  374   
  375           protocol = protocol.toLowerCase();
  376           this.protocol = protocol;
  377           if (host != null) {
  378   
  379               /**
  380                * if host is a literal IPv6 address,
  381                * we will make it conform to RFC 2732
  382                */
  383               if (host.indexOf(':') >= 0 && !host.startsWith("[")) {
  384                   host = "["+host+"]";
  385               }
  386               this.host = host;
  387   
  388               if (port < -1) {
  389                   throw new MalformedURLException("Invalid port number :" +
  390                                                       port);
  391               }
  392               this.port = port;
  393               authority = (port == -1) ? host : host + ":" + port;
  394           }
  395   
  396           Parts parts = new Parts(file);
  397           path = parts.getPath();
  398           query = parts.getQuery();
  399   
  400           if (query != null) {
  401               this.file = path + "?" + query;
  402           } else {
  403               this.file = path;
  404           }
  405           ref = parts.getRef();
  406   
  407           // Note: we don't do validation of the URL here. Too risky to change
  408           // right now, but worth considering for future reference. -br
  409           if (handler == null &&
  410               (handler = getURLStreamHandler(protocol)) == null) {
  411               throw new MalformedURLException("unknown protocol: " + protocol);
  412           }
  413           this.handler = handler;
  414       }
  415   
  416       /**
  417        * Creates a <code>URL</code> object from the <code>String</code>
  418        * representation.
  419        * <p>
  420        * This constructor is equivalent to a call to the two-argument
  421        * constructor with a <code>null</code> first argument.
  422        *
  423        * @param      spec   the <code>String</code> to parse as a URL.
  424        * @exception  MalformedURLException  if no protocol is specified, or an
  425        *               unknown protocol is found, or <tt>spec</tt> is <tt>null</tt>.
  426        * @see        java.net.URL#URL(java.net.URL, java.lang.String)
  427        */
  428       public URL(String spec) throws MalformedURLException {
  429           this(null, spec);
  430       }
  431   
  432       /**
  433        * Creates a URL by parsing the given spec within a specified context.
  434        *
  435        * The new URL is created from the given context URL and the spec
  436        * argument as described in
  437        * RFC2396 &quot;Uniform Resource Identifiers : Generic * Syntax&quot; :
  438        * <blockquote><pre>
  439        *          &lt;scheme&gt;://&lt;authority&gt;&lt;path&gt;?&lt;query&gt;#&lt;fragment&gt;
  440        * </pre></blockquote>
  441        * The reference is parsed into the scheme, authority, path, query and
  442        * fragment parts. If the path component is empty and the scheme,
  443        * authority, and query components are undefined, then the new URL is a
  444        * reference to the current document. Otherwise, the fragment and query
  445        * parts present in the spec are used in the new URL.
  446        * <p>
  447        * If the scheme component is defined in the given spec and does not match
  448        * the scheme of the context, then the new URL is created as an absolute
  449        * URL based on the spec alone. Otherwise the scheme component is inherited
  450        * from the context URL.
  451        * <p>
  452        * If the authority component is present in the spec then the spec is
  453        * treated as absolute and the spec authority and path will replace the
  454        * context authority and path. If the authority component is absent in the
  455        * spec then the authority of the new URL will be inherited from the
  456        * context.
  457        * <p>
  458        * If the spec's path component begins with a slash character
  459        * &quot;/&quot; then the
  460        * path is treated as absolute and the spec path replaces the context path.
  461        * <p>
  462        * Otherwise, the path is treated as a relative path and is appended to the
  463        * context path, as described in RFC2396. Also, in this case,
  464        * the path is canonicalized through the removal of directory
  465        * changes made by occurences of &quot;..&quot; and &quot;.&quot;.
  466        * <p>
  467        * For a more detailed description of URL parsing, refer to RFC2396.
  468        *
  469        * @param      context   the context in which to parse the specification.
  470        * @param      spec      the <code>String</code> to parse as a URL.
  471        * @exception  MalformedURLException  if no protocol is specified, or an
  472        *               unknown protocol is found, or <tt>spec</tt> is <tt>null</tt>.
  473        * @see        java.net.URL#URL(java.lang.String, java.lang.String,
  474        *                  int, java.lang.String)
  475        * @see        java.net.URLStreamHandler
  476        * @see        java.net.URLStreamHandler#parseURL(java.net.URL,
  477        *                  java.lang.String, int, int)
  478        */
  479       public URL(URL context, String spec) throws MalformedURLException {
  480           this(context, spec, null);
  481       }
  482   
  483       /**
  484        * Creates a URL by parsing the given spec with the specified handler
  485        * within a specified context. If the handler is null, the parsing
  486        * occurs as with the two argument constructor.
  487        *
  488        * @param      context   the context in which to parse the specification.
  489        * @param      spec      the <code>String</code> to parse as a URL.
  490        * @param      handler   the stream handler for the URL.
  491        * @exception  MalformedURLException  if no protocol is specified, or an
  492        *               unknown protocol is found, or <tt>spec</tt> is <tt>null</tt>.
  493        * @exception  SecurityException
  494        *        if a security manager exists and its
  495        *        <code>checkPermission</code> method doesn't allow
  496        *        specifying a stream handler.
  497        * @see        java.net.URL#URL(java.lang.String, java.lang.String,
  498        *                  int, java.lang.String)
  499        * @see        java.net.URLStreamHandler
  500        * @see        java.net.URLStreamHandler#parseURL(java.net.URL,
  501        *                  java.lang.String, int, int)
  502        */
  503       public URL(URL context, String spec, URLStreamHandler handler)
  504           throws MalformedURLException
  505       {
  506           String original = spec;
  507           int i, limit, c;
  508           int start = 0;
  509           String newProtocol = null;
  510           boolean aRef=false;
  511           boolean isRelative = false;
  512   
  513           // Check for permission to specify a handler
  514           if (handler != null) {
  515               SecurityManager sm = System.getSecurityManager();
  516               if (sm != null) {
  517                   checkSpecifyHandler(sm);
  518               }
  519           }
  520   
  521           try {
  522               limit = spec.length();
  523               while ((limit > 0) && (spec.charAt(limit - 1) <= ' ')) {
  524                   limit--;        //eliminate trailing whitespace
  525               }
  526               while ((start < limit) && (spec.charAt(start) <= ' ')) {
  527                   start++;        // eliminate leading whitespace
  528               }
  529   
  530               if (spec.regionMatches(true, start, "url:", 0, 4)) {
  531                   start += 4;
  532               }
  533               if (start < spec.length() && spec.charAt(start) == '#') {
  534                   /* we're assuming this is a ref relative to the context URL.
  535                    * This means protocols cannot start w/ '#', but we must parse
  536                    * ref URL's like: "hello:there" w/ a ':' in them.
  537                    */
  538                   aRef=true;
  539               }
  540               for (i = start ; !aRef && (i < limit) &&
  541                        ((c = spec.charAt(i)) != '/') ; i++) {
  542                   if (c == ':') {
  543   
  544                       String s = spec.substring(start, i).toLowerCase();
  545                       if (isValidProtocol(s)) {
  546                           newProtocol = s;
  547                           start = i + 1;
  548                       }
  549                       break;
  550                   }
  551               }
  552   
  553               // Only use our context if the protocols match.
  554               protocol = newProtocol;
  555               if ((context != null) && ((newProtocol == null) ||
  556                               newProtocol.equalsIgnoreCase(context.protocol))) {
  557                   // inherit the protocol handler from the context
  558                   // if not specified to the constructor
  559                   if (handler == null) {
  560                       handler = context.handler;
  561                   }
  562   
  563                   // If the context is a hierarchical URL scheme and the spec
  564                   // contains a matching scheme then maintain backwards
  565                   // compatibility and treat it as if the spec didn't contain
  566                   // the scheme; see 5.2.3 of RFC2396
  567                   if (context.path != null && context.path.startsWith("/"))
  568                       newProtocol = null;
  569   
  570                   if (newProtocol == null) {
  571                       protocol = context.protocol;
  572                       authority = context.authority;
  573                       userInfo = context.userInfo;
  574                       host = context.host;
  575                       port = context.port;
  576                       file = context.file;
  577                       path = context.path;
  578                       isRelative = true;
  579                   }
  580               }
  581   
  582               if (protocol == null) {
  583                   throw new MalformedURLException("no protocol: "+original);
  584               }
  585   
  586               // Get the protocol handler if not specified or the protocol
  587               // of the context could not be used
  588               if (handler == null &&
  589                   (handler = getURLStreamHandler(protocol)) == null) {
  590                   throw new MalformedURLException("unknown protocol: "+protocol);
  591               }
  592   
  593               this.handler = handler;
  594   
  595               i = spec.indexOf('#', start);
  596               if (i >= 0) {
  597                   ref = spec.substring(i + 1, limit);
  598                   limit = i;
  599               }
  600   
  601               /*
  602                * Handle special case inheritance of query and fragment
  603                * implied by RFC2396 section 5.2.2.
  604                */
  605               if (isRelative && start == limit) {
  606                   query = context.query;
  607                   if (ref == null) {
  608                       ref = context.ref;
  609                   }
  610               }
  611   
  612               handler.parseURL(this, spec, start, limit);
  613   
  614           } catch(MalformedURLException e) {
  615               throw e;
  616           } catch(Exception e) {
  617               MalformedURLException exception = new MalformedURLException(e.getMessage());
  618               exception.initCause(e);
  619               throw exception;
  620           }
  621       }
  622   
  623       /*
  624        * Returns true if specified string is a valid protocol name.
  625        */
  626       private boolean isValidProtocol(String protocol) {
  627           int len = protocol.length();
  628           if (len < 1)
  629               return false;
  630           char c = protocol.charAt(0);
  631           if (!Character.isLetter(c))
  632               return false;
  633           for (int i = 1; i < len; i++) {
  634               c = protocol.charAt(i);
  635               if (!Character.isLetterOrDigit(c) && c != '.' && c != '+' &&
  636                   c != '-') {
  637                   return false;
  638               }
  639           }
  640           return true;
  641       }
  642   
  643       /*
  644        * Checks for permission to specify a stream handler.
  645        */
  646       private void checkSpecifyHandler(SecurityManager sm) {
  647           sm.checkPermission(SecurityConstants.SPECIFY_HANDLER_PERMISSION);
  648       }
  649   
  650       /**
  651        * Sets the fields of the URL. This is not a public method so that
  652        * only URLStreamHandlers can modify URL fields. URLs are
  653        * otherwise constant.
  654        *
  655        * @param protocol the name of the protocol to use
  656        * @param host the name of the host
  657          @param port the port number on the host
  658        * @param file the file on the host
  659        * @param ref the internal reference in the URL
  660        */
  661       protected void set(String protocol, String host,
  662                          int port, String file, String ref) {
  663           synchronized (this) {
  664               this.protocol = protocol;
  665               this.host = host;
  666               authority = port == -1 ? host : host + ":" + port;
  667               this.port = port;
  668               this.file = file;
  669               this.ref = ref;
  670               /* This is very important. We must recompute this after the
  671                * URL has been changed. */
  672               hashCode = -1;
  673               hostAddress = null;
  674               int q = file.lastIndexOf('?');
  675               if (q != -1) {
  676                   query = file.substring(q+1);
  677                   path = file.substring(0, q);
  678               } else
  679                   path = file;
  680           }
  681       }
  682   
  683       /**
  684        * Sets the specified 8 fields of the URL. This is not a public method so
  685        * that only URLStreamHandlers can modify URL fields. URLs are otherwise
  686        * constant.
  687        *
  688        * @param protocol the name of the protocol to use
  689        * @param host the name of the host
  690        * @param port the port number on the host
  691        * @param authority the authority part for the url
  692        * @param userInfo the username and password
  693        * @param path the file on the host
  694        * @param ref the internal reference in the URL
  695        * @param query the query part of this URL
  696        * @since 1.3
  697        */
  698       protected void set(String protocol, String host, int port,
  699                          String authority, String userInfo, String path,
  700                          String query, String ref) {
  701           synchronized (this) {
  702               this.protocol = protocol;
  703               this.host = host;
  704               this.port = port;
  705               this.file = query == null ? path : path + "?" + query;
  706               this.userInfo = userInfo;
  707               this.path = path;
  708               this.ref = ref;
  709               /* This is very important. We must recompute this after the
  710                * URL has been changed. */
  711               hashCode = -1;
  712               hostAddress = null;
  713               this.query = query;
  714               this.authority = authority;
  715           }
  716       }
  717   
  718       /**
  719        * Gets the query part of this <code>URL</code>.
  720        *
  721        * @return  the query part of this <code>URL</code>,
  722        * or <CODE>null</CODE> if one does not exist
  723        * @since 1.3
  724        */
  725       public String getQuery() {
  726           return query;
  727       }
  728   
  729       /**
  730        * Gets the path part of this <code>URL</code>.
  731        *
  732        * @return  the path part of this <code>URL</code>, or an
  733        * empty string if one does not exist
  734        * @since 1.3
  735        */
  736       public String getPath() {
  737           return path;
  738       }
  739   
  740       /**
  741        * Gets the userInfo part of this <code>URL</code>.
  742        *
  743        * @return  the userInfo part of this <code>URL</code>, or
  744        * <CODE>null</CODE> if one does not exist
  745        * @since 1.3
  746        */
  747       public String getUserInfo() {
  748           return userInfo;
  749       }
  750   
  751       /**
  752        * Gets the authority part of this <code>URL</code>.
  753        *
  754        * @return  the authority part of this <code>URL</code>
  755        * @since 1.3
  756        */
  757       public String getAuthority() {
  758           return authority;
  759       }
  760   
  761       /**
  762        * Gets the port number of this <code>URL</code>.
  763        *
  764        * @return  the port number, or -1 if the port is not set
  765        */
  766       public int getPort() {
  767           return port;
  768       }
  769   
  770       /**
  771        * Gets the default port number of the protocol associated
  772        * with this <code>URL</code>. If the URL scheme or the URLStreamHandler
  773        * for the URL do not define a default port number,
  774        * then -1 is returned.
  775        *
  776        * @return  the port number
  777        * @since 1.4
  778        */
  779       public int getDefaultPort() {
  780           return handler.getDefaultPort();
  781       }
  782   
  783       /**
  784        * Gets the protocol name of this <code>URL</code>.
  785        *
  786        * @return  the protocol of this <code>URL</code>.
  787        */
  788       public String getProtocol() {
  789           return protocol;
  790       }
  791   
  792       /**
  793        * Gets the host name of this <code>URL</code>, if applicable.
  794        * The format of the host conforms to RFC 2732, i.e. for a
  795        * literal IPv6 address, this method will return the IPv6 address
  796        * enclosed in square brackets (<tt>'['</tt> and <tt>']'</tt>).
  797        *
  798        * @return  the host name of this <code>URL</code>.
  799        */
  800       public String getHost() {
  801           return host;
  802       }
  803   
  804       /**
  805        * Gets the file name of this <code>URL</code>.
  806        * The returned file portion will be
  807        * the same as <CODE>getPath()</CODE>, plus the concatenation of
  808        * the value of <CODE>getQuery()</CODE>, if any. If there is
  809        * no query portion, this method and <CODE>getPath()</CODE> will
  810        * return identical results.
  811        *
  812        * @return  the file name of this <code>URL</code>,
  813        * or an empty string if one does not exist
  814        */
  815       public String getFile() {
  816           return file;
  817       }
  818   
  819       /**
  820        * Gets the anchor (also known as the "reference") of this
  821        * <code>URL</code>.
  822        *
  823        * @return  the anchor (also known as the "reference") of this
  824        *          <code>URL</code>, or <CODE>null</CODE> if one does not exist
  825        */
  826       public String getRef() {
  827           return ref;
  828       }
  829   
  830       /**
  831        * Compares this URL for equality with another object.<p>
  832        *
  833        * If the given object is not a URL then this method immediately returns
  834        * <code>false</code>.<p>
  835        *
  836        * Two URL objects are equal if they have the same protocol, reference
  837        * equivalent hosts, have the same port number on the host, and the same
  838        * file and fragment of the file.<p>
  839        *
  840        * Two hosts are considered equivalent if both host names can be resolved
  841        * into the same IP addresses; else if either host name can't be
  842        * resolved, the host names must be equal without regard to case; or both
  843        * host names equal to null.<p>
  844        *
  845        * Since hosts comparison requires name resolution, this operation is a
  846        * blocking operation. <p>
  847        *
  848        * Note: The defined behavior for <code>equals</code> is known to
  849        * be inconsistent with virtual hosting in HTTP.
  850        *
  851        * @param   obj   the URL to compare against.
  852        * @return  <code>true</code> if the objects are the same;
  853        *          <code>false</code> otherwise.
  854        */
  855       public boolean equals(Object obj) {
  856           if (!(obj instanceof URL))
  857               return false;
  858           URL u2 = (URL)obj;
  859   
  860           return handler.equals(this, u2);
  861       }
  862   
  863       /**
  864        * Creates an integer suitable for hash table indexing.<p>
  865        *
  866        * The hash code is based upon all the URL components relevant for URL
  867        * comparison. As such, this operation is a blocking operation.<p>
  868        *
  869        * @return  a hash code for this <code>URL</code>.
  870        */
  871       public synchronized int hashCode() {
  872           if (hashCode != -1)
  873               return hashCode;
  874   
  875           hashCode = handler.hashCode(this);
  876           return hashCode;
  877       }
  878   
  879       /**
  880        * Compares two URLs, excluding the fragment component.<p>
  881        *
  882        * Returns <code>true</code> if this <code>URL</code> and the
  883        * <code>other</code> argument are equal without taking the
  884        * fragment component into consideration.
  885        *
  886        * @param   other   the <code>URL</code> to compare against.
  887        * @return  <code>true</code> if they reference the same remote object;
  888        *          <code>false</code> otherwise.
  889        */
  890       public boolean sameFile(URL other) {
  891           return handler.sameFile(this, other);
  892       }
  893   
  894       /**
  895        * Constructs a string representation of this <code>URL</code>. The
  896        * string is created by calling the <code>toExternalForm</code>
  897        * method of the stream protocol handler for this object.
  898        *
  899        * @return  a string representation of this object.
  900        * @see     java.net.URL#URL(java.lang.String, java.lang.String, int,
  901        *                  java.lang.String)
  902        * @see     java.net.URLStreamHandler#toExternalForm(java.net.URL)
  903        */
  904       public String toString() {
  905           return toExternalForm();
  906       }
  907   
  908       /**
  909        * Constructs a string representation of this <code>URL</code>. The
  910        * string is created by calling the <code>toExternalForm</code>
  911        * method of the stream protocol handler for this object.
  912        *
  913        * @return  a string representation of this object.
  914        * @see     java.net.URL#URL(java.lang.String, java.lang.String,
  915        *                  int, java.lang.String)
  916        * @see     java.net.URLStreamHandler#toExternalForm(java.net.URL)
  917        */
  918       public String toExternalForm() {
  919           return handler.toExternalForm(this);
  920       }
  921   
  922       /**
  923        * Returns a {@link java.net.URI} equivalent to this URL.
  924        * This method functions in the same way as <code>new URI (this.toString())</code>.
  925        * <p>Note, any URL instance that complies with RFC 2396 can be converted
  926        * to a URI. However, some URLs that are not strictly in compliance
  927        * can not be converted to a URI.
  928        *
  929        * @exception URISyntaxException if this URL is not formatted strictly according to
  930        *            to RFC2396 and cannot be converted to a URI.
  931        *
  932        * @return    a URI instance equivalent to this URL.
  933        * @since 1.5
  934        */
  935       public URI toURI() throws URISyntaxException {
  936           return new URI (toString());
  937       }
  938   
  939       /**
  940        * Returns a {@link java.net.URLConnection URLConnection} instance that
  941        * represents a connection to the remote object referred to by the
  942        * {@code URL}.
  943        *
  944        * <P>A new instance of {@linkplain java.net.URLConnection URLConnection} is
  945        * created every time when invoking the
  946        * {@linkplain java.net.URLStreamHandler#openConnection(URL)
  947        * URLStreamHandler.openConnection(URL)} method of the protocol handler for
  948        * this URL.</P>
  949        *
  950        * <P>It should be noted that a URLConnection instance does not establish
  951        * the actual network connection on creation. This will happen only when
  952        * calling {@linkplain java.net.URLConnection#connect() URLConnection.connect()}.</P>
  953        *
  954        * <P>If for the URL's protocol (such as HTTP or JAR), there
  955        * exists a public, specialized URLConnection subclass belonging
  956        * to one of the following packages or one of their subpackages:
  957        * java.lang, java.io, java.util, java.net, the connection
  958        * returned will be of that subclass. For example, for HTTP an
  959        * HttpURLConnection will be returned, and for JAR a
  960        * JarURLConnection will be returned.</P>
  961        *
  962        * @return     a {@link java.net.URLConnection URLConnection} linking
  963        *             to the URL.
  964        * @exception  IOException  if an I/O exception occurs.
  965        * @see        java.net.URL#URL(java.lang.String, java.lang.String,
  966        *             int, java.lang.String)
  967        */
  968       public URLConnection openConnection() throws java.io.IOException {
  969           return handler.openConnection(this);
  970       }
  971   
  972       /**
  973        * Same as {@link #openConnection()}, except that the connection will be
  974        * made through the specified proxy; Protocol handlers that do not
  975        * support proxing will ignore the proxy parameter and make a
  976        * normal connection.
  977        *
  978        * Invoking this method preempts the system's default ProxySelector
  979        * settings.
  980        *
  981        * @param      proxy the Proxy through which this connection
  982        *             will be made. If direct connection is desired,
  983        *             Proxy.NO_PROXY should be specified.
  984        * @return     a <code>URLConnection</code> to the URL.
  985        * @exception  IOException  if an I/O exception occurs.
  986        * @exception  SecurityException if a security manager is present
  987        *             and the caller doesn't have permission to connect
  988        *             to the proxy.
  989        * @exception  IllegalArgumentException will be thrown if proxy is null,
  990        *             or proxy has the wrong type
  991        * @exception  UnsupportedOperationException if the subclass that
  992        *             implements the protocol handler doesn't support
  993        *             this method.
  994        * @see        java.net.URL#URL(java.lang.String, java.lang.String,
  995        *             int, java.lang.String)
  996        * @see        java.net.URLConnection
  997        * @see        java.net.URLStreamHandler#openConnection(java.net.URL,
  998        *             java.net.Proxy)
  999        * @since      1.5
 1000        */
 1001       public URLConnection openConnection(Proxy proxy)
 1002           throws java.io.IOException {
 1003           if (proxy == null) {
 1004               throw new IllegalArgumentException("proxy can not be null");
 1005           }
 1006   
 1007           // Create a copy of Proxy as a security measure
 1008           Proxy p = proxy == Proxy.NO_PROXY ? Proxy.NO_PROXY : sun.net.ApplicationProxy.create(proxy);
 1009           SecurityManager sm = System.getSecurityManager();
 1010           if (p.type() != Proxy.Type.DIRECT && sm != null) {
 1011               InetSocketAddress epoint = (InetSocketAddress) p.address();
 1012               if (epoint.isUnresolved())
 1013                   sm.checkConnect(epoint.getHostName(), epoint.getPort());
 1014               else
 1015                   sm.checkConnect(epoint.getAddress().getHostAddress(),
 1016                                   epoint.getPort());
 1017           }
 1018           return handler.openConnection(this, p);
 1019       }
 1020   
 1021       /**
 1022        * Opens a connection to this <code>URL</code> and returns an
 1023        * <code>InputStream</code> for reading from that connection. This
 1024        * method is a shorthand for:
 1025        * <blockquote><pre>
 1026        *     openConnection().getInputStream()
 1027        * </pre></blockquote>
 1028        *
 1029        * @return     an input stream for reading from the URL connection.
 1030        * @exception  IOException  if an I/O exception occurs.
 1031        * @see        java.net.URL#openConnection()
 1032        * @see        java.net.URLConnection#getInputStream()
 1033        */
 1034       public final InputStream openStream() throws java.io.IOException {
 1035           return openConnection().getInputStream();
 1036       }
 1037   
 1038       /**
 1039        * Gets the contents of this URL. This method is a shorthand for:
 1040        * <blockquote><pre>
 1041        *     openConnection().getContent()
 1042        * </pre></blockquote>
 1043        *
 1044        * @return     the contents of this URL.
 1045        * @exception  IOException  if an I/O exception occurs.
 1046        * @see        java.net.URLConnection#getContent()
 1047        */
 1048       public final Object getContent() throws java.io.IOException {
 1049           return openConnection().getContent();
 1050       }
 1051   
 1052       /**
 1053        * Gets the contents of this URL. This method is a shorthand for:
 1054        * <blockquote><pre>
 1055        *     openConnection().getContent(Class[])
 1056        * </pre></blockquote>
 1057        *
 1058        * @param classes an array of Java types
 1059        * @return     the content object of this URL that is the first match of
 1060        *               the types specified in the classes array.
 1061        *               null if none of the requested types are supported.
 1062        * @exception  IOException  if an I/O exception occurs.
 1063        * @see        java.net.URLConnection#getContent(Class[])
 1064        * @since 1.3
 1065        */
 1066       public final Object getContent(Class[] classes)
 1067       throws java.io.IOException {
 1068           return openConnection().getContent(classes);
 1069       }
 1070   
 1071       /**
 1072        * The URLStreamHandler factory.
 1073        */
 1074       static URLStreamHandlerFactory factory;
 1075   
 1076       /**
 1077        * Sets an application's <code>URLStreamHandlerFactory</code>.
 1078        * This method can be called at most once in a given Java Virtual
 1079        * Machine.
 1080        *
 1081        *<p> The <code>URLStreamHandlerFactory</code> instance is used to
 1082        *construct a stream protocol handler from a protocol name.
 1083        *
 1084        * <p> If there is a security manager, this method first calls
 1085        * the security manager's <code>checkSetFactory</code> method
 1086        * to ensure the operation is allowed.
 1087        * This could result in a SecurityException.
 1088        *
 1089        * @param      fac   the desired factory.
 1090        * @exception  Error  if the application has already set a factory.
 1091        * @exception  SecurityException  if a security manager exists and its
 1092        *             <code>checkSetFactory</code> method doesn't allow
 1093        *             the operation.
 1094        * @see        java.net.URL#URL(java.lang.String, java.lang.String,
 1095        *             int, java.lang.String)
 1096        * @see        java.net.URLStreamHandlerFactory
 1097        * @see        SecurityManager#checkSetFactory
 1098        */
 1099       public static void setURLStreamHandlerFactory(URLStreamHandlerFactory fac) {
 1100           synchronized (streamHandlerLock) {
 1101               if (factory != null) {
 1102                   throw new Error("factory already defined");
 1103               }
 1104               SecurityManager security = System.getSecurityManager();
 1105               if (security != null) {
 1106                   security.checkSetFactory();
 1107               }
 1108               handlers.clear();
 1109               factory = fac;
 1110           }
 1111       }
 1112   
 1113       /**
 1114        * A table of protocol handlers.
 1115        */
 1116       static Hashtable handlers = new Hashtable();
 1117       private static Object streamHandlerLock = new Object();
 1118   
 1119       /**
 1120        * Returns the Stream Handler.
 1121        * @param protocol the protocol to use
 1122        */
 1123       static URLStreamHandler getURLStreamHandler(String protocol) {
 1124   
 1125           URLStreamHandler handler = (URLStreamHandler)handlers.get(protocol);
 1126           if (handler == null) {
 1127   
 1128               boolean checkedWithFactory = false;
 1129   
 1130               // Use the factory (if any)
 1131               if (factory != null) {
 1132                   handler = factory.createURLStreamHandler(protocol);
 1133                   checkedWithFactory = true;
 1134               }
 1135   
 1136               // Try java protocol handler
 1137               if (handler == null) {
 1138                   String packagePrefixList = null;
 1139   
 1140                   packagePrefixList
 1141                       = java.security.AccessController.doPrivileged(
 1142                       new sun.security.action.GetPropertyAction(
 1143                           protocolPathProp,""));
 1144                   if (packagePrefixList != "") {
 1145                       packagePrefixList += "|";
 1146                   }
 1147   
 1148                   // REMIND: decide whether to allow the "null" class prefix
 1149                   // or not.
 1150                   packagePrefixList += "sun.net.www.protocol";
 1151   
 1152                   StringTokenizer packagePrefixIter =
 1153                       new StringTokenizer(packagePrefixList, "|");
 1154   
 1155                   while (handler == null &&
 1156                          packagePrefixIter.hasMoreTokens()) {
 1157   
 1158                       String packagePrefix =
 1159                         packagePrefixIter.nextToken().trim();
 1160                       try {
 1161                           String clsName = packagePrefix + "." + protocol +
 1162                             ".Handler";
 1163                           Class cls = null;
 1164                           try {
 1165                               cls = Class.forName(clsName);
 1166                           } catch (ClassNotFoundException e) {
 1167                               ClassLoader cl = ClassLoader.getSystemClassLoader();
 1168                               if (cl != null) {
 1169                                   cls = cl.loadClass(clsName);
 1170                               }
 1171                           }
 1172                           if (cls != null) {
 1173                               handler  =
 1174                                 (URLStreamHandler)cls.newInstance();
 1175                           }
 1176                       } catch (Exception e) {
 1177                           // any number of exceptions can get thrown here
 1178                       }
 1179                   }
 1180               }
 1181   
 1182               synchronized (streamHandlerLock) {
 1183   
 1184                   URLStreamHandler handler2 = null;
 1185   
 1186                   // Check again with hashtable just in case another
 1187                   // thread created a handler since we last checked
 1188                   handler2 = (URLStreamHandler)handlers.get(protocol);
 1189   
 1190                   if (handler2 != null) {
 1191                       return handler2;
 1192                   }
 1193   
 1194                   // Check with factory if another thread set a
 1195                   // factory since our last check
 1196                   if (!checkedWithFactory && factory != null) {
 1197                       handler2 = factory.createURLStreamHandler(protocol);
 1198                   }
 1199   
 1200                   if (handler2 != null) {
 1201                       // The handler from the factory must be given more
 1202                       // importance. Discard the default handler that
 1203                       // this thread created.
 1204                       handler = handler2;
 1205                   }
 1206   
 1207                   // Insert this handler into the hashtable
 1208                   if (handler != null) {
 1209                       handlers.put(protocol, handler);
 1210                   }
 1211   
 1212               }
 1213           }
 1214   
 1215           return handler;
 1216   
 1217       }
 1218   
 1219       /**
 1220        * WriteObject is called to save the state of the URL to an
 1221        * ObjectOutputStream. The handler is not saved since it is
 1222        * specific to this system.
 1223        *
 1224        * @serialData the default write object value. When read back in,
 1225        * the reader must ensure that calling getURLStreamHandler with
 1226        * the protocol variable returns a valid URLStreamHandler and
 1227        * throw an IOException if it does not.
 1228        */
 1229       private synchronized void writeObject(java.io.ObjectOutputStream s)
 1230           throws IOException
 1231       {
 1232           s.defaultWriteObject(); // write the fields
 1233       }
 1234   
 1235       /**
 1236        * readObject is called to restore the state of the URL from the
 1237        * stream.  It reads the components of the URL and finds the local
 1238        * stream handler.
 1239        */
 1240       private synchronized void readObject(java.io.ObjectInputStream s)
 1241            throws IOException, ClassNotFoundException
 1242       {
 1243           s.defaultReadObject();  // read the fields
 1244           if ((handler = getURLStreamHandler(protocol)) == null) {
 1245               throw new IOException("unknown protocol: " + protocol);
 1246           }
 1247   
 1248           // Construct authority part
 1249           if (authority == null &&
 1250               ((host != null && host.length() > 0) || port != -1)) {
 1251               if (host == null)
 1252                   host = "";
 1253               authority = (port == -1) ? host : host + ":" + port;
 1254   
 1255               // Handle hosts with userInfo in them
 1256               int at = host.lastIndexOf('@');
 1257               if (at != -1) {
 1258                   userInfo = host.substring(0, at);
 1259                   host = host.substring(at+1);
 1260               }
 1261           } else if (authority != null) {
 1262               // Construct user info part
 1263               int ind = authority.indexOf('@');
 1264               if (ind != -1)
 1265                   userInfo = authority.substring(0, ind);
 1266           }
 1267   
 1268           // Construct path and query part
 1269           path = null;
 1270           query = null;
 1271           if (file != null) {
 1272               // Fix: only do this if hierarchical?
 1273               int q = file.lastIndexOf('?');
 1274               if (q != -1) {
 1275                   query = file.substring(q+1);
 1276                   path = file.substring(0, q);
 1277               } else
 1278                   path = file;
 1279           }
 1280       }
 1281   }
 1282   
 1283   class Parts {
 1284       String path, query, ref;
 1285   
 1286       Parts(String file) {
 1287           int ind = file.indexOf('#');
 1288           ref = ind < 0 ? null: file.substring(ind + 1);
 1289           file = ind < 0 ? file: file.substring(0, ind);
 1290           int q = file.lastIndexOf('?');
 1291           if (q != -1) {
 1292               query = file.substring(q+1);
 1293               path = file.substring(0, q);
 1294           } else {
 1295               path = file;
 1296           }
 1297       }
 1298   
 1299       String getPath() {
 1300           return path;
 1301       }
 1302   
 1303       String getQuery() {
 1304           return query;
 1305       }
 1306   
 1307       String getRef() {
 1308           return ref;
 1309       }
 1310   }

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