emul/mini/src/main/java/java/net/URL.java
branchemul
changeset 554 05224402145d
parent 374 e5b4bd29f268
child 576 b679a7dad297
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/emul/mini/src/main/java/java/net/URL.java	Wed Jan 23 20:39:23 2013 +0100
     1.3 @@ -0,0 +1,1037 @@
     1.4 +/*
     1.5 + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
     1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     1.7 + *
     1.8 + * This code is free software; you can redistribute it and/or modify it
     1.9 + * under the terms of the GNU General Public License version 2 only, as
    1.10 + * published by the Free Software Foundation.  Oracle designates this
    1.11 + * particular file as subject to the "Classpath" exception as provided
    1.12 + * by Oracle in the LICENSE file that accompanied this code.
    1.13 + *
    1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
    1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    1.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    1.17 + * version 2 for more details (a copy is included in the LICENSE file that
    1.18 + * accompanied this code).
    1.19 + *
    1.20 + * You should have received a copy of the GNU General Public License version
    1.21 + * 2 along with this work; if not, write to the Free Software Foundation,
    1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    1.23 + *
    1.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    1.25 + * or visit www.oracle.com if you need additional information or have any
    1.26 + * questions.
    1.27 + */
    1.28 +
    1.29 +package java.net;
    1.30 +
    1.31 +import java.io.IOException;
    1.32 +import java.io.InputStream;
    1.33 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
    1.34 +
    1.35 +/**
    1.36 + * Class <code>URL</code> represents a Uniform Resource
    1.37 + * Locator, a pointer to a "resource" on the World
    1.38 + * Wide Web. A resource can be something as simple as a file or a
    1.39 + * directory, or it can be a reference to a more complicated object,
    1.40 + * such as a query to a database or to a search engine. More
    1.41 + * information on the types of URLs and their formats can be found at:
    1.42 + * <blockquote>
    1.43 + *     <a href="http://www.socs.uts.edu.au/MosaicDocs-old/url-primer.html">
    1.44 + *    <i>http://www.socs.uts.edu.au/MosaicDocs-old/url-primer.html</i></a>
    1.45 + * </blockquote>
    1.46 + * <p>
    1.47 + * In general, a URL can be broken into several parts. The previous
    1.48 + * example of a URL indicates that the protocol to use is
    1.49 + * <code>http</code> (HyperText Transfer Protocol) and that the
    1.50 + * information resides on a host machine named
    1.51 + * <code>www.socs.uts.edu.au</code>. The information on that host
    1.52 + * machine is named <code>/MosaicDocs-old/url-primer.html</code>. The exact
    1.53 + * meaning of this name on the host machine is both protocol
    1.54 + * dependent and host dependent. The information normally resides in
    1.55 + * a file, but it could be generated on the fly. This component of
    1.56 + * the URL is called the <i>path</i> component.
    1.57 + * <p>
    1.58 + * A URL can optionally specify a "port", which is the
    1.59 + * port number to which the TCP connection is made on the remote host
    1.60 + * machine. If the port is not specified, the default port for
    1.61 + * the protocol is used instead. For example, the default port for
    1.62 + * <code>http</code> is <code>80</code>. An alternative port could be
    1.63 + * specified as:
    1.64 + * <blockquote><pre>
    1.65 + *     http://www.socs.uts.edu.au:80/MosaicDocs-old/url-primer.html
    1.66 + * </pre></blockquote>
    1.67 + * <p>
    1.68 + * The syntax of <code>URL</code> is defined by  <a
    1.69 + * href="http://www.ietf.org/rfc/rfc2396.txt"><i>RFC&nbsp;2396: Uniform
    1.70 + * Resource Identifiers (URI): Generic Syntax</i></a>, amended by <a
    1.71 + * href="http://www.ietf.org/rfc/rfc2732.txt"><i>RFC&nbsp;2732: Format for
    1.72 + * Literal IPv6 Addresses in URLs</i></a>. The Literal IPv6 address format
    1.73 + * also supports scope_ids. The syntax and usage of scope_ids is described
    1.74 + * <a href="Inet6Address.html#scoped">here</a>.
    1.75 + * <p>
    1.76 + * A URL may have appended to it a "fragment", also known
    1.77 + * as a "ref" or a "reference". The fragment is indicated by the sharp
    1.78 + * sign character "#" followed by more characters. For example,
    1.79 + * <blockquote><pre>
    1.80 + *     http://java.sun.com/index.html#chapter1
    1.81 + * </pre></blockquote>
    1.82 + * <p>
    1.83 + * This fragment is not technically part of the URL. Rather, it
    1.84 + * indicates that after the specified resource is retrieved, the
    1.85 + * application is specifically interested in that part of the
    1.86 + * document that has the tag <code>chapter1</code> attached to it. The
    1.87 + * meaning of a tag is resource specific.
    1.88 + * <p>
    1.89 + * An application can also specify a "relative URL",
    1.90 + * which contains only enough information to reach the resource
    1.91 + * relative to another URL. Relative URLs are frequently used within
    1.92 + * HTML pages. For example, if the contents of the URL:
    1.93 + * <blockquote><pre>
    1.94 + *     http://java.sun.com/index.html
    1.95 + * </pre></blockquote>
    1.96 + * contained within it the relative URL:
    1.97 + * <blockquote><pre>
    1.98 + *     FAQ.html
    1.99 + * </pre></blockquote>
   1.100 + * it would be a shorthand for:
   1.101 + * <blockquote><pre>
   1.102 + *     http://java.sun.com/FAQ.html
   1.103 + * </pre></blockquote>
   1.104 + * <p>
   1.105 + * The relative URL need not specify all the components of a URL. If
   1.106 + * the protocol, host name, or port number is missing, the value is
   1.107 + * inherited from the fully specified URL. The file component must be
   1.108 + * specified. The optional fragment is not inherited.
   1.109 + * <p>
   1.110 + * The URL class does not itself encode or decode any URL components
   1.111 + * according to the escaping mechanism defined in RFC2396. It is the
   1.112 + * responsibility of the caller to encode any fields, which need to be
   1.113 + * escaped prior to calling URL, and also to decode any escaped fields,
   1.114 + * that are returned from URL. Furthermore, because URL has no knowledge
   1.115 + * of URL escaping, it does not recognise equivalence between the encoded
   1.116 + * or decoded form of the same URL. For example, the two URLs:<br>
   1.117 + * <pre>    http://foo.com/hello world/ and http://foo.com/hello%20world</pre>
   1.118 + * would be considered not equal to each other.
   1.119 + * <p>
   1.120 + * Note, the {@link java.net.URI} class does perform escaping of its
   1.121 + * component fields in certain circumstances. The recommended way
   1.122 + * to manage the encoding and decoding of URLs is to use {@link java.net.URI},
   1.123 + * and to convert between these two classes using {@link #toURI()} and
   1.124 + * {@link URI#toURL()}.
   1.125 + * <p>
   1.126 + * The {@link URLEncoder} and {@link URLDecoder} classes can also be
   1.127 + * used, but only for HTML form encoding, which is not the same
   1.128 + * as the encoding scheme defined in RFC2396.
   1.129 + *
   1.130 + * @author  James Gosling
   1.131 + * @since JDK1.0
   1.132 + */
   1.133 +public final class URL implements java.io.Serializable {
   1.134 +
   1.135 +    static final long serialVersionUID = -7627629688361524110L;
   1.136 +
   1.137 +    /**
   1.138 +     * The property which specifies the package prefix list to be scanned
   1.139 +     * for protocol handlers.  The value of this property (if any) should
   1.140 +     * be a vertical bar delimited list of package names to search through
   1.141 +     * for a protocol handler to load.  The policy of this class is that
   1.142 +     * all protocol handlers will be in a class called <protocolname>.Handler,
   1.143 +     * and each package in the list is examined in turn for a matching
   1.144 +     * handler.  If none are found (or the property is not specified), the
   1.145 +     * default package prefix, sun.net.www.protocol, is used.  The search
   1.146 +     * proceeds from the first package in the list to the last and stops
   1.147 +     * when a match is found.
   1.148 +     */
   1.149 +    private static final String protocolPathProp = "java.protocol.handler.pkgs";
   1.150 +
   1.151 +    /**
   1.152 +     * The protocol to use (ftp, http, nntp, ... etc.) .
   1.153 +     * @serial
   1.154 +     */
   1.155 +    private String protocol;
   1.156 +
   1.157 +    /**
   1.158 +     * The host name to connect to.
   1.159 +     * @serial
   1.160 +     */
   1.161 +    private String host;
   1.162 +
   1.163 +    /**
   1.164 +     * The protocol port to connect to.
   1.165 +     * @serial
   1.166 +     */
   1.167 +    private int port = -1;
   1.168 +
   1.169 +    /**
   1.170 +     * The specified file name on that host. <code>file</code> is
   1.171 +     * defined as <code>path[?query]</code>
   1.172 +     * @serial
   1.173 +     */
   1.174 +    private String file;
   1.175 +
   1.176 +    /**
   1.177 +     * The query part of this URL.
   1.178 +     */
   1.179 +    private transient String query;
   1.180 +
   1.181 +    /**
   1.182 +     * The authority part of this URL.
   1.183 +     * @serial
   1.184 +     */
   1.185 +    private String authority;
   1.186 +
   1.187 +    /**
   1.188 +     * The path part of this URL.
   1.189 +     */
   1.190 +    private transient String path;
   1.191 +
   1.192 +    /**
   1.193 +     * The userinfo part of this URL.
   1.194 +     */
   1.195 +    private transient String userInfo;
   1.196 +
   1.197 +    /**
   1.198 +     * # reference.
   1.199 +     * @serial
   1.200 +     */
   1.201 +    private String ref;
   1.202 +
   1.203 +    /**
   1.204 +     * The host's IP address, used in equals and hashCode.
   1.205 +     * Computed on demand. An uninitialized or unknown hostAddress is null.
   1.206 +     */
   1.207 +    transient Object hostAddress;
   1.208 +
   1.209 +    /**
   1.210 +     * The URLStreamHandler for this URL.
   1.211 +     */
   1.212 +    transient URLStreamHandler handler;
   1.213 +
   1.214 +    /* Our hash code.
   1.215 +     * @serial
   1.216 +     */
   1.217 +    private int hashCode = -1;
   1.218 +
   1.219 +    /**
   1.220 +     * Creates a <code>URL</code> object from the specified
   1.221 +     * <code>protocol</code>, <code>host</code>, <code>port</code>
   1.222 +     * number, and <code>file</code>.<p>
   1.223 +     *
   1.224 +     * <code>host</code> can be expressed as a host name or a literal
   1.225 +     * IP address. If IPv6 literal address is used, it should be
   1.226 +     * enclosed in square brackets (<tt>'['</tt> and <tt>']'</tt>), as
   1.227 +     * specified by <a
   1.228 +     * href="http://www.ietf.org/rfc/rfc2732.txt">RFC&nbsp;2732</a>;
   1.229 +     * However, the literal IPv6 address format defined in <a
   1.230 +     * href="http://www.ietf.org/rfc/rfc2373.txt"><i>RFC&nbsp;2373: IP
   1.231 +     * Version 6 Addressing Architecture</i></a> is also accepted.<p>
   1.232 +     *
   1.233 +     * Specifying a <code>port</code> number of <code>-1</code>
   1.234 +     * indicates that the URL should use the default port for the
   1.235 +     * protocol.<p>
   1.236 +     *
   1.237 +     * If this is the first URL object being created with the specified
   1.238 +     * protocol, a <i>stream protocol handler</i> object, an instance of
   1.239 +     * class <code>URLStreamHandler</code>, is created for that protocol:
   1.240 +     * <ol>
   1.241 +     * <li>If the application has previously set up an instance of
   1.242 +     *     <code>URLStreamHandlerFactory</code> as the stream handler factory,
   1.243 +     *     then the <code>createURLStreamHandler</code> method of that instance
   1.244 +     *     is called with the protocol string as an argument to create the
   1.245 +     *     stream protocol handler.
   1.246 +     * <li>If no <code>URLStreamHandlerFactory</code> has yet been set up,
   1.247 +     *     or if the factory's <code>createURLStreamHandler</code> method
   1.248 +     *     returns <code>null</code>, then the constructor finds the
   1.249 +     *     value of the system property:
   1.250 +     *     <blockquote><pre>
   1.251 +     *         java.protocol.handler.pkgs
   1.252 +     *     </pre></blockquote>
   1.253 +     *     If the value of that system property is not <code>null</code>,
   1.254 +     *     it is interpreted as a list of packages separated by a vertical
   1.255 +     *     slash character '<code>|</code>'. The constructor tries to load
   1.256 +     *     the class named:
   1.257 +     *     <blockquote><pre>
   1.258 +     *         &lt;<i>package</i>&gt;.&lt;<i>protocol</i>&gt;.Handler
   1.259 +     *     </pre></blockquote>
   1.260 +     *     where &lt;<i>package</i>&gt; is replaced by the name of the package
   1.261 +     *     and &lt;<i>protocol</i>&gt; is replaced by the name of the protocol.
   1.262 +     *     If this class does not exist, or if the class exists but it is not
   1.263 +     *     a subclass of <code>URLStreamHandler</code>, then the next package
   1.264 +     *     in the list is tried.
   1.265 +     * <li>If the previous step fails to find a protocol handler, then the
   1.266 +     *     constructor tries to load from a system default package.
   1.267 +     *     <blockquote><pre>
   1.268 +     *         &lt;<i>system default package</i>&gt;.&lt;<i>protocol</i>&gt;.Handler
   1.269 +     *     </pre></blockquote>
   1.270 +     *     If this class does not exist, or if the class exists but it is not a
   1.271 +     *     subclass of <code>URLStreamHandler</code>, then a
   1.272 +     *     <code>MalformedURLException</code> is thrown.
   1.273 +     * </ol>
   1.274 +     *
   1.275 +     * <p>Protocol handlers for the following protocols are guaranteed
   1.276 +     * to exist on the search path :-
   1.277 +     * <blockquote><pre>
   1.278 +     *     http, https, ftp, file, and jar
   1.279 +     * </pre></blockquote>
   1.280 +     * Protocol handlers for additional protocols may also be
   1.281 +     * available.
   1.282 +     *
   1.283 +     * <p>No validation of the inputs is performed by this constructor.
   1.284 +     *
   1.285 +     * @param      protocol   the name of the protocol to use.
   1.286 +     * @param      host       the name of the host.
   1.287 +     * @param      port       the port number on the host.
   1.288 +     * @param      file       the file on the host
   1.289 +     * @exception  MalformedURLException  if an unknown protocol is specified.
   1.290 +     * @see        java.lang.System#getProperty(java.lang.String)
   1.291 +     * @see        java.net.URL#setURLStreamHandlerFactory(
   1.292 +     *                  java.net.URLStreamHandlerFactory)
   1.293 +     * @see        java.net.URLStreamHandler
   1.294 +     * @see        java.net.URLStreamHandlerFactory#createURLStreamHandler(
   1.295 +     *                  java.lang.String)
   1.296 +     */
   1.297 +    public URL(String protocol, String host, int port, String file)
   1.298 +        throws MalformedURLException
   1.299 +    {
   1.300 +        this(protocol, host, port, file, null);
   1.301 +    }
   1.302 +
   1.303 +    /**
   1.304 +     * Creates a URL from the specified <code>protocol</code>
   1.305 +     * name, <code>host</code> name, and <code>file</code> name. The
   1.306 +     * default port for the specified protocol is used.
   1.307 +     * <p>
   1.308 +     * This method is equivalent to calling the four-argument
   1.309 +     * constructor with the arguments being <code>protocol</code>,
   1.310 +     * <code>host</code>, <code>-1</code>, and <code>file</code>.
   1.311 +     *
   1.312 +     * No validation of the inputs is performed by this constructor.
   1.313 +     *
   1.314 +     * @param      protocol   the name of the protocol to use.
   1.315 +     * @param      host       the name of the host.
   1.316 +     * @param      file       the file on the host.
   1.317 +     * @exception  MalformedURLException  if an unknown protocol is specified.
   1.318 +     * @see        java.net.URL#URL(java.lang.String, java.lang.String,
   1.319 +     *                  int, java.lang.String)
   1.320 +     */
   1.321 +    public URL(String protocol, String host, String file)
   1.322 +            throws MalformedURLException {
   1.323 +        this(protocol, host, -1, file);
   1.324 +    }
   1.325 +
   1.326 +    /**
   1.327 +     * Creates a <code>URL</code> object from the specified
   1.328 +     * <code>protocol</code>, <code>host</code>, <code>port</code>
   1.329 +     * number, <code>file</code>, and <code>handler</code>. Specifying
   1.330 +     * a <code>port</code> number of <code>-1</code> indicates that
   1.331 +     * the URL should use the default port for the protocol. Specifying
   1.332 +     * a <code>handler</code> of <code>null</code> indicates that the URL
   1.333 +     * should use a default stream handler for the protocol, as outlined
   1.334 +     * for:
   1.335 +     *     java.net.URL#URL(java.lang.String, java.lang.String, int,
   1.336 +     *                      java.lang.String)
   1.337 +     *
   1.338 +     * <p>If the handler is not null and there is a security manager,
   1.339 +     * the security manager's <code>checkPermission</code>
   1.340 +     * method is called with a
   1.341 +     * <code>NetPermission("specifyStreamHandler")</code> permission.
   1.342 +     * This may result in a SecurityException.
   1.343 +     *
   1.344 +     * No validation of the inputs is performed by this constructor.
   1.345 +     *
   1.346 +     * @param      protocol   the name of the protocol to use.
   1.347 +     * @param      host       the name of the host.
   1.348 +     * @param      port       the port number on the host.
   1.349 +     * @param      file       the file on the host
   1.350 +     * @param      handler    the stream handler for the URL.
   1.351 +     * @exception  MalformedURLException  if an unknown protocol is specified.
   1.352 +     * @exception  SecurityException
   1.353 +     *        if a security manager exists and its
   1.354 +     *        <code>checkPermission</code> method doesn't allow
   1.355 +     *        specifying a stream handler explicitly.
   1.356 +     * @see        java.lang.System#getProperty(java.lang.String)
   1.357 +     * @see        java.net.URL#setURLStreamHandlerFactory(
   1.358 +     *                  java.net.URLStreamHandlerFactory)
   1.359 +     * @see        java.net.URLStreamHandler
   1.360 +     * @see        java.net.URLStreamHandlerFactory#createURLStreamHandler(
   1.361 +     *                  java.lang.String)
   1.362 +     * @see        SecurityManager#checkPermission
   1.363 +     * @see        java.net.NetPermission
   1.364 +     */
   1.365 +    public URL(String protocol, String host, int port, String file,
   1.366 +               URLStreamHandler handler) throws MalformedURLException {
   1.367 +        if (handler != null) {
   1.368 +            throw new SecurityException();
   1.369 +        }
   1.370 +
   1.371 +        protocol = protocol.toLowerCase();
   1.372 +        this.protocol = protocol;
   1.373 +        if (host != null) {
   1.374 +
   1.375 +            /**
   1.376 +             * if host is a literal IPv6 address,
   1.377 +             * we will make it conform to RFC 2732
   1.378 +             */
   1.379 +            if (host.indexOf(':') >= 0 && !host.startsWith("[")) {
   1.380 +                host = "["+host+"]";
   1.381 +            }
   1.382 +            this.host = host;
   1.383 +
   1.384 +            if (port < -1) {
   1.385 +                throw new MalformedURLException("Invalid port number :" +
   1.386 +                                                    port);
   1.387 +            }
   1.388 +            this.port = port;
   1.389 +            authority = (port == -1) ? host : host + ":" + port;
   1.390 +        }
   1.391 +
   1.392 +        Parts parts = new Parts(file);
   1.393 +        path = parts.getPath();
   1.394 +        query = parts.getQuery();
   1.395 +
   1.396 +        if (query != null) {
   1.397 +            this.file = path + "?" + query;
   1.398 +        } else {
   1.399 +            this.file = path;
   1.400 +        }
   1.401 +        ref = parts.getRef();
   1.402 +
   1.403 +        // Note: we don't do validation of the URL here. Too risky to change
   1.404 +        // right now, but worth considering for future reference. -br
   1.405 +        if (handler == null &&
   1.406 +            (handler = getURLStreamHandler(protocol)) == null) {
   1.407 +            throw new MalformedURLException("unknown protocol: " + protocol);
   1.408 +        }
   1.409 +        this.handler = handler;
   1.410 +    }
   1.411 +
   1.412 +    /**
   1.413 +     * Creates a <code>URL</code> object from the <code>String</code>
   1.414 +     * representation.
   1.415 +     * <p>
   1.416 +     * This constructor is equivalent to a call to the two-argument
   1.417 +     * constructor with a <code>null</code> first argument.
   1.418 +     *
   1.419 +     * @param      spec   the <code>String</code> to parse as a URL.
   1.420 +     * @exception  MalformedURLException  if no protocol is specified, or an
   1.421 +     *               unknown protocol is found, or <tt>spec</tt> is <tt>null</tt>.
   1.422 +     * @see        java.net.URL#URL(java.net.URL, java.lang.String)
   1.423 +     */
   1.424 +    public URL(String spec) throws MalformedURLException {
   1.425 +        this(null, spec);
   1.426 +    }
   1.427 +
   1.428 +    /**
   1.429 +     * Creates a URL by parsing the given spec within a specified context.
   1.430 +     *
   1.431 +     * The new URL is created from the given context URL and the spec
   1.432 +     * argument as described in
   1.433 +     * RFC2396 &quot;Uniform Resource Identifiers : Generic * Syntax&quot; :
   1.434 +     * <blockquote><pre>
   1.435 +     *          &lt;scheme&gt;://&lt;authority&gt;&lt;path&gt;?&lt;query&gt;#&lt;fragment&gt;
   1.436 +     * </pre></blockquote>
   1.437 +     * The reference is parsed into the scheme, authority, path, query and
   1.438 +     * fragment parts. If the path component is empty and the scheme,
   1.439 +     * authority, and query components are undefined, then the new URL is a
   1.440 +     * reference to the current document. Otherwise, the fragment and query
   1.441 +     * parts present in the spec are used in the new URL.
   1.442 +     * <p>
   1.443 +     * If the scheme component is defined in the given spec and does not match
   1.444 +     * the scheme of the context, then the new URL is created as an absolute
   1.445 +     * URL based on the spec alone. Otherwise the scheme component is inherited
   1.446 +     * from the context URL.
   1.447 +     * <p>
   1.448 +     * If the authority component is present in the spec then the spec is
   1.449 +     * treated as absolute and the spec authority and path will replace the
   1.450 +     * context authority and path. If the authority component is absent in the
   1.451 +     * spec then the authority of the new URL will be inherited from the
   1.452 +     * context.
   1.453 +     * <p>
   1.454 +     * If the spec's path component begins with a slash character
   1.455 +     * &quot;/&quot; then the
   1.456 +     * path is treated as absolute and the spec path replaces the context path.
   1.457 +     * <p>
   1.458 +     * Otherwise, the path is treated as a relative path and is appended to the
   1.459 +     * context path, as described in RFC2396. Also, in this case,
   1.460 +     * the path is canonicalized through the removal of directory
   1.461 +     * changes made by occurences of &quot;..&quot; and &quot;.&quot;.
   1.462 +     * <p>
   1.463 +     * For a more detailed description of URL parsing, refer to RFC2396.
   1.464 +     *
   1.465 +     * @param      context   the context in which to parse the specification.
   1.466 +     * @param      spec      the <code>String</code> to parse as a URL.
   1.467 +     * @exception  MalformedURLException  if no protocol is specified, or an
   1.468 +     *               unknown protocol is found, or <tt>spec</tt> is <tt>null</tt>.
   1.469 +     * @see        java.net.URL#URL(java.lang.String, java.lang.String,
   1.470 +     *                  int, java.lang.String)
   1.471 +     * @see        java.net.URLStreamHandler
   1.472 +     * @see        java.net.URLStreamHandler#parseURL(java.net.URL,
   1.473 +     *                  java.lang.String, int, int)
   1.474 +     */
   1.475 +    public URL(URL context, String spec) throws MalformedURLException {
   1.476 +        this(context, spec, null);
   1.477 +    }
   1.478 +
   1.479 +    /**
   1.480 +     * Creates a URL by parsing the given spec with the specified handler
   1.481 +     * within a specified context. If the handler is null, the parsing
   1.482 +     * occurs as with the two argument constructor.
   1.483 +     *
   1.484 +     * @param      context   the context in which to parse the specification.
   1.485 +     * @param      spec      the <code>String</code> to parse as a URL.
   1.486 +     * @param      handler   the stream handler for the URL.
   1.487 +     * @exception  MalformedURLException  if no protocol is specified, or an
   1.488 +     *               unknown protocol is found, or <tt>spec</tt> is <tt>null</tt>.
   1.489 +     * @exception  SecurityException
   1.490 +     *        if a security manager exists and its
   1.491 +     *        <code>checkPermission</code> method doesn't allow
   1.492 +     *        specifying a stream handler.
   1.493 +     * @see        java.net.URL#URL(java.lang.String, java.lang.String,
   1.494 +     *                  int, java.lang.String)
   1.495 +     * @see        java.net.URLStreamHandler
   1.496 +     * @see        java.net.URLStreamHandler#parseURL(java.net.URL,
   1.497 +     *                  java.lang.String, int, int)
   1.498 +     */
   1.499 +    public URL(URL context, String spec, URLStreamHandler handler)
   1.500 +        throws MalformedURLException
   1.501 +    {
   1.502 +        String original = spec;
   1.503 +        int i, limit, c;
   1.504 +        int start = 0;
   1.505 +        String newProtocol = null;
   1.506 +        boolean aRef=false;
   1.507 +        boolean isRelative = false;
   1.508 +
   1.509 +        // Check for permission to specify a handler
   1.510 +        if (handler != null) {
   1.511 +            throw new SecurityException();
   1.512 +        }
   1.513 +
   1.514 +        try {
   1.515 +            limit = spec.length();
   1.516 +            while ((limit > 0) && (spec.charAt(limit - 1) <= ' ')) {
   1.517 +                limit--;        //eliminate trailing whitespace
   1.518 +            }
   1.519 +            while ((start < limit) && (spec.charAt(start) <= ' ')) {
   1.520 +                start++;        // eliminate leading whitespace
   1.521 +            }
   1.522 +
   1.523 +            if (spec.regionMatches(true, start, "url:", 0, 4)) {
   1.524 +                start += 4;
   1.525 +            }
   1.526 +            if (start < spec.length() && spec.charAt(start) == '#') {
   1.527 +                /* we're assuming this is a ref relative to the context URL.
   1.528 +                 * This means protocols cannot start w/ '#', but we must parse
   1.529 +                 * ref URL's like: "hello:there" w/ a ':' in them.
   1.530 +                 */
   1.531 +                aRef=true;
   1.532 +            }
   1.533 +            for (i = start ; !aRef && (i < limit) &&
   1.534 +                     ((c = spec.charAt(i)) != '/') ; i++) {
   1.535 +                if (c == ':') {
   1.536 +
   1.537 +                    String s = spec.substring(start, i).toLowerCase();
   1.538 +                    if (isValidProtocol(s)) {
   1.539 +                        newProtocol = s;
   1.540 +                        start = i + 1;
   1.541 +                    }
   1.542 +                    break;
   1.543 +                }
   1.544 +            }
   1.545 +
   1.546 +            // Only use our context if the protocols match.
   1.547 +            protocol = newProtocol;
   1.548 +            if ((context != null) && ((newProtocol == null) ||
   1.549 +                            newProtocol.equalsIgnoreCase(context.protocol))) {
   1.550 +                // inherit the protocol handler from the context
   1.551 +                // if not specified to the constructor
   1.552 +                if (handler == null) {
   1.553 +                    handler = context.handler;
   1.554 +                }
   1.555 +
   1.556 +                // If the context is a hierarchical URL scheme and the spec
   1.557 +                // contains a matching scheme then maintain backwards
   1.558 +                // compatibility and treat it as if the spec didn't contain
   1.559 +                // the scheme; see 5.2.3 of RFC2396
   1.560 +                if (context.path != null && context.path.startsWith("/"))
   1.561 +                    newProtocol = null;
   1.562 +
   1.563 +                if (newProtocol == null) {
   1.564 +                    protocol = context.protocol;
   1.565 +                    authority = context.authority;
   1.566 +                    userInfo = context.userInfo;
   1.567 +                    host = context.host;
   1.568 +                    port = context.port;
   1.569 +                    file = context.file;
   1.570 +                    path = context.path;
   1.571 +                    isRelative = true;
   1.572 +                }
   1.573 +            }
   1.574 +
   1.575 +            if (protocol == null) {
   1.576 +                throw new MalformedURLException("no protocol: "+original);
   1.577 +            }
   1.578 +
   1.579 +            // Get the protocol handler if not specified or the protocol
   1.580 +            // of the context could not be used
   1.581 +            if (handler == null &&
   1.582 +                (handler = getURLStreamHandler(protocol)) == null) {
   1.583 +                throw new MalformedURLException("unknown protocol: "+protocol);
   1.584 +            }
   1.585 +            this.handler = handler;
   1.586 +
   1.587 +            i = spec.indexOf('#', start);
   1.588 +            if (i >= 0) {
   1.589 +//thrw(protocol + " hnd: " + handler.getClass().getName() + " i: " + i);
   1.590 +                ref = spec.substring(i + 1, limit);
   1.591 +                limit = i;
   1.592 +            }
   1.593 +
   1.594 +            /*
   1.595 +             * Handle special case inheritance of query and fragment
   1.596 +             * implied by RFC2396 section 5.2.2.
   1.597 +             */
   1.598 +            if (isRelative && start == limit) {
   1.599 +                query = context.query;
   1.600 +                if (ref == null) {
   1.601 +                    ref = context.ref;
   1.602 +                }
   1.603 +            }
   1.604 +
   1.605 +            handler.parseURL(this, spec, start, limit);
   1.606 +
   1.607 +        } catch(MalformedURLException e) {
   1.608 +            throw e;
   1.609 +        } catch(Exception e) {
   1.610 +            MalformedURLException exception = new MalformedURLException(e.getMessage());
   1.611 +            exception.initCause(e);
   1.612 +            throw exception;
   1.613 +        }
   1.614 +    }
   1.615 +    
   1.616 +    /*
   1.617 +     * Returns true if specified string is a valid protocol name.
   1.618 +     */
   1.619 +    private boolean isValidProtocol(String protocol) {
   1.620 +        int len = protocol.length();
   1.621 +        if (len < 1)
   1.622 +            return false;
   1.623 +        char c = protocol.charAt(0);
   1.624 +        if (!Character.isLetter(c))
   1.625 +            return false;
   1.626 +        for (int i = 1; i < len; i++) {
   1.627 +            c = protocol.charAt(i);
   1.628 +            if (!Character.isLetterOrDigit(c) && c != '.' && c != '+' &&
   1.629 +                c != '-') {
   1.630 +                return false;
   1.631 +            }
   1.632 +        }
   1.633 +        return true;
   1.634 +    }
   1.635 +
   1.636 +    /**
   1.637 +     * Sets the fields of the URL. This is not a public method so that
   1.638 +     * only URLStreamHandlers can modify URL fields. URLs are
   1.639 +     * otherwise constant.
   1.640 +     *
   1.641 +     * @param protocol the name of the protocol to use
   1.642 +     * @param host the name of the host
   1.643 +       @param port the port number on the host
   1.644 +     * @param file the file on the host
   1.645 +     * @param ref the internal reference in the URL
   1.646 +     */
   1.647 +    protected void set(String protocol, String host,
   1.648 +                       int port, String file, String ref) {
   1.649 +        synchronized (this) {
   1.650 +            this.protocol = protocol;
   1.651 +            this.host = host;
   1.652 +            authority = port == -1 ? host : host + ":" + port;
   1.653 +            this.port = port;
   1.654 +            this.file = file;
   1.655 +            this.ref = ref;
   1.656 +            /* This is very important. We must recompute this after the
   1.657 +             * URL has been changed. */
   1.658 +            hashCode = -1;
   1.659 +            hostAddress = null;
   1.660 +            int q = file.lastIndexOf('?');
   1.661 +            if (q != -1) {
   1.662 +                query = file.substring(q+1);
   1.663 +                path = file.substring(0, q);
   1.664 +            } else
   1.665 +                path = file;
   1.666 +        }
   1.667 +    }
   1.668 +
   1.669 +    /**
   1.670 +     * Sets the specified 8 fields of the URL. This is not a public method so
   1.671 +     * that only URLStreamHandlers can modify URL fields. URLs are otherwise
   1.672 +     * constant.
   1.673 +     *
   1.674 +     * @param protocol the name of the protocol to use
   1.675 +     * @param host the name of the host
   1.676 +     * @param port the port number on the host
   1.677 +     * @param authority the authority part for the url
   1.678 +     * @param userInfo the username and password
   1.679 +     * @param path the file on the host
   1.680 +     * @param ref the internal reference in the URL
   1.681 +     * @param query the query part of this URL
   1.682 +     * @since 1.3
   1.683 +     */
   1.684 +    protected void set(String protocol, String host, int port,
   1.685 +                       String authority, String userInfo, String path,
   1.686 +                       String query, String ref) {
   1.687 +        synchronized (this) {
   1.688 +            this.protocol = protocol;
   1.689 +            this.host = host;
   1.690 +            this.port = port;
   1.691 +            this.file = query == null ? path : path + "?" + query;
   1.692 +            this.userInfo = userInfo;
   1.693 +            this.path = path;
   1.694 +            this.ref = ref;
   1.695 +            /* This is very important. We must recompute this after the
   1.696 +             * URL has been changed. */
   1.697 +            hashCode = -1;
   1.698 +            hostAddress = null;
   1.699 +            this.query = query;
   1.700 +            this.authority = authority;
   1.701 +        }
   1.702 +    }
   1.703 +
   1.704 +    /**
   1.705 +     * Gets the query part of this <code>URL</code>.
   1.706 +     *
   1.707 +     * @return  the query part of this <code>URL</code>,
   1.708 +     * or <CODE>null</CODE> if one does not exist
   1.709 +     * @since 1.3
   1.710 +     */
   1.711 +    public String getQuery() {
   1.712 +        return query;
   1.713 +    }
   1.714 +
   1.715 +    /**
   1.716 +     * Gets the path part of this <code>URL</code>.
   1.717 +     *
   1.718 +     * @return  the path part of this <code>URL</code>, or an
   1.719 +     * empty string if one does not exist
   1.720 +     * @since 1.3
   1.721 +     */
   1.722 +    public String getPath() {
   1.723 +        return path;
   1.724 +    }
   1.725 +
   1.726 +    /**
   1.727 +     * Gets the userInfo part of this <code>URL</code>.
   1.728 +     *
   1.729 +     * @return  the userInfo part of this <code>URL</code>, or
   1.730 +     * <CODE>null</CODE> if one does not exist
   1.731 +     * @since 1.3
   1.732 +     */
   1.733 +    public String getUserInfo() {
   1.734 +        return userInfo;
   1.735 +    }
   1.736 +
   1.737 +    /**
   1.738 +     * Gets the authority part of this <code>URL</code>.
   1.739 +     *
   1.740 +     * @return  the authority part of this <code>URL</code>
   1.741 +     * @since 1.3
   1.742 +     */
   1.743 +    public String getAuthority() {
   1.744 +        return authority;
   1.745 +    }
   1.746 +
   1.747 +    /**
   1.748 +     * Gets the port number of this <code>URL</code>.
   1.749 +     *
   1.750 +     * @return  the port number, or -1 if the port is not set
   1.751 +     */
   1.752 +    public int getPort() {
   1.753 +        return port;
   1.754 +    }
   1.755 +
   1.756 +    /**
   1.757 +     * Gets the default port number of the protocol associated
   1.758 +     * with this <code>URL</code>. If the URL scheme or the URLStreamHandler
   1.759 +     * for the URL do not define a default port number,
   1.760 +     * then -1 is returned.
   1.761 +     *
   1.762 +     * @return  the port number
   1.763 +     * @since 1.4
   1.764 +     */
   1.765 +    public int getDefaultPort() {
   1.766 +        return handler.getDefaultPort();
   1.767 +    }
   1.768 +
   1.769 +    /**
   1.770 +     * Gets the protocol name of this <code>URL</code>.
   1.771 +     *
   1.772 +     * @return  the protocol of this <code>URL</code>.
   1.773 +     */
   1.774 +    public String getProtocol() {
   1.775 +        return protocol;
   1.776 +    }
   1.777 +
   1.778 +    /**
   1.779 +     * Gets the host name of this <code>URL</code>, if applicable.
   1.780 +     * The format of the host conforms to RFC 2732, i.e. for a
   1.781 +     * literal IPv6 address, this method will return the IPv6 address
   1.782 +     * enclosed in square brackets (<tt>'['</tt> and <tt>']'</tt>).
   1.783 +     *
   1.784 +     * @return  the host name of this <code>URL</code>.
   1.785 +     */
   1.786 +    public String getHost() {
   1.787 +        return host;
   1.788 +    }
   1.789 +
   1.790 +    /**
   1.791 +     * Gets the file name of this <code>URL</code>.
   1.792 +     * The returned file portion will be
   1.793 +     * the same as <CODE>getPath()</CODE>, plus the concatenation of
   1.794 +     * the value of <CODE>getQuery()</CODE>, if any. If there is
   1.795 +     * no query portion, this method and <CODE>getPath()</CODE> will
   1.796 +     * return identical results.
   1.797 +     *
   1.798 +     * @return  the file name of this <code>URL</code>,
   1.799 +     * or an empty string if one does not exist
   1.800 +     */
   1.801 +    public String getFile() {
   1.802 +        return file;
   1.803 +    }
   1.804 +
   1.805 +    /**
   1.806 +     * Gets the anchor (also known as the "reference") of this
   1.807 +     * <code>URL</code>.
   1.808 +     *
   1.809 +     * @return  the anchor (also known as the "reference") of this
   1.810 +     *          <code>URL</code>, or <CODE>null</CODE> if one does not exist
   1.811 +     */
   1.812 +    public String getRef() {
   1.813 +        return ref;
   1.814 +    }
   1.815 +
   1.816 +    /**
   1.817 +     * Compares this URL for equality with another object.<p>
   1.818 +     *
   1.819 +     * If the given object is not a URL then this method immediately returns
   1.820 +     * <code>false</code>.<p>
   1.821 +     *
   1.822 +     * Two URL objects are equal if they have the same protocol, reference
   1.823 +     * equivalent hosts, have the same port number on the host, and the same
   1.824 +     * file and fragment of the file.<p>
   1.825 +     *
   1.826 +     * Two hosts are considered equivalent if both host names can be resolved
   1.827 +     * into the same IP addresses; else if either host name can't be
   1.828 +     * resolved, the host names must be equal without regard to case; or both
   1.829 +     * host names equal to null.<p>
   1.830 +     *
   1.831 +     * Since hosts comparison requires name resolution, this operation is a
   1.832 +     * blocking operation. <p>
   1.833 +     *
   1.834 +     * Note: The defined behavior for <code>equals</code> is known to
   1.835 +     * be inconsistent with virtual hosting in HTTP.
   1.836 +     *
   1.837 +     * @param   obj   the URL to compare against.
   1.838 +     * @return  <code>true</code> if the objects are the same;
   1.839 +     *          <code>false</code> otherwise.
   1.840 +     */
   1.841 +    public boolean equals(Object obj) {
   1.842 +        if (!(obj instanceof URL))
   1.843 +            return false;
   1.844 +        URL u2 = (URL)obj;
   1.845 +
   1.846 +        return handler.equals(this, u2);
   1.847 +    }
   1.848 +
   1.849 +    /**
   1.850 +     * Creates an integer suitable for hash table indexing.<p>
   1.851 +     *
   1.852 +     * The hash code is based upon all the URL components relevant for URL
   1.853 +     * comparison. As such, this operation is a blocking operation.<p>
   1.854 +     *
   1.855 +     * @return  a hash code for this <code>URL</code>.
   1.856 +     */
   1.857 +    public synchronized int hashCode() {
   1.858 +        if (hashCode != -1)
   1.859 +            return hashCode;
   1.860 +
   1.861 +        hashCode = handler.hashCode(this);
   1.862 +        return hashCode;
   1.863 +    }
   1.864 +
   1.865 +    /**
   1.866 +     * Compares two URLs, excluding the fragment component.<p>
   1.867 +     *
   1.868 +     * Returns <code>true</code> if this <code>URL</code> and the
   1.869 +     * <code>other</code> argument are equal without taking the
   1.870 +     * fragment component into consideration.
   1.871 +     *
   1.872 +     * @param   other   the <code>URL</code> to compare against.
   1.873 +     * @return  <code>true</code> if they reference the same remote object;
   1.874 +     *          <code>false</code> otherwise.
   1.875 +     */
   1.876 +    public boolean sameFile(URL other) {
   1.877 +        return handler.sameFile(this, other);
   1.878 +    }
   1.879 +
   1.880 +    /**
   1.881 +     * Constructs a string representation of this <code>URL</code>. The
   1.882 +     * string is created by calling the <code>toExternalForm</code>
   1.883 +     * method of the stream protocol handler for this object.
   1.884 +     *
   1.885 +     * @return  a string representation of this object.
   1.886 +     * @see     java.net.URL#URL(java.lang.String, java.lang.String, int,
   1.887 +     *                  java.lang.String)
   1.888 +     * @see     java.net.URLStreamHandler#toExternalForm(java.net.URL)
   1.889 +     */
   1.890 +    public String toString() {
   1.891 +        return toExternalForm();
   1.892 +    }
   1.893 +
   1.894 +    /**
   1.895 +     * Constructs a string representation of this <code>URL</code>. The
   1.896 +     * string is created by calling the <code>toExternalForm</code>
   1.897 +     * method of the stream protocol handler for this object.
   1.898 +     *
   1.899 +     * @return  a string representation of this object.
   1.900 +     * @see     java.net.URL#URL(java.lang.String, java.lang.String,
   1.901 +     *                  int, java.lang.String)
   1.902 +     * @see     java.net.URLStreamHandler#toExternalForm(java.net.URL)
   1.903 +     */
   1.904 +    public String toExternalForm() {
   1.905 +        return handler.toExternalForm(this);
   1.906 +    }
   1.907 +
   1.908 +    /**
   1.909 +     * Returns a {@link java.net.URLConnection URLConnection} instance that
   1.910 +     * represents a connection to the remote object referred to by the
   1.911 +     * {@code URL}.
   1.912 +     *
   1.913 +     * <P>A new instance of {@linkplain java.net.URLConnection URLConnection} is
   1.914 +     * created every time when invoking the
   1.915 +     * {@linkplain java.net.URLStreamHandler#openConnection(URL)
   1.916 +     * URLStreamHandler.openConnection(URL)} method of the protocol handler for
   1.917 +     * this URL.</P>
   1.918 +     *
   1.919 +     * <P>It should be noted that a URLConnection instance does not establish
   1.920 +     * the actual network connection on creation. This will happen only when
   1.921 +     * calling {@linkplain java.net.URLConnection#connect() URLConnection.connect()}.</P>
   1.922 +     *
   1.923 +     * <P>If for the URL's protocol (such as HTTP or JAR), there
   1.924 +     * exists a public, specialized URLConnection subclass belonging
   1.925 +     * to one of the following packages or one of their subpackages:
   1.926 +     * java.lang, java.io, java.util, java.net, the connection
   1.927 +     * returned will be of that subclass. For example, for HTTP an
   1.928 +     * HttpURLConnection will be returned, and for JAR a
   1.929 +     * JarURLConnection will be returned.</P>
   1.930 +     *
   1.931 +     * @return     a {@link java.net.URLConnection URLConnection} linking
   1.932 +     *             to the URL.
   1.933 +     * @exception  IOException  if an I/O exception occurs.
   1.934 +     * @see        java.net.URL#URL(java.lang.String, java.lang.String,
   1.935 +     *             int, java.lang.String)
   1.936 +     */
   1.937 +//    public URLConnection openConnection() throws java.io.IOException {
   1.938 +//        return handler.openConnection(this);
   1.939 +//    }
   1.940 +
   1.941 +
   1.942 +    /**
   1.943 +     * Opens a connection to this <code>URL</code> and returns an
   1.944 +     * <code>InputStream</code> for reading from that connection. This
   1.945 +     * method is a shorthand for:
   1.946 +     * <blockquote><pre>
   1.947 +     *     openConnection().getInputStream()
   1.948 +     * </pre></blockquote>
   1.949 +     *
   1.950 +     * @return     an input stream for reading from the URL connection.
   1.951 +     * @exception  IOException  if an I/O exception occurs.
   1.952 +     * @see        java.net.URL#openConnection()
   1.953 +     * @see        java.net.URLConnection#getInputStream()
   1.954 +     */
   1.955 +    public final InputStream openStream() throws java.io.IOException {
   1.956 +        throw new IOException();
   1.957 +//        return openConnection().getInputStream();
   1.958 +    }
   1.959 +
   1.960 +    /**
   1.961 +     * Gets the contents of this URL. This method is a shorthand for:
   1.962 +     * <blockquote><pre>
   1.963 +     *     openConnection().getContent()
   1.964 +     * </pre></blockquote>
   1.965 +     *
   1.966 +     * @return     the contents of this URL.
   1.967 +     * @exception  IOException  if an I/O exception occurs.
   1.968 +     * @see        java.net.URLConnection#getContent()
   1.969 +     */
   1.970 +    public final Object getContent() throws java.io.IOException {
   1.971 +        return loadText(toExternalForm());
   1.972 +    }
   1.973 +    
   1.974 +    @JavaScriptBody(args = "url", body = ""
   1.975 +        + "var request = new XMLHttpRequest();\n"
   1.976 +        + "request.open('GET', url, false);\n"
   1.977 +        + "request.send();\n"
   1.978 +        + "return request.responseText;\n"
   1.979 +    )
   1.980 +    private static native String loadText(String url) throws IOException;
   1.981 +
   1.982 +    /**
   1.983 +     * Gets the contents of this URL. This method is a shorthand for:
   1.984 +     * <blockquote><pre>
   1.985 +     *     openConnection().getContent(Class[])
   1.986 +     * </pre></blockquote>
   1.987 +     *
   1.988 +     * @param classes an array of Java types
   1.989 +     * @return     the content object of this URL that is the first match of
   1.990 +     *               the types specified in the classes array.
   1.991 +     *               null if none of the requested types are supported.
   1.992 +     * @exception  IOException  if an I/O exception occurs.
   1.993 +     * @see        java.net.URLConnection#getContent(Class[])
   1.994 +     * @since 1.3
   1.995 +     */
   1.996 +    public final Object getContent(Class[] classes)
   1.997 +    throws java.io.IOException {
   1.998 +        for (Class<?> c : classes) {
   1.999 +            if (c == String.class) {
  1.1000 +                return getContent();
  1.1001 +            }
  1.1002 +        }
  1.1003 +        return null;
  1.1004 +    }
  1.1005 +
  1.1006 +    static URLStreamHandler getURLStreamHandler(String protocol) {
  1.1007 +        URLStreamHandler universal = new URLStreamHandler() {};
  1.1008 +        return universal;
  1.1009 +    }
  1.1010 +
  1.1011 +}
  1.1012 +
  1.1013 +class Parts {
  1.1014 +    String path, query, ref;
  1.1015 +
  1.1016 +    Parts(String file) {
  1.1017 +        int ind = file.indexOf('#');
  1.1018 +        ref = ind < 0 ? null: file.substring(ind + 1);
  1.1019 +        file = ind < 0 ? file: file.substring(0, ind);
  1.1020 +        int q = file.lastIndexOf('?');
  1.1021 +        if (q != -1) {
  1.1022 +            query = file.substring(q+1);
  1.1023 +            path = file.substring(0, q);
  1.1024 +        } else {
  1.1025 +            path = file;
  1.1026 +        }
  1.1027 +    }
  1.1028 +
  1.1029 +    String getPath() {
  1.1030 +        return path;
  1.1031 +    }
  1.1032 +
  1.1033 +    String getQuery() {
  1.1034 +        return query;
  1.1035 +    }
  1.1036 +
  1.1037 +    String getRef() {
  1.1038 +        return ref;
  1.1039 +    }
  1.1040 +}