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 2396: Uniform 74 * Resource Identifiers (URI): Generic Syntax</i></a>, amended by <a 75 * href="http://www.ietf.org/rfc/rfc2732.txt"><i>RFC 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 2732</a>; 236 * However, the literal IPv6 address format defined in <a 237 * href="http://www.ietf.org/rfc/rfc2373.txt"><i>RFC 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 * <<i>package</i>>.<<i>protocol</i>>.Handler 266 * </pre></blockquote> 267 * where <<i>package</i>> is replaced by the name of the package 268 * and <<i>protocol</i>> 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 * <<i>system default package</i>>.<<i>protocol</i>>.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 "Uniform Resource Identifiers : Generic * Syntax" : 445 * <blockquote><pre> 446 * <scheme>://<authority><path>?<query>#<fragment> 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 * "/" 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 ".." and ".". 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