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