1. /*
  2. * @(#)URL.java 1.80 01/11/29
  3. *
  4. * Copyright 2002 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. /**
  14. * Class <code>URL</code> represents a Uniform Resource
  15. * Locator, a pointer to a "resource" on the World
  16. * Wide Web. A resource can be something as simple as a file or a
  17. * directory, or it can be a reference to a more complicated object,
  18. * such as a query to a database or to a search engine. More
  19. * information on the types of URLs and their formats can be found at:
  20. * <blockquote><pre>
  21. * http://www.ncsa.uiuc.edu/demoweb/url-primer.html
  22. * </pre></blockquote>
  23. * <p>
  24. * In general, a URL can be broken into several parts. The previous
  25. * example of a URL indicates that the protocol to use is
  26. * <code>http</code> (HyperText Transport Protocol) and that the
  27. * information resides on a host machine named
  28. * <code>www.ncsa.uiuc.edu</code>. The information on that host
  29. * machine is named <code>demoweb/url-primer.html</code>. The exact
  30. * meaning of this name on the host machine is both protocol
  31. * dependent and host dependent. The information normally resides in
  32. * a file, but it could be generated on the fly. This component of
  33. * the URL is called the <i>file</i> component, even though the
  34. * information is not necessarily in a file.
  35. * <p>
  36. * A URL can optionally specify a "port", which is the
  37. * port number to which the TCP connection is made on the remote host
  38. * machine. If the port is not specified, the default port for
  39. * the protocol is used instead. For example, the default port for
  40. * <code>http</code> is <code>80</code>. An alternative port could be
  41. * specified as:
  42. * <blockquote><pre>
  43. * http://www.ncsa.uiuc.edu:8080/demoweb/url-primer.html
  44. * </pre></blockquote>
  45. * <p>
  46. * A URL may have appended to it an "anchor", also known
  47. * as a "ref" or a "reference". The anchor is
  48. * indicated by the sharp sign character "#" followed by
  49. * more characters. For example,
  50. * <blockquote><pre>
  51. * http://java.sun.com/index.html#chapter1
  52. * </pre></blockquote>
  53. * <p>
  54. * This anchor is not technically part of the URL. Rather, it
  55. * indicates that after the specified resource is retrieved, the
  56. * application is specifically interested in that part of the
  57. * document that has the tag <code>chapter1</code> attached to it. The
  58. * meaning of a tag is resource specific.
  59. * <p>
  60. * An application can also specify a "relative URL",
  61. * which contains only enough information to reach the resource
  62. * relative to another URL. Relative URLs are frequently used within
  63. * HTML pages. For example, if the contents of the URL:
  64. * <blockquote><pre>
  65. * http://java.sun.com/index.html
  66. * </pre></blockquote>
  67. * contained within it the relative URL:
  68. * <blockquote><pre>
  69. * FAQ.html
  70. * </pre></blockquote>
  71. * it would be a shorthand for:
  72. * <blockquote><pre>
  73. * http://java.sun.com/FAQ.html
  74. * </pre></blockquote>
  75. * <p>
  76. * The relative URL need not specify all the components of a URL. If
  77. * the protocol, host name, or port number is missing, the value is
  78. * inherited from the fully specified URL. The file component must be
  79. * specified. The optional anchor is not inherited.
  80. *
  81. * @author James Gosling
  82. * @version 1.61, 04/16/98
  83. * @since JDK1.0
  84. */
  85. public final class URL implements java.io.Serializable {
  86. static final long serialVersionUID = -7627629688361524110L;
  87. /**
  88. * The property which specifies the package prefix list to be scanned
  89. * for protocol handlers. The value of this property (if any) should
  90. * be a vertical bar delimited list of package names to search through
  91. * for a protocol handler to load. The policy of this class is that
  92. * all protocol handlers will be in a class called <protocolname>.Handler,
  93. * and each package in the list is examined in turn for a matching
  94. * handler. If none are found (or the property is not specified), the
  95. * default package prefix, sun.net.www.protocol, is used. The search
  96. * proceeds from the first package in the list to the last and stops
  97. * when a match is found.
  98. */
  99. private static final String protocolPathProp = "java.protocol.handler.pkgs";
  100. /**
  101. * The protocol to use (ftp, http, nntp, ... etc.) .
  102. */
  103. private String protocol;
  104. /**
  105. * The host name in which to connect to.
  106. */
  107. private String host;
  108. /**
  109. * The host's IP address, used in equals and hashCode.
  110. * Computed on demand. An uninitialized or unknown hostAddress is null.
  111. */
  112. private transient InetAddress hostAddress;
  113. /**
  114. * The protocol port to connect to.
  115. */
  116. private int port = -1;
  117. /**
  118. * The specified file name on that host.
  119. */
  120. private String file;
  121. /**
  122. * # reference.
  123. */
  124. private String ref;
  125. /**
  126. * The URLStreamHandler for this URL.
  127. */
  128. transient URLStreamHandler handler;
  129. /* Our hash code. */
  130. private int hashCode = -1;
  131. /**
  132. * Creates a <code>URL</code> object from the specified
  133. * <code>protocol</code>, <code>host</code>, <code>port</code>
  134. * number, and <code>file</code>. Specifying a <code>port</code>
  135. * number of <code>-1</code> indicates that the URL should use
  136. * the default port for the protocol.
  137. * <p>
  138. * If this is the first URL object being created with the specified
  139. * protocol, a <i>stream protocol handler</i> object, an instance of
  140. * class <code>URLStreamHandler</code>, is created for that protocol:
  141. * <ol>
  142. * <li>If the application has previously set up an instance of
  143. * <code>URLStreamHandlerFactory</code> as the stream handler factory,
  144. * then the <code>createURLStreamHandler</code> method of that instance
  145. * is called with the protocol string as an argument to create the
  146. * stream protocol handler.
  147. * <li>If no <code>URLStreamHandlerFactory</code> has yet been set up,
  148. * or if the factory's <code>createURLStreamHandler</code> method
  149. * returns <code>null</code>, then the constructor finds the
  150. * value of the system property:
  151. * <blockquote><pre>
  152. * java.protocol.handler.pkgs
  153. * </pre></blockquote>
  154. * If the value of that system property is not <code>null</code>,
  155. * it is interpreted as a list of packages separated by a vertical
  156. * slash character '<code>|</code>'. The constructor tries to load
  157. * the class named:
  158. * <blockquote><pre>
  159. * <<i>package</i>>.<<i>protocol</i>>.Handler
  160. * </pre></blockquote>
  161. * where <<i>package</i>> is replaced by the name of the package
  162. * and <<i>protocol</i>> is replaced by the name of the protocol.
  163. * If this class does not exist, or if the class exists but it is not
  164. * a subclass of <code>URLStreamHandler</code>, then the next package
  165. * in the list is tried.
  166. * <li>If the previous step fails to find a protocol handler, then the
  167. * constructor tries to load the class named:
  168. * <blockquote><pre>
  169. * sun.net.www.protocol.<<i>protocol</i>>.Handler
  170. * </pre></blockquote>
  171. * If this class does not exist, or if the class exists but it is not a
  172. * subclass of <code>URLStreamHandler</code>, then a
  173. * <code>MalformedURLException</code> is thrown.
  174. * </ol>
  175. *
  176. * @param protocol the name of the protocol.
  177. * @param host the name of the host.
  178. * @param port the port number.
  179. * @param file the host file.
  180. * @exception MalformedURLException if an unknown protocol is specified.
  181. * @see java.lang.System#getProperty(java.lang.String)
  182. * @see java.net.URL#setURLStreamHandlerFactory(java.net.URLStreamHandlerFactory)
  183. * @see java.net.URLStreamHandler
  184. * @see java.net.URLStreamHandlerFactory#createURLStreamHandler(java.lang.String)
  185. */
  186. public URL(String protocol, String host, int port, String file)
  187. throws MalformedURLException
  188. {
  189. this(protocol, host, port, file, null);
  190. }
  191. /**
  192. * Creates an absolute URL from the specified <code>protocol</code>
  193. * name, <code>host</code> name, and <code>file</code> name. The
  194. * default port for the specified protocol is used.
  195. * <p>
  196. * This method is equivalent to calling the four-argument
  197. * constructor with the arguments being <code>protocol</code>,
  198. * <code>host</code>, <code>-1</code>, and <code>file</code>.
  199. *
  200. * @param protocol the protocol to use.
  201. * @param host the host to connect to.
  202. * @param file the file on that host.
  203. * @exception MalformedURLException if an unknown protocol is specified.
  204. * @see java.net.URL#URL(java.lang.String, java.lang.String, int, java.lang.String)
  205. */
  206. public URL(String protocol, String host, String file) throws MalformedURLException {
  207. this(protocol, host, -1, file);
  208. }
  209. /**
  210. * Creates a <code>URL</code> object from the specified
  211. * <code>protocol</code>, <code>host</code>, <code>port</code>
  212. * number, <code>file</code>, and <code>handler</code>. Specifying
  213. * a <code>port</code> number of <code>-1</code> indicates that
  214. * the URL should use the default port for the protocol. Specifying
  215. * a <code>handler</code> of <code>null</code> indicates that the URL
  216. * should use a default stream handler for the protocol, as outlined
  217. * for:
  218. * <blockquote><pre>
  219. * java.net.URL#URL(java.lang.String, java.lang.String, int,
  220. * java.lang.String)
  221. * </pre></blockquote>
  222. *
  223. * <p>If the handler is not null and there is a security manager,
  224. * the security manager's <code>checkPermission</code>
  225. * method is called with a
  226. * <code>NetPermission("specifyStreamHandler")</code> permission.
  227. * This may result in a SecurityException.
  228. *
  229. * @param protocol the name of the protocol.
  230. * @param host the name of the host.
  231. * @param port the port number.
  232. * @param file the host file.
  233. * @param handler the stream handler.
  234. * @exception MalformedURLException if an unknown protocol is specified.
  235. * @exception SecurityException
  236. * if a security manager exists and its
  237. * <code>checkPermission</code> method doesn't allow
  238. * specifying a stream handler explicitly.
  239. * @see java.lang.System#getProperty(java.lang.String)
  240. * @see java.net.URL#setURLStreamHandlerFactory(java.net.URLStreamHandlerFactory)
  241. * @see java.net.URLStreamHandler
  242. * @see java.net.URLStreamHandlerFactory#createURLStreamHandler(java.lang.String)
  243. * @see SecurityManager#checkPermission
  244. * @see java.net.NetPermission
  245. */
  246. public URL(String protocol, String host, int port, String file,
  247. URLStreamHandler handler)
  248. throws MalformedURLException
  249. {
  250. if (handler != null) {
  251. SecurityManager sm = System.getSecurityManager();
  252. if (sm != null) {
  253. // check for permission to specify a handler
  254. checkSpecifyHandler(sm);
  255. }
  256. }
  257. this.protocol = protocol;
  258. this.host = host;
  259. this.port = port;
  260. int ind = file.indexOf('#');
  261. this.file = ind < 0 ? file: file.substring(0, ind);
  262. this.ref = ind < 0 ? null: file.substring(ind + 1);
  263. // Note: we don't do validation of the URL here. Too risky to change
  264. // right now, but worth considering for future reference. -br
  265. if (handler == null &&
  266. (handler = getURLStreamHandler(protocol)) == null) {
  267. throw new MalformedURLException("unknown protocol: " + protocol);
  268. }
  269. this.handler = handler;
  270. }
  271. /**
  272. * Creates a <code>URL</code> object from the <code>String</code>
  273. * representation.
  274. * <p>
  275. * This constructor is equivalent to a call to the two-argument
  276. * constructor with a <code>null</code> first argument.
  277. *
  278. * @param spec the <code>String</code> to parse as a URL.
  279. * @exception MalformedURLException If the string specifies an
  280. * unknown protocol.
  281. * @see java.net.URL#URL(java.net.URL, java.lang.String)
  282. */
  283. public URL(String spec) throws MalformedURLException {
  284. this(null, spec);
  285. }
  286. /**
  287. * Creates a URL by parsing the specification <code>spec</code>
  288. * within a specified context. If the <code>context</code> argument
  289. * is not <code>null</code> and the <code>spec</code> argument is a
  290. * partial URL specification, then any of the strings missing
  291. * components are inherited from the <code>context</code> argument.
  292. * <p>
  293. * The specification given by the <code>String</code> argument is
  294. * parsed to determine if it specifies a protocol. If the
  295. * <code>String</code> contains an ASCII colon '<code>:</code>'
  296. * character before the first occurrence of an ASCII slash character
  297. * '<code>/</code>', then the characters before the colon comprise
  298. * the protocol.
  299. * <ul>
  300. * <li>If the <code>spec</code> argument does not specify a protocol:
  301. * <ul>
  302. * <li>If the context argument is not <code>null</code>, then the
  303. * protocol is copied from the context argument.
  304. * <li>If the context argument is <code>null</code>, then a
  305. * <code>MalformedURLException</code> is thrown.
  306. * </ul>
  307. * <li>If the <code>spec</code> argument does specify a protocol:
  308. * <ul>
  309. * <li>If the context argument is <code>null</code>, or specifies a
  310. * different protocol than the specification argument, the context
  311. * argument is ignored.
  312. * <li>If the context argument is not <code>null</code> and specifies
  313. * the same protocol as the specification, the <code>host</code>,
  314. * <code>port</code> number, and <code>file</code> are copied from
  315. * the context argument into the newly created <code>URL</code>.
  316. * </ul>
  317. * </ul>
  318. * <p>
  319. * The constructor then searches for an appropriate stream protocol
  320. * handler of type <code>URLStreamHandler</code> as outlined for:
  321. * <blockquote><pre>
  322. * java.net.URL#URL(java.lang.String, java.lang.String, int,
  323. * java.lang.String)
  324. * </pre></blockquote>
  325. * The stream protocol handler's
  326. * <code>parseURL</code> method is called to parse the remaining
  327. * fields of the specification that override any defaults set by the
  328. * context argument.
  329. * @param context the context in which to parse the specification.
  330. * @param spec a <code>String</code> representation of a URL.
  331. * @exception MalformedURLException if no protocol is specified, or an
  332. * unknown protocol is found.
  333. * @see java.net.URL#URL(java.lang.String, java.lang.String, int, java.lang.String)
  334. * @see java.net.URLStreamHandler
  335. * @see java.net.URLStreamHandler#parseURL(java.net.URL, java.lang.String, int, int)
  336. */
  337. public URL(URL context, String spec) throws MalformedURLException {
  338. this(context, spec, null);
  339. }
  340. /**
  341. * Creates a URL by parsing the specification <code>spec</code>
  342. * within a specified context. If the <code>context</code> argument
  343. * is not <code>null</code> and the <code>spec</code> argument is a
  344. * partial URL specification, then any of the strings missing
  345. * components are inherited from the <code>context</code> argument.
  346. * <p>
  347. * The specification given by the <code>String</code> argument is
  348. * parsed to determine if it specifies a protocol. If the
  349. * <code>String</code> contains an ASCII colon '<code>:</code>'
  350. * character before the first occurrence of an ASCII slash character
  351. * '<code>/</code>', then the characters before the colon comprise
  352. * the protocol.
  353. * <ul>
  354. * <li>If the <code>spec</code> argument does not specify a protocol:
  355. * <ul>
  356. * <li>If the context argument is not <code>null</code>, then the
  357. * protocol is copied from the context argument.
  358. * <li>If the context argument is <code>null</code>, then a
  359. * <code>MalformedURLException</code> is thrown.
  360. * </ul>
  361. * <li>If the <code>spec</code> argument does specify a protocol:
  362. * <ul>
  363. * <li>If the context argument is <code>null</code>, or specifies a
  364. * different protocol than the specification argument, the context
  365. * argument is ignored.
  366. * <li>If the context argument is not <code>null</code> and specifies
  367. * the same protocol as the specification, the <code>host</code>,
  368. * <code>port</code> number, and <code>file</code> are copied from
  369. * the context argument into the newly created <code>URL</code>.
  370. * </ul>
  371. * </ul>
  372. * <p>
  373. * If the argument <code>handler</code> is specified then it will be
  374. * used as the stream handler for the URL and will override that of
  375. * the context. Specifying a stream handler requires the NetPermission
  376. * <code>"specifyStreamHandler"</code> or a <code>SecurityException</code>
  377. * will be thrown.
  378. * <p>Otherwise, if <code>handler</code> is null and the context is
  379. * valid then the protocol handler of the context will be inherited.
  380. * The stream protocol handler's
  381. * <code>parseURL</code> method is called to parse the remaining
  382. * fields of the specification that override any defaults set by the
  383. * context argument.
  384. *
  385. * @param context the context in which to parse the specification.
  386. * @param spec a <code>String</code> representation of a URL.
  387. * @param handler the stream handler for the URL.
  388. * @exception MalformedURLException if no protocol is specified, or an
  389. * unknown protocol is found.
  390. * @exception SecurityException
  391. * if a security manager exists and its
  392. * <code>checkPermission</code> method doesn't allow
  393. * specifying a stream handler.
  394. * @see java.net.URL#URL(java.lang.String, java.lang.String, int, java.lang.String)
  395. * @see java.net.URLStreamHandler
  396. * @see java.net.URLStreamHandler#parseURL(java.net.URL, java.lang.String, int, int)
  397. */
  398. public URL(URL context, String spec, URLStreamHandler handler)
  399. throws MalformedURLException
  400. {
  401. String original = spec;
  402. int i, limit, c;
  403. int start = 0;
  404. String newProtocol = null;
  405. boolean aRef=false;
  406. // Check for permission to specify a handler
  407. if (handler != null) {
  408. SecurityManager sm = System.getSecurityManager();
  409. if (sm != null) {
  410. checkSpecifyHandler(sm);
  411. }
  412. }
  413. try {
  414. limit = spec.length();
  415. while ((limit > 0) && (spec.charAt(limit - 1) <= ' ')) {
  416. limit--; //eliminate trailing whitespace
  417. }
  418. while ((start < limit) && (spec.charAt(start) <= ' ')) {
  419. start++; // eliminate leading whitespace
  420. }
  421. if (spec.regionMatches(true, start, "url:", 0, 4)) {
  422. start += 4;
  423. }
  424. if (start < spec.length() && spec.charAt(start) == '#') {
  425. /* we're assuming this is a ref relative to the context URL.
  426. * This means protocols cannot start w/ '#', but we must parse
  427. * ref URL's like: "hello:there" w/ a ':' in them.
  428. */
  429. aRef=true;
  430. }
  431. for (i = start ; !aRef && (i < limit) &&
  432. ((c = spec.charAt(i)) != '/') ; i++) {
  433. if (c == ':') {
  434. String s = spec.substring(start, i).toLowerCase();
  435. if (isValidProtocol(s)) {
  436. newProtocol = s;
  437. start = i + 1;
  438. }
  439. break;
  440. }
  441. }
  442. // Only use our context if the protocols match.
  443. if ((context != null) && ((newProtocol == null) ||
  444. newProtocol.equals(context.protocol))) {
  445. protocol = context.protocol;
  446. host = context.host;
  447. port = context.port;
  448. file = context.file;
  449. // inherit the protocol handler as well from the context
  450. // if not specified to the contructor
  451. if (handler == null) {
  452. handler = context.handler;
  453. }
  454. } else {
  455. protocol = newProtocol;
  456. }
  457. if (protocol == null) {
  458. throw new MalformedURLException("no protocol: "+original);
  459. }
  460. // Get the protocol handler if not specified or the protocol
  461. // of the context could not be used
  462. if (handler == null &&
  463. (handler = getURLStreamHandler(protocol)) == null) {
  464. throw new MalformedURLException("unknown protocol: "+protocol);
  465. }
  466. this.handler = handler;
  467. i = spec.indexOf('#', start);
  468. if (i >= 0) {
  469. ref = spec.substring(i + 1, limit);
  470. limit = i;
  471. }
  472. handler.parseURL(this, spec, start, limit);
  473. } catch(MalformedURLException e) {
  474. throw e;
  475. } catch(Exception e) {
  476. throw new MalformedURLException(original + ": " + e);
  477. }
  478. }
  479. /*
  480. * Returns true if specified string is a valid protocol name.
  481. */
  482. private boolean isValidProtocol(String protocol) {
  483. int len = protocol.length();
  484. if (len < 2)
  485. return false;
  486. for (int i = 0; i < len; i++) {
  487. char c = protocol.charAt(i);
  488. if (!Character.isLetterOrDigit(c) && c != '.' && c != '+' &&
  489. c != '-') {
  490. return false;
  491. }
  492. }
  493. return true;
  494. }
  495. /*
  496. * Checks for permission to specify a stream handler.
  497. */
  498. private void checkSpecifyHandler(SecurityManager sm) {
  499. if (specifyHandlerPerm == null) {
  500. specifyHandlerPerm = new NetPermission("specifyStreamHandler");
  501. }
  502. sm.checkPermission(specifyHandlerPerm);
  503. }
  504. private static NetPermission specifyHandlerPerm;
  505. /**
  506. * Sets the fields of the URL. This is not a public method so that
  507. * only URLStreamHandlers can modify URL fields. URLs are
  508. * otherwise constant.
  509. *
  510. * @param protocol the protocol to use
  511. * @param host the host name to connecto to
  512. @param port the protocol port to connect to
  513. * @param file the specified file name on that host
  514. * @param ref the reference
  515. */
  516. protected void set(String protocol, String host,
  517. int port, String file, String ref) {
  518. synchronized (this) {
  519. this.protocol = protocol;
  520. this.host = host;
  521. this.port = port;
  522. this.file = file;
  523. this.ref = ref;
  524. /* This is very important. We must recompute this after the
  525. * URL has been changed. */
  526. hashCode = -1;
  527. hostAddress = null;
  528. }
  529. }
  530. /**
  531. * Returns the port number of this <code>URL</code>.
  532. * Returns -1 if the port is not set.
  533. *
  534. * @return the port number
  535. */
  536. public int getPort() {
  537. return port;
  538. }
  539. /**
  540. * Returns the protocol name this <code>URL</code>.
  541. *
  542. * @return the protocol of this <code>URL</code>.
  543. */
  544. public String getProtocol() {
  545. return protocol;
  546. }
  547. /**
  548. * Returns the host name of this <code>URL</code>, if applicable.
  549. * For "<code>file</code>" protocol, this is an empty string.
  550. *
  551. * @return the host name of this <code>URL</code>.
  552. */
  553. public String getHost() {
  554. return host;
  555. }
  556. /**
  557. * Returns the file name of this <code>URL</code>.
  558. *
  559. * @return the file name of this <code>URL</code>.
  560. */
  561. public String getFile() {
  562. return file;
  563. }
  564. /**
  565. * Returns the anchor (also known as the "reference") of this
  566. * <code>URL</code>.
  567. *
  568. * @return the anchor (also known as the "reference") of this
  569. * <code>URL</code>.
  570. */
  571. public String getRef() {
  572. return ref;
  573. }
  574. /**
  575. * Compares two URLs. The result is <code>true</code> if and
  576. * only if the argument is not <code>null</code> and is a
  577. * <code>URL</code> object that represents the same
  578. * <code>URL</code> as this object. Two URL objects are equal if
  579. * they have the same protocol and reference the same host, the
  580. * same port number on the host, and the same file and anchor on
  581. * the host.
  582. *
  583. * @param obj the URL to compare against.
  584. * @return <code>true</code> if the objects are the same;
  585. * <code>false</code> otherwise.
  586. */
  587. public boolean equals(Object obj) {
  588. if (!(obj instanceof URL))
  589. return false;
  590. URL u2 = (URL)obj;
  591. return sameFile(u2) &&
  592. (ref == u2.ref || (ref != null && ref.equals(u2.ref)));
  593. }
  594. /**
  595. * Creates an integer suitable for hash table indexing.
  596. *
  597. * @return a hash code for this <code>URL</code>.
  598. */
  599. public synchronized int hashCode() {
  600. if (hashCode != -1)
  601. return hashCode;
  602. int h = 0;
  603. // Generate the protocol part.
  604. if (protocol != null)
  605. h += protocol.hashCode();
  606. // Generate the host part.
  607. InetAddress addr = getHostAddress();
  608. if (addr != null)
  609. h += addr.hashCode();
  610. else if (host != null)
  611. h += host.toLowerCase().hashCode();
  612. // Generate the file part.
  613. if (file != null)
  614. h += file.hashCode();
  615. // Generate the port part.
  616. h += port;
  617. // Generate the ref part.
  618. if (ref != null)
  619. h += ref.hashCode();
  620. hashCode = h;
  621. return h;
  622. }
  623. /**
  624. * Get the IP address of our host. An empty host field or a DNS failure
  625. * will result in a null return.
  626. */
  627. private synchronized InetAddress getHostAddress() {
  628. if (hostAddress != null)
  629. return hostAddress;
  630. if (host == null || host.equals("")) {
  631. return null;
  632. } else {
  633. try {
  634. hostAddress = InetAddress.getByName(host);
  635. } catch (UnknownHostException ex) {
  636. return null;
  637. } catch (SecurityException se) {
  638. return null;
  639. }
  640. }
  641. return hostAddress;
  642. }
  643. /**
  644. * Compares the host components of two URLs.
  645. * @param h1 the URL of the first host to compare
  646. * @param h2 the URL of the second host to compare
  647. * @return true if and only if they are equal, false otherwise.
  648. * @exception UnknownHostException If an unknown host is found.
  649. */
  650. private static boolean hostsEqual(URL u1, URL u2) {
  651. InetAddress a1 = u1.getHostAddress();
  652. InetAddress a2 = u2.getHostAddress();
  653. // if we have internet address for both, compare them
  654. if (a1 != null && a2 != null) {
  655. return a1.equals(a2);
  656. // else, if both have host names, compare them
  657. } else if (u1.host != null && u2.host != null)
  658. return u1.host.equalsIgnoreCase(u2.host);
  659. else
  660. return u1.host == null && u2.host == null;
  661. }
  662. /**
  663. * Compares two URLs, excluding the "ref" fields.
  664. * Returns <code>true</code> if this <code>URL</code> and the
  665. * <code>other</code> argument both refer to the same resource.
  666. * The two <code>URL</code>s might not both contain the same anchor.
  667. *
  668. * @param other the <code>URL</code> to compare against.
  669. * @return <code>true</code> if they reference the same remote object;
  670. * <code>false</code> otherwise.
  671. */
  672. public boolean sameFile(URL other) {
  673. // Compare the protocols.
  674. if (!((other.protocol == protocol) ||
  675. (protocol != null && protocol.equalsIgnoreCase(other.protocol))))
  676. return false;
  677. // Compare the hosts.
  678. if (!hostsEqual(this, other))
  679. return false;
  680. // Compare the files.
  681. if (!(file == other.file || (file != null && file.equals(other.file))))
  682. return false;
  683. // Compare the ports.
  684. if (port != other.port)
  685. return false;
  686. return true;
  687. }
  688. /**
  689. * Constructs a string representation of this <code>URL</code>. The
  690. * string is created by calling the <code>toExternalForm</code>
  691. * method of the stream protocol handler for this object.
  692. *
  693. * @return a string representation of this object.
  694. * @see java.net.URL#URL(java.lang.String, java.lang.String, int, java.lang.String)
  695. * @see java.net.URLStreamHandler#toExternalForm(java.net.URL)
  696. */
  697. public String toString() {
  698. return toExternalForm();
  699. }
  700. /**
  701. * Constructs a string representation of this <code>URL</code>. The
  702. * string is created by calling the <code>toExternalForm</code>
  703. * method of the stream protocol handler for this object.
  704. *
  705. * @return a string representation of this object.
  706. * @see java.net.URL#URL(java.lang.String, java.lang.String, int, java.lang.String)
  707. * @see java.net.URLStreamHandler#toExternalForm(java.net.URL)
  708. */
  709. public String toExternalForm() {
  710. return handler.toExternalForm(this);
  711. }
  712. /**
  713. * Returns a <code>URLConnection</code> object that represents a
  714. * connection to the remote object referred to by the <code>URL</code>.
  715. *
  716. * <p>A new connection is opened every time by calling the
  717. * <code>openConnection</code> method of the protocol handler for
  718. * this URL.
  719. *
  720. * <p>If for the URL's protocol (such as HTTP or JAR), there
  721. * exists a public, specialized URLConnection subclass belonging
  722. * to one of the following packages or one of their subpackages:
  723. * java.lang, java.io, java.util, java.net, the connection
  724. * returned will be of that subclass. For example, for HTTP an
  725. * HttpURLConnection will be returned, and for JAR a
  726. * JarURLConnection will be returned.
  727. *
  728. * @return a <code>URLConnection</code> to the URL.
  729. * @exception IOException if an I/O exception occurs.
  730. * @see java.net.URL#URL(java.lang.String, java.lang.String,
  731. * int, java.lang.String)
  732. * @see java.net.URLConnection
  733. * @see java.net.URLStreamHandler#openConnection(java.net.URL)
  734. */
  735. public URLConnection openConnection() throws java.io.IOException {
  736. return handler.openConnection(this);
  737. }
  738. /**
  739. * Opens a connection to this <code>URL</code> and returns an
  740. * <code>InputStream</code> for reading from that connection. This
  741. * method is a shorthand for:
  742. * <blockquote><pre>
  743. * openConnection().getInputStream()
  744. * </pre></blockquote>
  745. *
  746. * @return an input stream for reading from the URL connection.
  747. * @exception IOException if an I/O exception occurs.
  748. * @see java.net.URL#openConnection()
  749. * @see java.net.URLConnection#getInputStream()
  750. */
  751. public final InputStream openStream() throws java.io.IOException {
  752. return openConnection().getInputStream();
  753. }
  754. /**
  755. * Returns the contents of this URL. This method is a shorthand for:
  756. * <blockquote><pre>
  757. * openConnection().getContent()
  758. * </pre></blockquote>
  759. *
  760. * @return the contents of this URL.
  761. * @exception IOException if an I/O exception occurs.
  762. * @see java.net.URLConnection#getContent()
  763. */
  764. public final Object getContent() throws java.io.IOException {
  765. return openConnection().getContent();
  766. }
  767. /**
  768. * The URLStreamHandler factory.
  769. */
  770. static URLStreamHandlerFactory factory;
  771. /**
  772. * Sets an application's <code>URLStreamHandlerFactory</code>.
  773. * This method can be called at most once in a given Java Virtual
  774. * Machine.
  775. *
  776. *<p> The <code>URLStreamHandlerFactory</code> instance is used to
  777. *construct a stream protocol handler from a protocol name.
  778. *
  779. * <p> If there is a security manager, this method first calls
  780. * the security manager's <code>checkSetFactory</code> method
  781. * to ensure the operation is allowed.
  782. * This could result in a SecurityException.
  783. *
  784. * @param fac the desired factory.
  785. * @exception Error if the application has already set a factory.
  786. * @exception SecurityException if a security manager exists and its
  787. * <code>checkSetFactory</code> method doesn't allow the operation.
  788. * @see java.net.URL#URL(java.lang.String, java.lang.String,
  789. * int, java.lang.String)
  790. * @see java.net.URLStreamHandlerFactory
  791. * @see SecurityManager#checkSetFactory
  792. */
  793. public static synchronized void setURLStreamHandlerFactory(URLStreamHandlerFactory fac) {
  794. if (factory != null) {
  795. throw new Error("factory already defined");
  796. }
  797. SecurityManager security = System.getSecurityManager();
  798. if (security != null) {
  799. security.checkSetFactory();
  800. }
  801. handlers.clear();
  802. factory = fac;
  803. }
  804. /**
  805. * A table of protocol handlers.
  806. */
  807. static Hashtable handlers = new Hashtable();
  808. /**
  809. * Returns the Stream Handler.
  810. * @param protocol the protocol to use
  811. */
  812. static synchronized URLStreamHandler getURLStreamHandler(String protocol) {
  813. URLStreamHandler handler = (URLStreamHandler)handlers.get(protocol);
  814. if (handler == null) {
  815. // Use the factory (if any)
  816. if (factory != null) {
  817. handler = factory.createURLStreamHandler(protocol);
  818. }
  819. // Try java protocol handler
  820. if (handler == null) {
  821. String packagePrefixList = null;
  822. packagePrefixList
  823. = (String) java.security.AccessController.doPrivileged(
  824. new sun.security.action.GetPropertyAction(protocolPathProp,""));
  825. if (packagePrefixList != "") {
  826. packagePrefixList += "|";
  827. }
  828. // REMIND: decide whether to allow the "null" class prefix
  829. // or not.
  830. packagePrefixList += "sun.net.www.protocol";
  831. StringTokenizer packagePrefixIter =
  832. new StringTokenizer(packagePrefixList, "|");
  833. while (handler == null &&
  834. packagePrefixIter.hasMoreTokens()) {
  835. String packagePrefix =
  836. packagePrefixIter.nextToken().trim();
  837. try {
  838. String clsName = packagePrefix + "." + protocol +
  839. ".Handler";
  840. Class cls = null;
  841. try {
  842. cls = Class.forName(clsName);
  843. } catch (ClassNotFoundException e) {
  844. ClassLoader cl = ClassLoader.getSystemClassLoader();
  845. if (cl != null) {
  846. cls = cl.loadClass(clsName);
  847. }
  848. }
  849. if (cls != null) {
  850. handler =
  851. (URLStreamHandler)cls.newInstance();
  852. }
  853. } catch (Exception e) {
  854. // any number of exceptions can get thrown here
  855. }
  856. }
  857. }
  858. if (handler != null) {
  859. handlers.put(protocol, handler);
  860. }
  861. }
  862. return handler;
  863. }
  864. /**
  865. * WriteObject is called to save the state of the URL to an
  866. * ObjectOutputStream. The handler is not saved since it is
  867. * specific to this system.
  868. *
  869. * @serialData the default write object value. When read back in,
  870. * the reader must ensure that calling getURLStreamHandler with
  871. * the protocol variable returns a valid URLStreamHandler and
  872. * throw an IOException if it does not.
  873. */
  874. private synchronized void writeObject(java.io.ObjectOutputStream s)
  875. throws IOException
  876. {
  877. s.defaultWriteObject(); // write the fields
  878. }
  879. /**
  880. * readObject is called to restore the state of the URL from the
  881. * stream. It reads the components of the URL and finds the local
  882. * stream handler.
  883. */
  884. private synchronized void readObject(java.io.ObjectInputStream s)
  885. throws IOException, ClassNotFoundException
  886. {
  887. s.defaultReadObject(); // read the fields
  888. if ((handler = getURLStreamHandler(protocol)) == null) {
  889. throw new IOException("unknown protocol: " + protocol);
  890. }
  891. }
  892. }