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