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