1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/emul/src/main/java/java/net/URL.java Tue Oct 30 09:14:17 2012 +0100
1.3 @@ -0,0 +1,1310 @@
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 java.io.OutputStream;
1.34 +import java.util.Hashtable;
1.35 +import java.util.StringTokenizer;
1.36 +import sun.security.util.SecurityConstants;
1.37 +
1.38 +/**
1.39 + * Class <code>URL</code> represents a Uniform Resource
1.40 + * Locator, a pointer to a "resource" on the World
1.41 + * Wide Web. A resource can be something as simple as a file or a
1.42 + * directory, or it can be a reference to a more complicated object,
1.43 + * such as a query to a database or to a search engine. More
1.44 + * information on the types of URLs and their formats can be found at:
1.45 + * <blockquote>
1.46 + * <a href="http://www.socs.uts.edu.au/MosaicDocs-old/url-primer.html">
1.47 + * <i>http://www.socs.uts.edu.au/MosaicDocs-old/url-primer.html</i></a>
1.48 + * </blockquote>
1.49 + * <p>
1.50 + * In general, a URL can be broken into several parts. The previous
1.51 + * example of a URL indicates that the protocol to use is
1.52 + * <code>http</code> (HyperText Transfer Protocol) and that the
1.53 + * information resides on a host machine named
1.54 + * <code>www.socs.uts.edu.au</code>. The information on that host
1.55 + * machine is named <code>/MosaicDocs-old/url-primer.html</code>. The exact
1.56 + * meaning of this name on the host machine is both protocol
1.57 + * dependent and host dependent. The information normally resides in
1.58 + * a file, but it could be generated on the fly. This component of
1.59 + * the URL is called the <i>path</i> component.
1.60 + * <p>
1.61 + * A URL can optionally specify a "port", which is the
1.62 + * port number to which the TCP connection is made on the remote host
1.63 + * machine. If the port is not specified, the default port for
1.64 + * the protocol is used instead. For example, the default port for
1.65 + * <code>http</code> is <code>80</code>. An alternative port could be
1.66 + * specified as:
1.67 + * <blockquote><pre>
1.68 + * http://www.socs.uts.edu.au:80/MosaicDocs-old/url-primer.html
1.69 + * </pre></blockquote>
1.70 + * <p>
1.71 + * The syntax of <code>URL</code> is defined by <a
1.72 + * href="http://www.ietf.org/rfc/rfc2396.txt"><i>RFC 2396: Uniform
1.73 + * Resource Identifiers (URI): Generic Syntax</i></a>, amended by <a
1.74 + * href="http://www.ietf.org/rfc/rfc2732.txt"><i>RFC 2732: Format for
1.75 + * Literal IPv6 Addresses in URLs</i></a>. The Literal IPv6 address format
1.76 + * also supports scope_ids. The syntax and usage of scope_ids is described
1.77 + * <a href="Inet6Address.html#scoped">here</a>.
1.78 + * <p>
1.79 + * A URL may have appended to it a "fragment", also known
1.80 + * as a "ref" or a "reference". The fragment is indicated by the sharp
1.81 + * sign character "#" followed by more characters. For example,
1.82 + * <blockquote><pre>
1.83 + * http://java.sun.com/index.html#chapter1
1.84 + * </pre></blockquote>
1.85 + * <p>
1.86 + * This fragment is not technically part of the URL. Rather, it
1.87 + * indicates that after the specified resource is retrieved, the
1.88 + * application is specifically interested in that part of the
1.89 + * document that has the tag <code>chapter1</code> attached to it. The
1.90 + * meaning of a tag is resource specific.
1.91 + * <p>
1.92 + * An application can also specify a "relative URL",
1.93 + * which contains only enough information to reach the resource
1.94 + * relative to another URL. Relative URLs are frequently used within
1.95 + * HTML pages. For example, if the contents of the URL:
1.96 + * <blockquote><pre>
1.97 + * http://java.sun.com/index.html
1.98 + * </pre></blockquote>
1.99 + * contained within it the relative URL:
1.100 + * <blockquote><pre>
1.101 + * FAQ.html
1.102 + * </pre></blockquote>
1.103 + * it would be a shorthand for:
1.104 + * <blockquote><pre>
1.105 + * http://java.sun.com/FAQ.html
1.106 + * </pre></blockquote>
1.107 + * <p>
1.108 + * The relative URL need not specify all the components of a URL. If
1.109 + * the protocol, host name, or port number is missing, the value is
1.110 + * inherited from the fully specified URL. The file component must be
1.111 + * specified. The optional fragment is not inherited.
1.112 + * <p>
1.113 + * The URL class does not itself encode or decode any URL components
1.114 + * according to the escaping mechanism defined in RFC2396. It is the
1.115 + * responsibility of the caller to encode any fields, which need to be
1.116 + * escaped prior to calling URL, and also to decode any escaped fields,
1.117 + * that are returned from URL. Furthermore, because URL has no knowledge
1.118 + * of URL escaping, it does not recognise equivalence between the encoded
1.119 + * or decoded form of the same URL. For example, the two URLs:<br>
1.120 + * <pre> http://foo.com/hello world/ and http://foo.com/hello%20world</pre>
1.121 + * would be considered not equal to each other.
1.122 + * <p>
1.123 + * Note, the {@link java.net.URI} class does perform escaping of its
1.124 + * component fields in certain circumstances. The recommended way
1.125 + * to manage the encoding and decoding of URLs is to use {@link java.net.URI},
1.126 + * and to convert between these two classes using {@link #toURI()} and
1.127 + * {@link URI#toURL()}.
1.128 + * <p>
1.129 + * The {@link URLEncoder} and {@link URLDecoder} classes can also be
1.130 + * used, but only for HTML form encoding, which is not the same
1.131 + * as the encoding scheme defined in RFC2396.
1.132 + *
1.133 + * @author James Gosling
1.134 + * @since JDK1.0
1.135 + */
1.136 +public final class URL implements java.io.Serializable {
1.137 +
1.138 + static final long serialVersionUID = -7627629688361524110L;
1.139 +
1.140 + /**
1.141 + * The property which specifies the package prefix list to be scanned
1.142 + * for protocol handlers. The value of this property (if any) should
1.143 + * be a vertical bar delimited list of package names to search through
1.144 + * for a protocol handler to load. The policy of this class is that
1.145 + * all protocol handlers will be in a class called <protocolname>.Handler,
1.146 + * and each package in the list is examined in turn for a matching
1.147 + * handler. If none are found (or the property is not specified), the
1.148 + * default package prefix, sun.net.www.protocol, is used. The search
1.149 + * proceeds from the first package in the list to the last and stops
1.150 + * when a match is found.
1.151 + */
1.152 + private static final String protocolPathProp = "java.protocol.handler.pkgs";
1.153 +
1.154 + /**
1.155 + * The protocol to use (ftp, http, nntp, ... etc.) .
1.156 + * @serial
1.157 + */
1.158 + private String protocol;
1.159 +
1.160 + /**
1.161 + * The host name to connect to.
1.162 + * @serial
1.163 + */
1.164 + private String host;
1.165 +
1.166 + /**
1.167 + * The protocol port to connect to.
1.168 + * @serial
1.169 + */
1.170 + private int port = -1;
1.171 +
1.172 + /**
1.173 + * The specified file name on that host. <code>file</code> is
1.174 + * defined as <code>path[?query]</code>
1.175 + * @serial
1.176 + */
1.177 + private String file;
1.178 +
1.179 + /**
1.180 + * The query part of this URL.
1.181 + */
1.182 + private transient String query;
1.183 +
1.184 + /**
1.185 + * The authority part of this URL.
1.186 + * @serial
1.187 + */
1.188 + private String authority;
1.189 +
1.190 + /**
1.191 + * The path part of this URL.
1.192 + */
1.193 + private transient String path;
1.194 +
1.195 + /**
1.196 + * The userinfo part of this URL.
1.197 + */
1.198 + private transient String userInfo;
1.199 +
1.200 + /**
1.201 + * # reference.
1.202 + * @serial
1.203 + */
1.204 + private String ref;
1.205 +
1.206 + /**
1.207 + * The host's IP address, used in equals and hashCode.
1.208 + * Computed on demand. An uninitialized or unknown hostAddress is null.
1.209 + */
1.210 + transient InetAddress hostAddress;
1.211 +
1.212 + /**
1.213 + * The URLStreamHandler for this URL.
1.214 + */
1.215 + transient URLStreamHandler handler;
1.216 +
1.217 + /* Our hash code.
1.218 + * @serial
1.219 + */
1.220 + private int hashCode = -1;
1.221 +
1.222 + /**
1.223 + * Creates a <code>URL</code> object from the specified
1.224 + * <code>protocol</code>, <code>host</code>, <code>port</code>
1.225 + * number, and <code>file</code>.<p>
1.226 + *
1.227 + * <code>host</code> can be expressed as a host name or a literal
1.228 + * IP address. If IPv6 literal address is used, it should be
1.229 + * enclosed in square brackets (<tt>'['</tt> and <tt>']'</tt>), as
1.230 + * specified by <a
1.231 + * href="http://www.ietf.org/rfc/rfc2732.txt">RFC 2732</a>;
1.232 + * However, the literal IPv6 address format defined in <a
1.233 + * href="http://www.ietf.org/rfc/rfc2373.txt"><i>RFC 2373: IP
1.234 + * Version 6 Addressing Architecture</i></a> is also accepted.<p>
1.235 + *
1.236 + * Specifying a <code>port</code> number of <code>-1</code>
1.237 + * indicates that the URL should use the default port for the
1.238 + * protocol.<p>
1.239 + *
1.240 + * If this is the first URL object being created with the specified
1.241 + * protocol, a <i>stream protocol handler</i> object, an instance of
1.242 + * class <code>URLStreamHandler</code>, is created for that protocol:
1.243 + * <ol>
1.244 + * <li>If the application has previously set up an instance of
1.245 + * <code>URLStreamHandlerFactory</code> as the stream handler factory,
1.246 + * then the <code>createURLStreamHandler</code> method of that instance
1.247 + * is called with the protocol string as an argument to create the
1.248 + * stream protocol handler.
1.249 + * <li>If no <code>URLStreamHandlerFactory</code> has yet been set up,
1.250 + * or if the factory's <code>createURLStreamHandler</code> method
1.251 + * returns <code>null</code>, then the constructor finds the
1.252 + * value of the system property:
1.253 + * <blockquote><pre>
1.254 + * java.protocol.handler.pkgs
1.255 + * </pre></blockquote>
1.256 + * If the value of that system property is not <code>null</code>,
1.257 + * it is interpreted as a list of packages separated by a vertical
1.258 + * slash character '<code>|</code>'. The constructor tries to load
1.259 + * the class named:
1.260 + * <blockquote><pre>
1.261 + * <<i>package</i>>.<<i>protocol</i>>.Handler
1.262 + * </pre></blockquote>
1.263 + * where <<i>package</i>> is replaced by the name of the package
1.264 + * and <<i>protocol</i>> is replaced by the name of the protocol.
1.265 + * If this class does not exist, or if the class exists but it is not
1.266 + * a subclass of <code>URLStreamHandler</code>, then the next package
1.267 + * in the list is tried.
1.268 + * <li>If the previous step fails to find a protocol handler, then the
1.269 + * constructor tries to load from a system default package.
1.270 + * <blockquote><pre>
1.271 + * <<i>system default package</i>>.<<i>protocol</i>>.Handler
1.272 + * </pre></blockquote>
1.273 + * If this class does not exist, or if the class exists but it is not a
1.274 + * subclass of <code>URLStreamHandler</code>, then a
1.275 + * <code>MalformedURLException</code> is thrown.
1.276 + * </ol>
1.277 + *
1.278 + * <p>Protocol handlers for the following protocols are guaranteed
1.279 + * to exist on the search path :-
1.280 + * <blockquote><pre>
1.281 + * http, https, ftp, file, and jar
1.282 + * </pre></blockquote>
1.283 + * Protocol handlers for additional protocols may also be
1.284 + * available.
1.285 + *
1.286 + * <p>No validation of the inputs is performed by this constructor.
1.287 + *
1.288 + * @param protocol the name of the protocol to use.
1.289 + * @param host the name of the host.
1.290 + * @param port the port number on the host.
1.291 + * @param file the file on the host
1.292 + * @exception MalformedURLException if an unknown protocol is specified.
1.293 + * @see java.lang.System#getProperty(java.lang.String)
1.294 + * @see java.net.URL#setURLStreamHandlerFactory(
1.295 + * java.net.URLStreamHandlerFactory)
1.296 + * @see java.net.URLStreamHandler
1.297 + * @see java.net.URLStreamHandlerFactory#createURLStreamHandler(
1.298 + * java.lang.String)
1.299 + */
1.300 + public URL(String protocol, String host, int port, String file)
1.301 + throws MalformedURLException
1.302 + {
1.303 + this(protocol, host, port, file, null);
1.304 + }
1.305 +
1.306 + /**
1.307 + * Creates a URL from the specified <code>protocol</code>
1.308 + * name, <code>host</code> name, and <code>file</code> name. The
1.309 + * default port for the specified protocol is used.
1.310 + * <p>
1.311 + * This method is equivalent to calling the four-argument
1.312 + * constructor with the arguments being <code>protocol</code>,
1.313 + * <code>host</code>, <code>-1</code>, and <code>file</code>.
1.314 + *
1.315 + * No validation of the inputs is performed by this constructor.
1.316 + *
1.317 + * @param protocol the name of the protocol to use.
1.318 + * @param host the name of the host.
1.319 + * @param file the file on the host.
1.320 + * @exception MalformedURLException if an unknown protocol is specified.
1.321 + * @see java.net.URL#URL(java.lang.String, java.lang.String,
1.322 + * int, java.lang.String)
1.323 + */
1.324 + public URL(String protocol, String host, String file)
1.325 + throws MalformedURLException {
1.326 + this(protocol, host, -1, file);
1.327 + }
1.328 +
1.329 + /**
1.330 + * Creates a <code>URL</code> object from the specified
1.331 + * <code>protocol</code>, <code>host</code>, <code>port</code>
1.332 + * number, <code>file</code>, and <code>handler</code>. Specifying
1.333 + * a <code>port</code> number of <code>-1</code> indicates that
1.334 + * the URL should use the default port for the protocol. Specifying
1.335 + * a <code>handler</code> of <code>null</code> indicates that the URL
1.336 + * should use a default stream handler for the protocol, as outlined
1.337 + * for:
1.338 + * java.net.URL#URL(java.lang.String, java.lang.String, int,
1.339 + * java.lang.String)
1.340 + *
1.341 + * <p>If the handler is not null and there is a security manager,
1.342 + * the security manager's <code>checkPermission</code>
1.343 + * method is called with a
1.344 + * <code>NetPermission("specifyStreamHandler")</code> permission.
1.345 + * This may result in a SecurityException.
1.346 + *
1.347 + * No validation of the inputs is performed by this constructor.
1.348 + *
1.349 + * @param protocol the name of the protocol to use.
1.350 + * @param host the name of the host.
1.351 + * @param port the port number on the host.
1.352 + * @param file the file on the host
1.353 + * @param handler the stream handler for the URL.
1.354 + * @exception MalformedURLException if an unknown protocol is specified.
1.355 + * @exception SecurityException
1.356 + * if a security manager exists and its
1.357 + * <code>checkPermission</code> method doesn't allow
1.358 + * specifying a stream handler explicitly.
1.359 + * @see java.lang.System#getProperty(java.lang.String)
1.360 + * @see java.net.URL#setURLStreamHandlerFactory(
1.361 + * java.net.URLStreamHandlerFactory)
1.362 + * @see java.net.URLStreamHandler
1.363 + * @see java.net.URLStreamHandlerFactory#createURLStreamHandler(
1.364 + * java.lang.String)
1.365 + * @see SecurityManager#checkPermission
1.366 + * @see java.net.NetPermission
1.367 + */
1.368 + public URL(String protocol, String host, int port, String file,
1.369 + URLStreamHandler handler) throws MalformedURLException {
1.370 + if (handler != null) {
1.371 + SecurityManager sm = System.getSecurityManager();
1.372 + if (sm != null) {
1.373 + // check for permission to specify a handler
1.374 + checkSpecifyHandler(sm);
1.375 + }
1.376 + }
1.377 +
1.378 + protocol = protocol.toLowerCase();
1.379 + this.protocol = protocol;
1.380 + if (host != null) {
1.381 +
1.382 + /**
1.383 + * if host is a literal IPv6 address,
1.384 + * we will make it conform to RFC 2732
1.385 + */
1.386 + if (host.indexOf(':') >= 0 && !host.startsWith("[")) {
1.387 + host = "["+host+"]";
1.388 + }
1.389 + this.host = host;
1.390 +
1.391 + if (port < -1) {
1.392 + throw new MalformedURLException("Invalid port number :" +
1.393 + port);
1.394 + }
1.395 + this.port = port;
1.396 + authority = (port == -1) ? host : host + ":" + port;
1.397 + }
1.398 +
1.399 + Parts parts = new Parts(file);
1.400 + path = parts.getPath();
1.401 + query = parts.getQuery();
1.402 +
1.403 + if (query != null) {
1.404 + this.file = path + "?" + query;
1.405 + } else {
1.406 + this.file = path;
1.407 + }
1.408 + ref = parts.getRef();
1.409 +
1.410 + // Note: we don't do validation of the URL here. Too risky to change
1.411 + // right now, but worth considering for future reference. -br
1.412 + if (handler == null &&
1.413 + (handler = getURLStreamHandler(protocol)) == null) {
1.414 + throw new MalformedURLException("unknown protocol: " + protocol);
1.415 + }
1.416 + this.handler = handler;
1.417 + }
1.418 +
1.419 + /**
1.420 + * Creates a <code>URL</code> object from the <code>String</code>
1.421 + * representation.
1.422 + * <p>
1.423 + * This constructor is equivalent to a call to the two-argument
1.424 + * constructor with a <code>null</code> first argument.
1.425 + *
1.426 + * @param spec the <code>String</code> to parse as a URL.
1.427 + * @exception MalformedURLException if no protocol is specified, or an
1.428 + * unknown protocol is found, or <tt>spec</tt> is <tt>null</tt>.
1.429 + * @see java.net.URL#URL(java.net.URL, java.lang.String)
1.430 + */
1.431 + public URL(String spec) throws MalformedURLException {
1.432 + this(null, spec);
1.433 + }
1.434 +
1.435 + /**
1.436 + * Creates a URL by parsing the given spec within a specified context.
1.437 + *
1.438 + * The new URL is created from the given context URL and the spec
1.439 + * argument as described in
1.440 + * RFC2396 "Uniform Resource Identifiers : Generic * Syntax" :
1.441 + * <blockquote><pre>
1.442 + * <scheme>://<authority><path>?<query>#<fragment>
1.443 + * </pre></blockquote>
1.444 + * The reference is parsed into the scheme, authority, path, query and
1.445 + * fragment parts. If the path component is empty and the scheme,
1.446 + * authority, and query components are undefined, then the new URL is a
1.447 + * reference to the current document. Otherwise, the fragment and query
1.448 + * parts present in the spec are used in the new URL.
1.449 + * <p>
1.450 + * If the scheme component is defined in the given spec and does not match
1.451 + * the scheme of the context, then the new URL is created as an absolute
1.452 + * URL based on the spec alone. Otherwise the scheme component is inherited
1.453 + * from the context URL.
1.454 + * <p>
1.455 + * If the authority component is present in the spec then the spec is
1.456 + * treated as absolute and the spec authority and path will replace the
1.457 + * context authority and path. If the authority component is absent in the
1.458 + * spec then the authority of the new URL will be inherited from the
1.459 + * context.
1.460 + * <p>
1.461 + * If the spec's path component begins with a slash character
1.462 + * "/" then the
1.463 + * path is treated as absolute and the spec path replaces the context path.
1.464 + * <p>
1.465 + * Otherwise, the path is treated as a relative path and is appended to the
1.466 + * context path, as described in RFC2396. Also, in this case,
1.467 + * the path is canonicalized through the removal of directory
1.468 + * changes made by occurences of ".." and ".".
1.469 + * <p>
1.470 + * For a more detailed description of URL parsing, refer to RFC2396.
1.471 + *
1.472 + * @param context the context in which to parse the specification.
1.473 + * @param spec the <code>String</code> to parse as a URL.
1.474 + * @exception MalformedURLException if no protocol is specified, or an
1.475 + * unknown protocol is found, or <tt>spec</tt> is <tt>null</tt>.
1.476 + * @see java.net.URL#URL(java.lang.String, java.lang.String,
1.477 + * int, java.lang.String)
1.478 + * @see java.net.URLStreamHandler
1.479 + * @see java.net.URLStreamHandler#parseURL(java.net.URL,
1.480 + * java.lang.String, int, int)
1.481 + */
1.482 + public URL(URL context, String spec) throws MalformedURLException {
1.483 + this(context, spec, null);
1.484 + }
1.485 +
1.486 + /**
1.487 + * Creates a URL by parsing the given spec with the specified handler
1.488 + * within a specified context. If the handler is null, the parsing
1.489 + * occurs as with the two argument constructor.
1.490 + *
1.491 + * @param context the context in which to parse the specification.
1.492 + * @param spec the <code>String</code> to parse as a URL.
1.493 + * @param handler the stream handler for the URL.
1.494 + * @exception MalformedURLException if no protocol is specified, or an
1.495 + * unknown protocol is found, or <tt>spec</tt> is <tt>null</tt>.
1.496 + * @exception SecurityException
1.497 + * if a security manager exists and its
1.498 + * <code>checkPermission</code> method doesn't allow
1.499 + * specifying a stream handler.
1.500 + * @see java.net.URL#URL(java.lang.String, java.lang.String,
1.501 + * int, java.lang.String)
1.502 + * @see java.net.URLStreamHandler
1.503 + * @see java.net.URLStreamHandler#parseURL(java.net.URL,
1.504 + * java.lang.String, int, int)
1.505 + */
1.506 + public URL(URL context, String spec, URLStreamHandler handler)
1.507 + throws MalformedURLException
1.508 + {
1.509 + String original = spec;
1.510 + int i, limit, c;
1.511 + int start = 0;
1.512 + String newProtocol = null;
1.513 + boolean aRef=false;
1.514 + boolean isRelative = false;
1.515 +
1.516 + // Check for permission to specify a handler
1.517 + if (handler != null) {
1.518 + SecurityManager sm = System.getSecurityManager();
1.519 + if (sm != null) {
1.520 + checkSpecifyHandler(sm);
1.521 + }
1.522 + }
1.523 +
1.524 + try {
1.525 + limit = spec.length();
1.526 + while ((limit > 0) && (spec.charAt(limit - 1) <= ' ')) {
1.527 + limit--; //eliminate trailing whitespace
1.528 + }
1.529 + while ((start < limit) && (spec.charAt(start) <= ' ')) {
1.530 + start++; // eliminate leading whitespace
1.531 + }
1.532 +
1.533 + if (spec.regionMatches(true, start, "url:", 0, 4)) {
1.534 + start += 4;
1.535 + }
1.536 + if (start < spec.length() && spec.charAt(start) == '#') {
1.537 + /* we're assuming this is a ref relative to the context URL.
1.538 + * This means protocols cannot start w/ '#', but we must parse
1.539 + * ref URL's like: "hello:there" w/ a ':' in them.
1.540 + */
1.541 + aRef=true;
1.542 + }
1.543 + for (i = start ; !aRef && (i < limit) &&
1.544 + ((c = spec.charAt(i)) != '/') ; i++) {
1.545 + if (c == ':') {
1.546 +
1.547 + String s = spec.substring(start, i).toLowerCase();
1.548 + if (isValidProtocol(s)) {
1.549 + newProtocol = s;
1.550 + start = i + 1;
1.551 + }
1.552 + break;
1.553 + }
1.554 + }
1.555 +
1.556 + // Only use our context if the protocols match.
1.557 + protocol = newProtocol;
1.558 + if ((context != null) && ((newProtocol == null) ||
1.559 + newProtocol.equalsIgnoreCase(context.protocol))) {
1.560 + // inherit the protocol handler from the context
1.561 + // if not specified to the constructor
1.562 + if (handler == null) {
1.563 + handler = context.handler;
1.564 + }
1.565 +
1.566 + // If the context is a hierarchical URL scheme and the spec
1.567 + // contains a matching scheme then maintain backwards
1.568 + // compatibility and treat it as if the spec didn't contain
1.569 + // the scheme; see 5.2.3 of RFC2396
1.570 + if (context.path != null && context.path.startsWith("/"))
1.571 + newProtocol = null;
1.572 +
1.573 + if (newProtocol == null) {
1.574 + protocol = context.protocol;
1.575 + authority = context.authority;
1.576 + userInfo = context.userInfo;
1.577 + host = context.host;
1.578 + port = context.port;
1.579 + file = context.file;
1.580 + path = context.path;
1.581 + isRelative = true;
1.582 + }
1.583 + }
1.584 +
1.585 + if (protocol == null) {
1.586 + throw new MalformedURLException("no protocol: "+original);
1.587 + }
1.588 +
1.589 + // Get the protocol handler if not specified or the protocol
1.590 + // of the context could not be used
1.591 + if (handler == null &&
1.592 + (handler = getURLStreamHandler(protocol)) == null) {
1.593 + throw new MalformedURLException("unknown protocol: "+protocol);
1.594 + }
1.595 +
1.596 + this.handler = handler;
1.597 +
1.598 + i = spec.indexOf('#', start);
1.599 + if (i >= 0) {
1.600 + ref = spec.substring(i + 1, limit);
1.601 + limit = i;
1.602 + }
1.603 +
1.604 + /*
1.605 + * Handle special case inheritance of query and fragment
1.606 + * implied by RFC2396 section 5.2.2.
1.607 + */
1.608 + if (isRelative && start == limit) {
1.609 + query = context.query;
1.610 + if (ref == null) {
1.611 + ref = context.ref;
1.612 + }
1.613 + }
1.614 +
1.615 + handler.parseURL(this, spec, start, limit);
1.616 +
1.617 + } catch(MalformedURLException e) {
1.618 + throw e;
1.619 + } catch(Exception e) {
1.620 + MalformedURLException exception = new MalformedURLException(e.getMessage());
1.621 + exception.initCause(e);
1.622 + throw exception;
1.623 + }
1.624 + }
1.625 +
1.626 + /*
1.627 + * Returns true if specified string is a valid protocol name.
1.628 + */
1.629 + private boolean isValidProtocol(String protocol) {
1.630 + int len = protocol.length();
1.631 + if (len < 1)
1.632 + return false;
1.633 + char c = protocol.charAt(0);
1.634 + if (!Character.isLetter(c))
1.635 + return false;
1.636 + for (int i = 1; i < len; i++) {
1.637 + c = protocol.charAt(i);
1.638 + if (!Character.isLetterOrDigit(c) && c != '.' && c != '+' &&
1.639 + c != '-') {
1.640 + return false;
1.641 + }
1.642 + }
1.643 + return true;
1.644 + }
1.645 +
1.646 + /*
1.647 + * Checks for permission to specify a stream handler.
1.648 + */
1.649 + private void checkSpecifyHandler(SecurityManager sm) {
1.650 + sm.checkPermission(SecurityConstants.SPECIFY_HANDLER_PERMISSION);
1.651 + }
1.652 +
1.653 + /**
1.654 + * Sets the fields of the URL. This is not a public method so that
1.655 + * only URLStreamHandlers can modify URL fields. URLs are
1.656 + * otherwise constant.
1.657 + *
1.658 + * @param protocol the name of the protocol to use
1.659 + * @param host the name of the host
1.660 + @param port the port number on the host
1.661 + * @param file the file on the host
1.662 + * @param ref the internal reference in the URL
1.663 + */
1.664 + protected void set(String protocol, String host,
1.665 + int port, String file, String ref) {
1.666 + synchronized (this) {
1.667 + this.protocol = protocol;
1.668 + this.host = host;
1.669 + authority = port == -1 ? host : host + ":" + port;
1.670 + this.port = port;
1.671 + this.file = file;
1.672 + this.ref = ref;
1.673 + /* This is very important. We must recompute this after the
1.674 + * URL has been changed. */
1.675 + hashCode = -1;
1.676 + hostAddress = null;
1.677 + int q = file.lastIndexOf('?');
1.678 + if (q != -1) {
1.679 + query = file.substring(q+1);
1.680 + path = file.substring(0, q);
1.681 + } else
1.682 + path = file;
1.683 + }
1.684 + }
1.685 +
1.686 + /**
1.687 + * Sets the specified 8 fields of the URL. This is not a public method so
1.688 + * that only URLStreamHandlers can modify URL fields. URLs are otherwise
1.689 + * constant.
1.690 + *
1.691 + * @param protocol the name of the protocol to use
1.692 + * @param host the name of the host
1.693 + * @param port the port number on the host
1.694 + * @param authority the authority part for the url
1.695 + * @param userInfo the username and password
1.696 + * @param path the file on the host
1.697 + * @param ref the internal reference in the URL
1.698 + * @param query the query part of this URL
1.699 + * @since 1.3
1.700 + */
1.701 + protected void set(String protocol, String host, int port,
1.702 + String authority, String userInfo, String path,
1.703 + String query, String ref) {
1.704 + synchronized (this) {
1.705 + this.protocol = protocol;
1.706 + this.host = host;
1.707 + this.port = port;
1.708 + this.file = query == null ? path : path + "?" + query;
1.709 + this.userInfo = userInfo;
1.710 + this.path = path;
1.711 + this.ref = ref;
1.712 + /* This is very important. We must recompute this after the
1.713 + * URL has been changed. */
1.714 + hashCode = -1;
1.715 + hostAddress = null;
1.716 + this.query = query;
1.717 + this.authority = authority;
1.718 + }
1.719 + }
1.720 +
1.721 + /**
1.722 + * Gets the query part of this <code>URL</code>.
1.723 + *
1.724 + * @return the query part of this <code>URL</code>,
1.725 + * or <CODE>null</CODE> if one does not exist
1.726 + * @since 1.3
1.727 + */
1.728 + public String getQuery() {
1.729 + return query;
1.730 + }
1.731 +
1.732 + /**
1.733 + * Gets the path part of this <code>URL</code>.
1.734 + *
1.735 + * @return the path part of this <code>URL</code>, or an
1.736 + * empty string if one does not exist
1.737 + * @since 1.3
1.738 + */
1.739 + public String getPath() {
1.740 + return path;
1.741 + }
1.742 +
1.743 + /**
1.744 + * Gets the userInfo part of this <code>URL</code>.
1.745 + *
1.746 + * @return the userInfo part of this <code>URL</code>, or
1.747 + * <CODE>null</CODE> if one does not exist
1.748 + * @since 1.3
1.749 + */
1.750 + public String getUserInfo() {
1.751 + return userInfo;
1.752 + }
1.753 +
1.754 + /**
1.755 + * Gets the authority part of this <code>URL</code>.
1.756 + *
1.757 + * @return the authority part of this <code>URL</code>
1.758 + * @since 1.3
1.759 + */
1.760 + public String getAuthority() {
1.761 + return authority;
1.762 + }
1.763 +
1.764 + /**
1.765 + * Gets the port number of this <code>URL</code>.
1.766 + *
1.767 + * @return the port number, or -1 if the port is not set
1.768 + */
1.769 + public int getPort() {
1.770 + return port;
1.771 + }
1.772 +
1.773 + /**
1.774 + * Gets the default port number of the protocol associated
1.775 + * with this <code>URL</code>. If the URL scheme or the URLStreamHandler
1.776 + * for the URL do not define a default port number,
1.777 + * then -1 is returned.
1.778 + *
1.779 + * @return the port number
1.780 + * @since 1.4
1.781 + */
1.782 + public int getDefaultPort() {
1.783 + return handler.getDefaultPort();
1.784 + }
1.785 +
1.786 + /**
1.787 + * Gets the protocol name of this <code>URL</code>.
1.788 + *
1.789 + * @return the protocol of this <code>URL</code>.
1.790 + */
1.791 + public String getProtocol() {
1.792 + return protocol;
1.793 + }
1.794 +
1.795 + /**
1.796 + * Gets the host name of this <code>URL</code>, if applicable.
1.797 + * The format of the host conforms to RFC 2732, i.e. for a
1.798 + * literal IPv6 address, this method will return the IPv6 address
1.799 + * enclosed in square brackets (<tt>'['</tt> and <tt>']'</tt>).
1.800 + *
1.801 + * @return the host name of this <code>URL</code>.
1.802 + */
1.803 + public String getHost() {
1.804 + return host;
1.805 + }
1.806 +
1.807 + /**
1.808 + * Gets the file name of this <code>URL</code>.
1.809 + * The returned file portion will be
1.810 + * the same as <CODE>getPath()</CODE>, plus the concatenation of
1.811 + * the value of <CODE>getQuery()</CODE>, if any. If there is
1.812 + * no query portion, this method and <CODE>getPath()</CODE> will
1.813 + * return identical results.
1.814 + *
1.815 + * @return the file name of this <code>URL</code>,
1.816 + * or an empty string if one does not exist
1.817 + */
1.818 + public String getFile() {
1.819 + return file;
1.820 + }
1.821 +
1.822 + /**
1.823 + * Gets the anchor (also known as the "reference") of this
1.824 + * <code>URL</code>.
1.825 + *
1.826 + * @return the anchor (also known as the "reference") of this
1.827 + * <code>URL</code>, or <CODE>null</CODE> if one does not exist
1.828 + */
1.829 + public String getRef() {
1.830 + return ref;
1.831 + }
1.832 +
1.833 + /**
1.834 + * Compares this URL for equality with another object.<p>
1.835 + *
1.836 + * If the given object is not a URL then this method immediately returns
1.837 + * <code>false</code>.<p>
1.838 + *
1.839 + * Two URL objects are equal if they have the same protocol, reference
1.840 + * equivalent hosts, have the same port number on the host, and the same
1.841 + * file and fragment of the file.<p>
1.842 + *
1.843 + * Two hosts are considered equivalent if both host names can be resolved
1.844 + * into the same IP addresses; else if either host name can't be
1.845 + * resolved, the host names must be equal without regard to case; or both
1.846 + * host names equal to null.<p>
1.847 + *
1.848 + * Since hosts comparison requires name resolution, this operation is a
1.849 + * blocking operation. <p>
1.850 + *
1.851 + * Note: The defined behavior for <code>equals</code> is known to
1.852 + * be inconsistent with virtual hosting in HTTP.
1.853 + *
1.854 + * @param obj the URL to compare against.
1.855 + * @return <code>true</code> if the objects are the same;
1.856 + * <code>false</code> otherwise.
1.857 + */
1.858 + public boolean equals(Object obj) {
1.859 + if (!(obj instanceof URL))
1.860 + return false;
1.861 + URL u2 = (URL)obj;
1.862 +
1.863 + return handler.equals(this, u2);
1.864 + }
1.865 +
1.866 + /**
1.867 + * Creates an integer suitable for hash table indexing.<p>
1.868 + *
1.869 + * The hash code is based upon all the URL components relevant for URL
1.870 + * comparison. As such, this operation is a blocking operation.<p>
1.871 + *
1.872 + * @return a hash code for this <code>URL</code>.
1.873 + */
1.874 + public synchronized int hashCode() {
1.875 + if (hashCode != -1)
1.876 + return hashCode;
1.877 +
1.878 + hashCode = handler.hashCode(this);
1.879 + return hashCode;
1.880 + }
1.881 +
1.882 + /**
1.883 + * Compares two URLs, excluding the fragment component.<p>
1.884 + *
1.885 + * Returns <code>true</code> if this <code>URL</code> and the
1.886 + * <code>other</code> argument are equal without taking the
1.887 + * fragment component into consideration.
1.888 + *
1.889 + * @param other the <code>URL</code> to compare against.
1.890 + * @return <code>true</code> if they reference the same remote object;
1.891 + * <code>false</code> otherwise.
1.892 + */
1.893 + public boolean sameFile(URL other) {
1.894 + return handler.sameFile(this, other);
1.895 + }
1.896 +
1.897 + /**
1.898 + * Constructs a string representation of this <code>URL</code>. The
1.899 + * string is created by calling the <code>toExternalForm</code>
1.900 + * method of the stream protocol handler for this object.
1.901 + *
1.902 + * @return a string representation of this object.
1.903 + * @see java.net.URL#URL(java.lang.String, java.lang.String, int,
1.904 + * java.lang.String)
1.905 + * @see java.net.URLStreamHandler#toExternalForm(java.net.URL)
1.906 + */
1.907 + public String toString() {
1.908 + return toExternalForm();
1.909 + }
1.910 +
1.911 + /**
1.912 + * Constructs a string representation of this <code>URL</code>. The
1.913 + * string is created by calling the <code>toExternalForm</code>
1.914 + * method of the stream protocol handler for this object.
1.915 + *
1.916 + * @return a string representation of this object.
1.917 + * @see java.net.URL#URL(java.lang.String, java.lang.String,
1.918 + * int, java.lang.String)
1.919 + * @see java.net.URLStreamHandler#toExternalForm(java.net.URL)
1.920 + */
1.921 + public String toExternalForm() {
1.922 + return handler.toExternalForm(this);
1.923 + }
1.924 +
1.925 + /**
1.926 + * Returns a {@link java.net.URI} equivalent to this URL.
1.927 + * This method functions in the same way as <code>new URI (this.toString())</code>.
1.928 + * <p>Note, any URL instance that complies with RFC 2396 can be converted
1.929 + * to a URI. However, some URLs that are not strictly in compliance
1.930 + * can not be converted to a URI.
1.931 + *
1.932 + * @exception URISyntaxException if this URL is not formatted strictly according to
1.933 + * to RFC2396 and cannot be converted to a URI.
1.934 + *
1.935 + * @return a URI instance equivalent to this URL.
1.936 + * @since 1.5
1.937 + */
1.938 + public URI toURI() throws URISyntaxException {
1.939 + return new URI (toString());
1.940 + }
1.941 +
1.942 + /**
1.943 + * Returns a {@link java.net.URLConnection URLConnection} instance that
1.944 + * represents a connection to the remote object referred to by the
1.945 + * {@code URL}.
1.946 + *
1.947 + * <P>A new instance of {@linkplain java.net.URLConnection URLConnection} is
1.948 + * created every time when invoking the
1.949 + * {@linkplain java.net.URLStreamHandler#openConnection(URL)
1.950 + * URLStreamHandler.openConnection(URL)} method of the protocol handler for
1.951 + * this URL.</P>
1.952 + *
1.953 + * <P>It should be noted that a URLConnection instance does not establish
1.954 + * the actual network connection on creation. This will happen only when
1.955 + * calling {@linkplain java.net.URLConnection#connect() URLConnection.connect()}.</P>
1.956 + *
1.957 + * <P>If for the URL's protocol (such as HTTP or JAR), there
1.958 + * exists a public, specialized URLConnection subclass belonging
1.959 + * to one of the following packages or one of their subpackages:
1.960 + * java.lang, java.io, java.util, java.net, the connection
1.961 + * returned will be of that subclass. For example, for HTTP an
1.962 + * HttpURLConnection will be returned, and for JAR a
1.963 + * JarURLConnection will be returned.</P>
1.964 + *
1.965 + * @return a {@link java.net.URLConnection URLConnection} linking
1.966 + * to the URL.
1.967 + * @exception IOException if an I/O exception occurs.
1.968 + * @see java.net.URL#URL(java.lang.String, java.lang.String,
1.969 + * int, java.lang.String)
1.970 + */
1.971 + public URLConnection openConnection() throws java.io.IOException {
1.972 + return handler.openConnection(this);
1.973 + }
1.974 +
1.975 + /**
1.976 + * Same as {@link #openConnection()}, except that the connection will be
1.977 + * made through the specified proxy; Protocol handlers that do not
1.978 + * support proxing will ignore the proxy parameter and make a
1.979 + * normal connection.
1.980 + *
1.981 + * Invoking this method preempts the system's default ProxySelector
1.982 + * settings.
1.983 + *
1.984 + * @param proxy the Proxy through which this connection
1.985 + * will be made. If direct connection is desired,
1.986 + * Proxy.NO_PROXY should be specified.
1.987 + * @return a <code>URLConnection</code> to the URL.
1.988 + * @exception IOException if an I/O exception occurs.
1.989 + * @exception SecurityException if a security manager is present
1.990 + * and the caller doesn't have permission to connect
1.991 + * to the proxy.
1.992 + * @exception IllegalArgumentException will be thrown if proxy is null,
1.993 + * or proxy has the wrong type
1.994 + * @exception UnsupportedOperationException if the subclass that
1.995 + * implements the protocol handler doesn't support
1.996 + * this method.
1.997 + * @see java.net.URL#URL(java.lang.String, java.lang.String,
1.998 + * int, java.lang.String)
1.999 + * @see java.net.URLConnection
1.1000 + * @see java.net.URLStreamHandler#openConnection(java.net.URL,
1.1001 + * java.net.Proxy)
1.1002 + * @since 1.5
1.1003 + */
1.1004 + public URLConnection openConnection(Proxy proxy)
1.1005 + throws java.io.IOException {
1.1006 + if (proxy == null) {
1.1007 + throw new IllegalArgumentException("proxy can not be null");
1.1008 + }
1.1009 +
1.1010 + // Create a copy of Proxy as a security measure
1.1011 + Proxy p = proxy == Proxy.NO_PROXY ? Proxy.NO_PROXY : sun.net.ApplicationProxy.create(proxy);
1.1012 + SecurityManager sm = System.getSecurityManager();
1.1013 + if (p.type() != Proxy.Type.DIRECT && sm != null) {
1.1014 + InetSocketAddress epoint = (InetSocketAddress) p.address();
1.1015 + if (epoint.isUnresolved())
1.1016 + sm.checkConnect(epoint.getHostName(), epoint.getPort());
1.1017 + else
1.1018 + sm.checkConnect(epoint.getAddress().getHostAddress(),
1.1019 + epoint.getPort());
1.1020 + }
1.1021 + return handler.openConnection(this, p);
1.1022 + }
1.1023 +
1.1024 + /**
1.1025 + * Opens a connection to this <code>URL</code> and returns an
1.1026 + * <code>InputStream</code> for reading from that connection. This
1.1027 + * method is a shorthand for:
1.1028 + * <blockquote><pre>
1.1029 + * openConnection().getInputStream()
1.1030 + * </pre></blockquote>
1.1031 + *
1.1032 + * @return an input stream for reading from the URL connection.
1.1033 + * @exception IOException if an I/O exception occurs.
1.1034 + * @see java.net.URL#openConnection()
1.1035 + * @see java.net.URLConnection#getInputStream()
1.1036 + */
1.1037 + public final InputStream openStream() throws java.io.IOException {
1.1038 + return openConnection().getInputStream();
1.1039 + }
1.1040 +
1.1041 + /**
1.1042 + * Gets the contents of this URL. This method is a shorthand for:
1.1043 + * <blockquote><pre>
1.1044 + * openConnection().getContent()
1.1045 + * </pre></blockquote>
1.1046 + *
1.1047 + * @return the contents of this URL.
1.1048 + * @exception IOException if an I/O exception occurs.
1.1049 + * @see java.net.URLConnection#getContent()
1.1050 + */
1.1051 + public final Object getContent() throws java.io.IOException {
1.1052 + return openConnection().getContent();
1.1053 + }
1.1054 +
1.1055 + /**
1.1056 + * Gets the contents of this URL. This method is a shorthand for:
1.1057 + * <blockquote><pre>
1.1058 + * openConnection().getContent(Class[])
1.1059 + * </pre></blockquote>
1.1060 + *
1.1061 + * @param classes an array of Java types
1.1062 + * @return the content object of this URL that is the first match of
1.1063 + * the types specified in the classes array.
1.1064 + * null if none of the requested types are supported.
1.1065 + * @exception IOException if an I/O exception occurs.
1.1066 + * @see java.net.URLConnection#getContent(Class[])
1.1067 + * @since 1.3
1.1068 + */
1.1069 + public final Object getContent(Class[] classes)
1.1070 + throws java.io.IOException {
1.1071 + return openConnection().getContent(classes);
1.1072 + }
1.1073 +
1.1074 + /**
1.1075 + * The URLStreamHandler factory.
1.1076 + */
1.1077 + static URLStreamHandlerFactory factory;
1.1078 +
1.1079 + /**
1.1080 + * Sets an application's <code>URLStreamHandlerFactory</code>.
1.1081 + * This method can be called at most once in a given Java Virtual
1.1082 + * Machine.
1.1083 + *
1.1084 + *<p> The <code>URLStreamHandlerFactory</code> instance is used to
1.1085 + *construct a stream protocol handler from a protocol name.
1.1086 + *
1.1087 + * <p> If there is a security manager, this method first calls
1.1088 + * the security manager's <code>checkSetFactory</code> method
1.1089 + * to ensure the operation is allowed.
1.1090 + * This could result in a SecurityException.
1.1091 + *
1.1092 + * @param fac the desired factory.
1.1093 + * @exception Error if the application has already set a factory.
1.1094 + * @exception SecurityException if a security manager exists and its
1.1095 + * <code>checkSetFactory</code> method doesn't allow
1.1096 + * the operation.
1.1097 + * @see java.net.URL#URL(java.lang.String, java.lang.String,
1.1098 + * int, java.lang.String)
1.1099 + * @see java.net.URLStreamHandlerFactory
1.1100 + * @see SecurityManager#checkSetFactory
1.1101 + */
1.1102 + public static void setURLStreamHandlerFactory(URLStreamHandlerFactory fac) {
1.1103 + synchronized (streamHandlerLock) {
1.1104 + if (factory != null) {
1.1105 + throw new Error("factory already defined");
1.1106 + }
1.1107 + SecurityManager security = System.getSecurityManager();
1.1108 + if (security != null) {
1.1109 + security.checkSetFactory();
1.1110 + }
1.1111 + handlers.clear();
1.1112 + factory = fac;
1.1113 + }
1.1114 + }
1.1115 +
1.1116 + /**
1.1117 + * A table of protocol handlers.
1.1118 + */
1.1119 + static Hashtable handlers = new Hashtable();
1.1120 + private static Object streamHandlerLock = new Object();
1.1121 +
1.1122 + /**
1.1123 + * Returns the Stream Handler.
1.1124 + * @param protocol the protocol to use
1.1125 + */
1.1126 + static URLStreamHandler getURLStreamHandler(String protocol) {
1.1127 +
1.1128 + URLStreamHandler handler = (URLStreamHandler)handlers.get(protocol);
1.1129 + if (handler == null) {
1.1130 +
1.1131 + boolean checkedWithFactory = false;
1.1132 +
1.1133 + // Use the factory (if any)
1.1134 + if (factory != null) {
1.1135 + handler = factory.createURLStreamHandler(protocol);
1.1136 + checkedWithFactory = true;
1.1137 + }
1.1138 +
1.1139 + // Try java protocol handler
1.1140 + if (handler == null) {
1.1141 + String packagePrefixList = null;
1.1142 +
1.1143 + packagePrefixList
1.1144 + = java.security.AccessController.doPrivileged(
1.1145 + new sun.security.action.GetPropertyAction(
1.1146 + protocolPathProp,""));
1.1147 + if (packagePrefixList != "") {
1.1148 + packagePrefixList += "|";
1.1149 + }
1.1150 +
1.1151 + // REMIND: decide whether to allow the "null" class prefix
1.1152 + // or not.
1.1153 + packagePrefixList += "sun.net.www.protocol";
1.1154 +
1.1155 + StringTokenizer packagePrefixIter =
1.1156 + new StringTokenizer(packagePrefixList, "|");
1.1157 +
1.1158 + while (handler == null &&
1.1159 + packagePrefixIter.hasMoreTokens()) {
1.1160 +
1.1161 + String packagePrefix =
1.1162 + packagePrefixIter.nextToken().trim();
1.1163 + try {
1.1164 + String clsName = packagePrefix + "." + protocol +
1.1165 + ".Handler";
1.1166 + Class cls = null;
1.1167 + try {
1.1168 + cls = Class.forName(clsName);
1.1169 + } catch (ClassNotFoundException e) {
1.1170 + ClassLoader cl = ClassLoader.getSystemClassLoader();
1.1171 + if (cl != null) {
1.1172 + cls = cl.loadClass(clsName);
1.1173 + }
1.1174 + }
1.1175 + if (cls != null) {
1.1176 + handler =
1.1177 + (URLStreamHandler)cls.newInstance();
1.1178 + }
1.1179 + } catch (Exception e) {
1.1180 + // any number of exceptions can get thrown here
1.1181 + }
1.1182 + }
1.1183 + }
1.1184 +
1.1185 + synchronized (streamHandlerLock) {
1.1186 +
1.1187 + URLStreamHandler handler2 = null;
1.1188 +
1.1189 + // Check again with hashtable just in case another
1.1190 + // thread created a handler since we last checked
1.1191 + handler2 = (URLStreamHandler)handlers.get(protocol);
1.1192 +
1.1193 + if (handler2 != null) {
1.1194 + return handler2;
1.1195 + }
1.1196 +
1.1197 + // Check with factory if another thread set a
1.1198 + // factory since our last check
1.1199 + if (!checkedWithFactory && factory != null) {
1.1200 + handler2 = factory.createURLStreamHandler(protocol);
1.1201 + }
1.1202 +
1.1203 + if (handler2 != null) {
1.1204 + // The handler from the factory must be given more
1.1205 + // importance. Discard the default handler that
1.1206 + // this thread created.
1.1207 + handler = handler2;
1.1208 + }
1.1209 +
1.1210 + // Insert this handler into the hashtable
1.1211 + if (handler != null) {
1.1212 + handlers.put(protocol, handler);
1.1213 + }
1.1214 +
1.1215 + }
1.1216 + }
1.1217 +
1.1218 + return handler;
1.1219 +
1.1220 + }
1.1221 +
1.1222 + /**
1.1223 + * WriteObject is called to save the state of the URL to an
1.1224 + * ObjectOutputStream. The handler is not saved since it is
1.1225 + * specific to this system.
1.1226 + *
1.1227 + * @serialData the default write object value. When read back in,
1.1228 + * the reader must ensure that calling getURLStreamHandler with
1.1229 + * the protocol variable returns a valid URLStreamHandler and
1.1230 + * throw an IOException if it does not.
1.1231 + */
1.1232 + private synchronized void writeObject(java.io.ObjectOutputStream s)
1.1233 + throws IOException
1.1234 + {
1.1235 + s.defaultWriteObject(); // write the fields
1.1236 + }
1.1237 +
1.1238 + /**
1.1239 + * readObject is called to restore the state of the URL from the
1.1240 + * stream. It reads the components of the URL and finds the local
1.1241 + * stream handler.
1.1242 + */
1.1243 + private synchronized void readObject(java.io.ObjectInputStream s)
1.1244 + throws IOException, ClassNotFoundException
1.1245 + {
1.1246 + s.defaultReadObject(); // read the fields
1.1247 + if ((handler = getURLStreamHandler(protocol)) == null) {
1.1248 + throw new IOException("unknown protocol: " + protocol);
1.1249 + }
1.1250 +
1.1251 + // Construct authority part
1.1252 + if (authority == null &&
1.1253 + ((host != null && host.length() > 0) || port != -1)) {
1.1254 + if (host == null)
1.1255 + host = "";
1.1256 + authority = (port == -1) ? host : host + ":" + port;
1.1257 +
1.1258 + // Handle hosts with userInfo in them
1.1259 + int at = host.lastIndexOf('@');
1.1260 + if (at != -1) {
1.1261 + userInfo = host.substring(0, at);
1.1262 + host = host.substring(at+1);
1.1263 + }
1.1264 + } else if (authority != null) {
1.1265 + // Construct user info part
1.1266 + int ind = authority.indexOf('@');
1.1267 + if (ind != -1)
1.1268 + userInfo = authority.substring(0, ind);
1.1269 + }
1.1270 +
1.1271 + // Construct path and query part
1.1272 + path = null;
1.1273 + query = null;
1.1274 + if (file != null) {
1.1275 + // Fix: only do this if hierarchical?
1.1276 + int q = file.lastIndexOf('?');
1.1277 + if (q != -1) {
1.1278 + query = file.substring(q+1);
1.1279 + path = file.substring(0, q);
1.1280 + } else
1.1281 + path = file;
1.1282 + }
1.1283 + }
1.1284 +}
1.1285 +
1.1286 +class Parts {
1.1287 + String path, query, ref;
1.1288 +
1.1289 + Parts(String file) {
1.1290 + int ind = file.indexOf('#');
1.1291 + ref = ind < 0 ? null: file.substring(ind + 1);
1.1292 + file = ind < 0 ? file: file.substring(0, ind);
1.1293 + int q = file.lastIndexOf('?');
1.1294 + if (q != -1) {
1.1295 + query = file.substring(q+1);
1.1296 + path = file.substring(0, q);
1.1297 + } else {
1.1298 + path = file;
1.1299 + }
1.1300 + }
1.1301 +
1.1302 + String getPath() {
1.1303 + return path;
1.1304 + }
1.1305 +
1.1306 + String getQuery() {
1.1307 + return query;
1.1308 + }
1.1309 +
1.1310 + String getRef() {
1.1311 + return ref;
1.1312 + }
1.1313 +}