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