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