1. /*
  2. * @(#)URLConnection.java 1.102 04/05/18
  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.Date;
  13. import java.util.StringTokenizer;
  14. import java.util.Collections;
  15. import java.util.Map;
  16. import java.util.List;
  17. import java.security.Permission;
  18. import java.security.AccessController;
  19. import sun.security.util.SecurityConstants;
  20. /**
  21. * The abstract class <code>URLConnection</code> is the superclass
  22. * of all classes that represent a communications link between the
  23. * application and a URL. Instances of this class can be used both to
  24. * read from and to write to the resource referenced by the URL. In
  25. * general, creating a connection to a URL is a multistep process:
  26. * <p>
  27. * <center><table border=2 summary="Describes the process of creating a connection to a URL: openConnection() and connect() over time.">
  28. * <tr><th><code>openConnection()</code></th>
  29. * <th><code>connect()</code></th></tr>
  30. * <tr><td>Manipulate parameters that affect the connection to the remote
  31. * resource.</td>
  32. * <td>Interact with the resource; query header fields and
  33. * contents.</td></tr>
  34. * </table>
  35. * ---------------------------->
  36. * <br>time</center>
  37. *
  38. * <ol>
  39. * <li>The connection object is created by invoking the
  40. * <code>openConnection</code> method on a URL.
  41. * <li>The setup parameters and general request properties are manipulated.
  42. * <li>The actual connection to the remote object is made, using the
  43. * <code>connect</code> method.
  44. * <li>The remote object becomes available. The header fields and the contents
  45. * of the remote object can be accessed.
  46. * </ol>
  47. * <p>
  48. * The setup parameters are modified using the following methods:
  49. * <ul>
  50. * <li><code>setAllowUserInteraction</code>
  51. * <li><code>setDoInput</code>
  52. * <li><code>setDoOutput</code>
  53. * <li><code>setIfModifiedSince</code>
  54. * <li><code>setUseCaches</code>
  55. * </ul>
  56. * <p>
  57. * and the general request properties are modified using the method:
  58. * <ul>
  59. * <li><code>setRequestProperty</code>
  60. * </ul>
  61. * <p>
  62. * Default values for the <code>AllowUserInteraction</code> and
  63. * <code>UseCaches</code> parameters can be set using the methods
  64. * <code>setDefaultAllowUserInteraction</code> and
  65. * <code>setDefaultUseCaches</code>.
  66. * <p>
  67. * Each of the above <code>set</code> methods has a corresponding
  68. * <code>get</code> method to retrieve the value of the parameter or
  69. * general request property. The specific parameters and general
  70. * request properties that are applicable are protocol specific.
  71. * <p>
  72. * The following methods are used to access the header fields and
  73. * the contents after the connection is made to the remote object:
  74. * <ul>
  75. * <li><code>getContent</code>
  76. * <li><code>getHeaderField</code>
  77. * <li><code>getInputStream</code>
  78. * <li><code>getOutputStream</code>
  79. * </ul>
  80. * <p>
  81. * Certain header fields are accessed frequently. The methods:
  82. * <ul>
  83. * <li><code>getContentEncoding</code>
  84. * <li><code>getContentLength</code>
  85. * <li><code>getContentType</code>
  86. * <li><code>getDate</code>
  87. * <li><code>getExpiration</code>
  88. * <li><code>getLastModifed</code>
  89. * </ul>
  90. * <p>
  91. * provide convenient access to these fields. The
  92. * <code>getContentType</code> method is used by the
  93. * <code>getContent</code> method to determine the type of the remote
  94. * object; subclasses may find it convenient to override the
  95. * <code>getContentType</code> method.
  96. * <p>
  97. * In the common case, all of the pre-connection parameters and
  98. * general request properties can be ignored: the pre-connection
  99. * parameters and request properties default to sensible values. For
  100. * most clients of this interface, there are only two interesting
  101. * methods: <code>getInputStream</code> and <code>getContent</code>,
  102. * which are mirrored in the <code>URL</code> class by convenience methods.
  103. * <p>
  104. * More information on the request properties and header fields of
  105. * an <code>http</code> connection can be found at:
  106. * <blockquote><pre>
  107. * <a href="http://www.ietf.org/rfc/rfc2068.txt">http://www.ietf.org/rfc/rfc2068.txt</a>
  108. * </pre></blockquote>
  109. *
  110. * Note about <code>fileNameMap</code>: In versions prior to JDK 1.1.6,
  111. * field <code>fileNameMap</code> of <code>URLConnection</code> was public.
  112. * In JDK 1.1.6 and later, <code>fileNameMap</code> is private; accessor
  113. * and mutator methods {@link #getFileNameMap() getFileNameMap} and
  114. * {@link #setFileNameMap(java.net.FileNameMap) setFileNameMap} are added
  115. * to access it. This change is also described on the <a href=
  116. * "http://java.sun.com/products/jdk/1.2/compatibility.html#incompatibilities1.2">
  117. * Compatibility</a> page.
  118. *
  119. * Invoking the <tt>close()</tt> methods on the <tt>InputStream</tt> or <tt>OutputStream</tt> of an
  120. * <tt>URLConnection</tt> after a request may free network resources associated with this
  121. * instance, unless particular protocol specifications specify different behaviours
  122. * for it.
  123. *
  124. * @author James Gosling
  125. * @version 1.102, 05/18/04
  126. * @see java.net.URL#openConnection()
  127. * @see java.net.URLConnection#connect()
  128. * @see java.net.URLConnection#getContent()
  129. * @see java.net.URLConnection#getContentEncoding()
  130. * @see java.net.URLConnection#getContentLength()
  131. * @see java.net.URLConnection#getContentType()
  132. * @see java.net.URLConnection#getDate()
  133. * @see java.net.URLConnection#getExpiration()
  134. * @see java.net.URLConnection#getHeaderField(int)
  135. * @see java.net.URLConnection#getHeaderField(java.lang.String)
  136. * @see java.net.URLConnection#getInputStream()
  137. * @see java.net.URLConnection#getLastModified()
  138. * @see java.net.URLConnection#getOutputStream()
  139. * @see java.net.URLConnection#setAllowUserInteraction(boolean)
  140. * @see java.net.URLConnection#setDefaultUseCaches(boolean)
  141. * @see java.net.URLConnection#setDoInput(boolean)
  142. * @see java.net.URLConnection#setDoOutput(boolean)
  143. * @see java.net.URLConnection#setIfModifiedSince(long)
  144. * @see java.net.URLConnection#setRequestProperty(java.lang.String, java.lang.String)
  145. * @see java.net.URLConnection#setUseCaches(boolean)
  146. * @since JDK1.0
  147. */
  148. public abstract class URLConnection {
  149. /**
  150. * The URL represents the remote object on the World Wide Web to
  151. * which this connection is opened.
  152. * <p>
  153. * The value of this field can be accessed by the
  154. * <code>getURL</code> method.
  155. * <p>
  156. * The default value of this variable is the value of the URL
  157. * argument in the <code>URLConnection</code> constructor.
  158. *
  159. * @see java.net.URLConnection#getURL()
  160. * @see java.net.URLConnection#url
  161. */
  162. protected URL url;
  163. /**
  164. * This variable is set by the <code>setDoInput</code> method. Its
  165. * value is returned by the <code>getDoInput</code> method.
  166. * <p>
  167. * A URL connection can be used for input and/or output. Setting the
  168. * <code>doInput</code> flag to <code>true</code> indicates that
  169. * the application intends to read data from the URL connection.
  170. * <p>
  171. * The default value of this field is <code>true</code>.
  172. *
  173. * @see java.net.URLConnection#getDoInput()
  174. * @see java.net.URLConnection#setDoInput(boolean)
  175. */
  176. protected boolean doInput = true;
  177. /**
  178. * This variable is set by the <code>setDoOutput</code> method. Its
  179. * value is returned by the <code>getDoOutput</code> method.
  180. * <p>
  181. * A URL connection can be used for input and/or output. Setting the
  182. * <code>doOutput</code> flag to <code>true</code> indicates
  183. * that the application intends to write data to the URL connection.
  184. * <p>
  185. * The default value of this field is <code>false</code>.
  186. *
  187. * @see java.net.URLConnection#getDoOutput()
  188. * @see java.net.URLConnection#setDoOutput(boolean)
  189. */
  190. protected boolean doOutput = false;
  191. private static boolean defaultAllowUserInteraction = false;
  192. /**
  193. * If <code>true</code>, this <code>URL</code> is being examined in
  194. * a context in which it makes sense to allow user interactions such
  195. * as popping up an authentication dialog. If <code>false</code>,
  196. * then no user interaction is allowed.
  197. * <p>
  198. * The value of this field can be set by the
  199. * <code>setAllowUserInteraction</code> method.
  200. * Its value is returned by the
  201. * <code>getAllowUserInteraction</code> method.
  202. * Its default value is the value of the argument in the last invocation
  203. * of the <code>setDefaultAllowUserInteraction</code> method.
  204. *
  205. * @see java.net.URLConnection#getAllowUserInteraction()
  206. * @see java.net.URLConnection#setAllowUserInteraction(boolean)
  207. * @see java.net.URLConnection#setDefaultAllowUserInteraction(boolean)
  208. */
  209. protected boolean allowUserInteraction = defaultAllowUserInteraction;
  210. private static boolean defaultUseCaches = true;
  211. /**
  212. * If <code>true</code>, the protocol is allowed to use caching
  213. * whenever it can. If <code>false</code>, the protocol must always
  214. * try to get a fresh copy of the object.
  215. * <p>
  216. * This field is set by the <code>setUseCaches</code> method. Its
  217. * value is returned by the <code>getUseCaches</code> method.
  218. * <p>
  219. * Its default value is the value given in the last invocation of the
  220. * <code>setDefaultUseCaches</code> method.
  221. *
  222. * @see java.net.URLConnection#setUseCaches(boolean)
  223. * @see java.net.URLConnection#getUseCaches()
  224. * @see java.net.URLConnection#setDefaultUseCaches(boolean)
  225. */
  226. protected boolean useCaches = defaultUseCaches;
  227. /**
  228. * Some protocols support skipping the fetching of the object unless
  229. * the object has been modified more recently than a certain time.
  230. * <p>
  231. * A nonzero value gives a time as the number of milliseconds since
  232. * January 1, 1970, GMT. The object is fetched only if it has been
  233. * modified more recently than that time.
  234. * <p>
  235. * This variable is set by the <code>setIfModifiedSince</code>
  236. * method. Its value is returned by the
  237. * <code>getIfModifiedSince</code> method.
  238. * <p>
  239. * The default value of this field is <code>0</code>, indicating
  240. * that the fetching must always occur.
  241. *
  242. * @see java.net.URLConnection#getIfModifiedSince()
  243. * @see java.net.URLConnection#setIfModifiedSince(long)
  244. */
  245. protected long ifModifiedSince = 0;
  246. /**
  247. * If <code>false</code>, this connection object has not created a
  248. * communications link to the specified URL. If <code>true</code>,
  249. * the communications link has been established.
  250. */
  251. protected boolean connected = false;
  252. /**
  253. * @since 1.5
  254. */
  255. private int connectTimeout;
  256. private int readTimeout;
  257. /**
  258. * @since JDK1.1
  259. */
  260. private static FileNameMap fileNameMap;
  261. /**
  262. * @since 1.2.2
  263. */
  264. private static boolean fileNameMapLoaded = false;
  265. /**
  266. * Loads filename map (a mimetable) from a data file. It will
  267. * first try to load the user-specific table, defined
  268. * by "content.types.user.table" property. If that fails,
  269. * it tries to load the default built-in table at
  270. * lib/content-types.properties under java home.
  271. *
  272. * @return the FileNameMap
  273. * @since 1.2
  274. * @see #setFileNameMap(java.net.FileNameMap)
  275. */
  276. public static synchronized FileNameMap getFileNameMap() {
  277. if ((fileNameMap == null) && !fileNameMapLoaded) {
  278. fileNameMap = sun.net.www.MimeTable.loadTable();
  279. fileNameMapLoaded = true;
  280. }
  281. return new FileNameMap() {
  282. private FileNameMap map = fileNameMap;
  283. public String getContentTypeFor(String fileName) {
  284. return map.getContentTypeFor(fileName);
  285. }
  286. };
  287. }
  288. /**
  289. * Sets the FileNameMap.
  290. * <p>
  291. * If there is a security manager, this method first calls
  292. * the security manager's <code>checkSetFactory</code> method
  293. * to ensure the operation is allowed.
  294. * This could result in a SecurityException.
  295. *
  296. * @param map the FileNameMap to be set
  297. * @exception SecurityException if a security manager exists and its
  298. * <code>checkSetFactory</code> method doesn't allow the operation.
  299. * @see SecurityManager#checkSetFactory
  300. * @see #getFileNameMap()
  301. * @since 1.2
  302. */
  303. public static void setFileNameMap(FileNameMap map) {
  304. SecurityManager sm = System.getSecurityManager();
  305. if (sm != null) sm.checkSetFactory();
  306. fileNameMap = map;
  307. }
  308. /**
  309. * Opens a communications link to the resource referenced by this
  310. * URL, if such a connection has not already been established.
  311. * <p>
  312. * If the <code>connect</code> method is called when the connection
  313. * has already been opened (indicated by the <code>connected</code>
  314. * field having the value <code>true</code>), the call is ignored.
  315. * <p>
  316. * URLConnection objects go through two phases: first they are
  317. * created, then they are connected. After being created, and
  318. * before being connected, various options can be specified
  319. * (e.g., doInput and UseCaches). After connecting, it is an
  320. * error to try to set them. Operations that depend on being
  321. * connected, like getContentLength, will implicitly perform the
  322. * connection, if necessary.
  323. *
  324. * @throws SocketTimeoutException if the timeout expires before
  325. * the connection can be established
  326. * @exception IOException if an I/O error occurs while opening the
  327. * connection.
  328. * @see java.net.URLConnection#connected
  329. * @see #getConnectTimeout()
  330. * @see #setConnectTimeout(int)
  331. */
  332. abstract public void connect() throws IOException;
  333. /**
  334. * Sets a specified timeout value, in milliseconds, to be used
  335. * when opening a communications link to the resource referenced
  336. * by this URLConnection. If the timeout expires before the
  337. * connection can be established, a
  338. * java.net.SocketTimeoutException is raised. A timeout of zero is
  339. * interpreted as an infinite timeout.
  340. * <p> Some non-standard implmentation of this method may ignore
  341. * the specified timeout. To see the connect timeout set, please
  342. * call getConnectTimeout().
  343. *
  344. * @param timeout an <code>int</code> that specifies the connect
  345. * timeout value in milliseconds
  346. * @throws IllegalArgumentException if the timeout parameter is negative
  347. *
  348. * @see #getConnectTimeout()
  349. * @see #connect()
  350. * @since 1.5
  351. */
  352. public void setConnectTimeout(int timeout) {
  353. if (timeout < 0) {
  354. throw new IllegalArgumentException("timeout can not be negative");
  355. }
  356. connectTimeout = timeout;
  357. }
  358. /**
  359. * Returns setting for connect timeout.
  360. * <p>
  361. * 0 return implies that the option is disabled
  362. * (i.e., timeout of infinity).
  363. *
  364. * @return an <code>int</code> that indicates the connect timeout
  365. * value in milliseconds
  366. * @see #setConnectTimeout(int)
  367. * @see #connect()
  368. * @since 1.5
  369. */
  370. public int getConnectTimeout() {
  371. return connectTimeout;
  372. }
  373. /**
  374. * Sets the read timeout to a specified timeout, in
  375. * milliseconds. A non-zero value specifies the timeout when
  376. * reading from Input stream when a connection is established to a
  377. * resource. If the timeout expires before there is data available
  378. * for read, a java.net.SocketTimeoutException is raised. A
  379. * timeout of zero is interpreted as an infinite timeout.
  380. *
  381. *<p> Some non-standard implementation of this method ignores the
  382. * specified timeout. To see the read timeout set, please call
  383. * getReadTimeout().
  384. *
  385. * @param timeout an <code>int</code> that specifies the timeout
  386. * value to be used in milliseconds
  387. * @throws IllegalArgumentException if the timeout parameter is negative
  388. *
  389. * @see #getReadTimeout()
  390. * @see InputStream#read()
  391. * @since 1.5
  392. */
  393. public void setReadTimeout(int timeout) {
  394. if (timeout < 0) {
  395. throw new IllegalArgumentException("timeout can not be negative");
  396. }
  397. readTimeout = timeout;
  398. }
  399. /**
  400. * Returns setting for read timeout. 0 return implies that the
  401. * option is disabled (i.e., timeout of infinity).
  402. *
  403. * @return an <code>int</code> that indicates the read timeout
  404. * value in milliseconds
  405. *
  406. * @see #setReadTimeout(int)
  407. * @see InputStream#read()
  408. * @since 1.5
  409. */
  410. public int getReadTimeout() {
  411. return readTimeout;
  412. }
  413. /**
  414. * Constructs a URL connection to the specified URL. A connection to
  415. * the object referenced by the URL is not created.
  416. *
  417. * @param url the specified URL.
  418. */
  419. protected URLConnection(URL url) {
  420. this.url = url;
  421. }
  422. /**
  423. * Returns the value of this <code>URLConnection</code>'s <code>URL</code>
  424. * field.
  425. *
  426. * @return the value of this <code>URLConnection</code>'s <code>URL</code>
  427. * field.
  428. * @see java.net.URLConnection#url
  429. */
  430. public URL getURL() {
  431. return url;
  432. }
  433. /**
  434. * Returns the value of the <code>content-length</code> header field.
  435. *
  436. * @return the content length of the resource that this connection's URL
  437. * references, or <code>-1</code> if the content length is
  438. * not known.
  439. */
  440. public int getContentLength() {
  441. return getHeaderFieldInt("content-length", -1);
  442. }
  443. /**
  444. * Returns the value of the <code>content-type</code> header field.
  445. *
  446. * @return the content type of the resource that the URL references,
  447. * or <code>null</code> if not known.
  448. * @see java.net.URLConnection#getHeaderField(java.lang.String)
  449. */
  450. public String getContentType() {
  451. return getHeaderField("content-type");
  452. }
  453. /**
  454. * Returns the value of the <code>content-encoding</code> header field.
  455. *
  456. * @return the content encoding of the resource that the URL references,
  457. * or <code>null</code> if not known.
  458. * @see java.net.URLConnection#getHeaderField(java.lang.String)
  459. */
  460. public String getContentEncoding() {
  461. return getHeaderField("content-encoding");
  462. }
  463. /**
  464. * Returns the value of the <code>expires</code> header field.
  465. *
  466. * @return the expiration date of the resource that this URL references,
  467. * or 0 if not known. The value is the number of milliseconds since
  468. * January 1, 1970 GMT.
  469. * @see java.net.URLConnection#getHeaderField(java.lang.String)
  470. */
  471. public long getExpiration() {
  472. return getHeaderFieldDate("expires", 0);
  473. }
  474. /**
  475. * Returns the value of the <code>date</code> header field.
  476. *
  477. * @return the sending date of the resource that the URL references,
  478. * or <code>0</code> if not known. The value returned is the
  479. * number of milliseconds since January 1, 1970 GMT.
  480. * @see java.net.URLConnection#getHeaderField(java.lang.String)
  481. */
  482. public long getDate() {
  483. return getHeaderFieldDate("date", 0);
  484. }
  485. /**
  486. * Returns the value of the <code>last-modified</code> header field.
  487. * The result is the number of milliseconds since January 1, 1970 GMT.
  488. *
  489. * @return the date the resource referenced by this
  490. * <code>URLConnection</code> was last modified, or 0 if not known.
  491. * @see java.net.URLConnection#getHeaderField(java.lang.String)
  492. */
  493. public long getLastModified() {
  494. return getHeaderFieldDate("last-modified", 0);
  495. }
  496. /**
  497. * Returns the value of the named header field.
  498. * <p>
  499. * If called on a connection that sets the same header multiple times
  500. * with possibly different values, only the last value is returned.
  501. *
  502. *
  503. * @param name the name of a header field.
  504. * @return the value of the named header field, or <code>null</code>
  505. * if there is no such field in the header.
  506. */
  507. public String getHeaderField(String name) {
  508. return null;
  509. }
  510. /**
  511. * Returns an unmodifiable Map of the header fields.
  512. * The Map keys are Strings that represent the
  513. * response-header field names. Each Map value is an
  514. * unmodifiable List of Strings that represents
  515. * the corresponding field values.
  516. *
  517. * @return a Map of header fields
  518. * @since 1.4
  519. */
  520. public Map<String,List<String>> getHeaderFields() {
  521. return Collections.EMPTY_MAP;
  522. }
  523. /**
  524. * Returns the value of the named field parsed as a number.
  525. * <p>
  526. * This form of <code>getHeaderField</code> exists because some
  527. * connection types (e.g., <code>http-ng</code>) have pre-parsed
  528. * headers. Classes for that connection type can override this method
  529. * and short-circuit the parsing.
  530. *
  531. * @param name the name of the header field.
  532. * @param Default the default value.
  533. * @return the value of the named field, parsed as an integer. The
  534. * <code>Default</code> value is returned if the field is
  535. * missing or malformed.
  536. */
  537. public int getHeaderFieldInt(String name, int Default) {
  538. String value = getHeaderField(name);
  539. try {
  540. return Integer.parseInt(value);
  541. } catch (Exception e) { }
  542. return Default;
  543. }
  544. /**
  545. * Returns the value of the named field parsed as date.
  546. * The result is the number of milliseconds since January 1, 1970 GMT
  547. * represented by the named field.
  548. * <p>
  549. * This form of <code>getHeaderField</code> exists because some
  550. * connection types (e.g., <code>http-ng</code>) have pre-parsed
  551. * headers. Classes for that connection type can override this method
  552. * and short-circuit the parsing.
  553. *
  554. * @param name the name of the header field.
  555. * @param Default a default value.
  556. * @return the value of the field, parsed as a date. The value of the
  557. * <code>Default</code> argument is returned if the field is
  558. * missing or malformed.
  559. */
  560. public long getHeaderFieldDate(String name, long Default) {
  561. String value = getHeaderField(name);
  562. try {
  563. return Date.parse(value);
  564. } catch (Exception e) { }
  565. return Default;
  566. }
  567. /**
  568. * Returns the key for the <code>n</code><sup>th</sup> header field.
  569. * It returns <code>null</code> if there are fewer than <code>n+1</code> fields.
  570. *
  571. * @param n an index, where n>=0
  572. * @return the key for the <code>n</code><sup>th</sup> header field,
  573. * or <code>null</code> if there are fewer than <code>n+1</code>
  574. * fields.
  575. */
  576. public String getHeaderFieldKey(int n) {
  577. return null;
  578. }
  579. /**
  580. * Returns the value for the <code>n</code><sup>th</sup> header field.
  581. * It returns <code>null</code> if there are fewer than
  582. * <code>n+1</code>fields.
  583. * <p>
  584. * This method can be used in conjunction with the
  585. * {@link #getHeaderFieldKey(int) getHeaderFieldKey} method to iterate through all
  586. * the headers in the message.
  587. *
  588. * @param n an index, where n>=0
  589. * @return the value of the <code>n</code><sup>th</sup> header field
  590. * or <code>null</code> if there are fewer than <code>n+1</code> fields
  591. * @see java.net.URLConnection#getHeaderFieldKey(int)
  592. */
  593. public String getHeaderField(int n) {
  594. return null;
  595. }
  596. /**
  597. * Retrieves the contents of this URL connection.
  598. * <p>
  599. * This method first determines the content type of the object by
  600. * calling the <code>getContentType</code> method. If this is
  601. * the first time that the application has seen that specific content
  602. * type, a content handler for that content type is created:
  603. * <ol>
  604. * <li>If the application has set up a content handler factory instance
  605. * using the <code>setContentHandlerFactory</code> method, the
  606. * <code>createContentHandler</code> method of that instance is called
  607. * with the content type as an argument; the result is a content
  608. * handler for that content type.
  609. * <li>If no content handler factory has yet been set up, or if the
  610. * factory's <code>createContentHandler</code> method returns
  611. * <code>null</code>, then the application loads the class named:
  612. * <blockquote><pre>
  613. * sun.net.www.content.<<i>contentType</i>>
  614. * </pre></blockquote>
  615. * where <<i>contentType</i>> is formed by taking the
  616. * content-type string, replacing all slash characters with a
  617. * <code>period</code> ('.'), and all other non-alphanumeric characters
  618. * with the underscore character '<code>_</code>'. The alphanumeric
  619. * characters are specifically the 26 uppercase ASCII letters
  620. * '<code>A</code>' through '<code>Z</code>', the 26 lowercase ASCII
  621. * letters '<code>a</code>' through '<code>z</code>', and the 10 ASCII
  622. * digits '<code>0</code>' through '<code>9</code>'. If the specified
  623. * class does not exist, or is not a subclass of
  624. * <code>ContentHandler</code>, then an
  625. * <code>UnknownServiceException</code> is thrown.
  626. * </ol>
  627. *
  628. * @return the object fetched. The <code>instanceof</code> operator
  629. * should be used to determine the specific kind of object
  630. * returned.
  631. * @exception IOException if an I/O error occurs while
  632. * getting the content.
  633. * @exception UnknownServiceException if the protocol does not support
  634. * the content type.
  635. * @see java.net.ContentHandlerFactory#createContentHandler(java.lang.String)
  636. * @see java.net.URLConnection#getContentType()
  637. * @see java.net.URLConnection#setContentHandlerFactory(java.net.ContentHandlerFactory)
  638. */
  639. public Object getContent() throws IOException {
  640. // Must call getInputStream before GetHeaderField gets called
  641. // so that FileNotFoundException has a chance to be thrown up
  642. // from here without being caught.
  643. getInputStream();
  644. return getContentHandler().getContent(this);
  645. }
  646. /**
  647. * Retrieves the contents of this URL connection.
  648. *
  649. * @param classes the <code>Class</code> array
  650. * indicating the requested types
  651. * @return the object fetched that is the first match of the type
  652. * specified in the classes array. null if none of
  653. * the requested types are supported.
  654. * The <code>instanceof</code> operator should be used to
  655. * determine the specific kind of object returned.
  656. * @exception IOException if an I/O error occurs while
  657. * getting the content.
  658. * @exception UnknownServiceException if the protocol does not support
  659. * the content type.
  660. * @see java.net.URLConnection#getContent()
  661. * @see java.net.ContentHandlerFactory#createContentHandler(java.lang.String)
  662. * @see java.net.URLConnection#getContent(java.lang.Class[])
  663. * @see java.net.URLConnection#setContentHandlerFactory(java.net.ContentHandlerFactory)
  664. */
  665. public Object getContent(Class[] classes) throws IOException {
  666. // Must call getInputStream before GetHeaderField gets called
  667. // so that FileNotFoundException has a chance to be thrown up
  668. // from here without being caught.
  669. getInputStream();
  670. return getContentHandler().getContent(this, classes);
  671. }
  672. /**
  673. * Returns a permission object representing the permission
  674. * necessary to make the connection represented by this
  675. * object. This method returns null if no permission is
  676. * required to make the connection. By default, this method
  677. * returns <code>java.security.AllPermission</code>. Subclasses
  678. * should override this method and return the permission
  679. * that best represents the permission required to make a
  680. * a connection to the URL. For example, a <code>URLConnection</code>
  681. * representing a <code>file:</code> URL would return a
  682. * <code>java.io.FilePermission</code> object.
  683. *
  684. * <p>The permission returned may dependent upon the state of the
  685. * connection. For example, the permission before connecting may be
  686. * different from that after connecting. For example, an HTTP
  687. * sever, say foo.com, may redirect the connection to a different
  688. * host, say bar.com. Before connecting the permission returned by
  689. * the connection will represent the permission needed to connect
  690. * to foo.com, while the permission returned after connecting will
  691. * be to bar.com.
  692. *
  693. * <p>Permissions are generally used for two purposes: to protect
  694. * caches of objects obtained through URLConnections, and to check
  695. * the right of a recipient to learn about a particular URL. In
  696. * the first case, the permission should be obtained
  697. * <em>after</em> the object has been obtained. For example, in an
  698. * HTTP connection, this will represent the permission to connect
  699. * to the host from which the data was ultimately fetched. In the
  700. * second case, the permission should be obtained and tested
  701. * <em>before</em> connecting.
  702. *
  703. * @return the permission object representing the permission
  704. * necessary to make the connection represented by this
  705. * URLConnection.
  706. *
  707. * @exception IOException if the computation of the permission
  708. * requires network or file I/O and an exception occurs while
  709. * computing it.
  710. */
  711. public Permission getPermission() throws IOException {
  712. return SecurityConstants.ALL_PERMISSION;
  713. }
  714. /**
  715. * Returns an input stream that reads from this open connection.
  716. *
  717. * A SocketTimeoutException can be thrown when reading from the
  718. * returned input stream if the read timeout expires before data
  719. * is available for read.
  720. *
  721. * @return an input stream that reads from this open connection.
  722. * @exception IOException if an I/O error occurs while
  723. * creating the input stream.
  724. * @exception UnknownServiceException if the protocol does not support
  725. * input.
  726. * @see #setReadTimeout(int)
  727. * @see #getReadTimeout()
  728. */
  729. public InputStream getInputStream() throws IOException {
  730. throw new UnknownServiceException("protocol doesn't support input");
  731. }
  732. /**
  733. * Returns an output stream that writes to this connection.
  734. *
  735. * @return an output stream that writes to this connection.
  736. * @exception IOException if an I/O error occurs while
  737. * creating the output stream.
  738. * @exception UnknownServiceException if the protocol does not support
  739. * output.
  740. */
  741. public OutputStream getOutputStream() throws IOException {
  742. throw new UnknownServiceException("protocol doesn't support output");
  743. }
  744. /**
  745. * Returns a <code>String</code> representation of this URL connection.
  746. *
  747. * @return a string representation of this <code>URLConnection</code>.
  748. */
  749. public String toString() {
  750. return this.getClass().getName() + ":" + url;
  751. }
  752. /**
  753. * Sets the value of the <code>doInput</code> field for this
  754. * <code>URLConnection</code> to the specified value.
  755. * <p>
  756. * A URL connection can be used for input and/or output. Set the DoInput
  757. * flag to true if you intend to use the URL connection for input,
  758. * false if not. The default is true.
  759. *
  760. * @param doinput the new value.
  761. * @throws IllegalStateException if already connected
  762. * @see java.net.URLConnection#doInput
  763. * @see #getDoInput()
  764. */
  765. public void setDoInput(boolean doinput) {
  766. if (connected)
  767. throw new IllegalStateException("Already connected");
  768. doInput = doinput;
  769. }
  770. /**
  771. * Returns the value of this <code>URLConnection</code>'s
  772. * <code>doInput</code> flag.
  773. *
  774. * @return the value of this <code>URLConnection</code>'s
  775. * <code>doInput</code> flag.
  776. * @see #setDoInput(boolean)
  777. */
  778. public boolean getDoInput() {
  779. return doInput;
  780. }
  781. /**
  782. * Sets the value of the <code>doOutput</code> field for this
  783. * <code>URLConnection</code> to the specified value.
  784. * <p>
  785. * A URL connection can be used for input and/or output. Set the DoOutput
  786. * flag to true if you intend to use the URL connection for output,
  787. * false if not. The default is false.
  788. *
  789. * @param dooutput the new value.
  790. * @throws IllegalStateException if already connected
  791. * @see #getDoOutput()
  792. */
  793. public void setDoOutput(boolean dooutput) {
  794. if (connected)
  795. throw new IllegalStateException("Already connected");
  796. doOutput = dooutput;
  797. }
  798. /**
  799. * Returns the value of this <code>URLConnection</code>'s
  800. * <code>doOutput</code> flag.
  801. *
  802. * @return the value of this <code>URLConnection</code>'s
  803. * <code>doOutput</code> flag.
  804. * @see #setDoOutput(boolean)
  805. */
  806. public boolean getDoOutput() {
  807. return doOutput;
  808. }
  809. /**
  810. * Set the value of the <code>allowUserInteraction</code> field of
  811. * this <code>URLConnection</code>.
  812. *
  813. * @param allowuserinteraction the new value.
  814. * @throws IllegalStateException if already connected
  815. * @see #getAllowUserInteraction()
  816. */
  817. public void setAllowUserInteraction(boolean allowuserinteraction) {
  818. if (connected)
  819. throw new IllegalStateException("Already connected");
  820. allowUserInteraction = allowuserinteraction;
  821. }
  822. /**
  823. * Returns the value of the <code>allowUserInteraction</code> field for
  824. * this object.
  825. *
  826. * @return the value of the <code>allowUserInteraction</code> field for
  827. * this object.
  828. * @see #setAllowUserInteraction(boolean)
  829. */
  830. public boolean getAllowUserInteraction() {
  831. return allowUserInteraction;
  832. }
  833. /**
  834. * Sets the default value of the
  835. * <code>allowUserInteraction</code> field for all future
  836. * <code>URLConnection</code> objects to the specified value.
  837. *
  838. * @param defaultallowuserinteraction the new value.
  839. * @see #getDefaultAllowUserInteraction()
  840. */
  841. public static void setDefaultAllowUserInteraction(boolean defaultallowuserinteraction) {
  842. defaultAllowUserInteraction = defaultallowuserinteraction;
  843. }
  844. /**
  845. * Returns the default value of the <code>allowUserInteraction</code>
  846. * field.
  847. * <p>
  848. * Ths default is "sticky", being a part of the static state of all
  849. * URLConnections. This flag applies to the next, and all following
  850. * URLConnections that are created.
  851. *
  852. * @return the default value of the <code>allowUserInteraction</code>
  853. * field.
  854. * @see #setDefaultAllowUserInteraction(boolean)
  855. */
  856. public static boolean getDefaultAllowUserInteraction() {
  857. return defaultAllowUserInteraction;
  858. }
  859. /**
  860. * Sets the value of the <code>useCaches</code> field of this
  861. * <code>URLConnection</code> to the specified value.
  862. * <p>
  863. * Some protocols do caching of documents. Occasionally, it is important
  864. * to be able to "tunnel through" and ignore the caches (e.g., the
  865. * "reload" button in a browser). If the UseCaches flag on a connection
  866. * is true, the connection is allowed to use whatever caches it can.
  867. * If false, caches are to be ignored.
  868. * The default value comes from DefaultUseCaches, which defaults to
  869. * true.
  870. *
  871. * @param usecaches a <code>boolean</code> indicating whether
  872. * or not to allow caching
  873. * @throws IllegalStateException if already connected
  874. * @see #getUseCaches()
  875. */
  876. public void setUseCaches(boolean usecaches) {
  877. if (connected)
  878. throw new IllegalStateException("Already connected");
  879. useCaches = usecaches;
  880. }
  881. /**
  882. * Returns the value of this <code>URLConnection</code>'s
  883. * <code>useCaches</code> field.
  884. *
  885. * @return the value of this <code>URLConnection</code>'s
  886. * <code>useCaches</code> field.
  887. * @see #setUseCaches(boolean)
  888. */
  889. public boolean getUseCaches() {
  890. return useCaches;
  891. }
  892. /**
  893. * Sets the value of the <code>ifModifiedSince</code> field of
  894. * this <code>URLConnection</code> to the specified value.
  895. *
  896. * @param ifmodifiedsince the new value.
  897. * @throws IllegalStateException if already connected
  898. * @see #getIfModifiedSince()
  899. */
  900. public void setIfModifiedSince(long ifmodifiedsince) {
  901. if (connected)
  902. throw new IllegalStateException("Already connected");
  903. ifModifiedSince = ifmodifiedsince;
  904. }
  905. /**
  906. * Returns the value of this object's <code>ifModifiedSince</code> field.
  907. *
  908. * @return the value of this object's <code>ifModifiedSince</code> field.
  909. * @see #setIfModifiedSince(long)
  910. */
  911. public long getIfModifiedSince() {
  912. return ifModifiedSince;
  913. }
  914. /**
  915. * Returns the default value of a <code>URLConnection</code>'s
  916. * <code>useCaches</code> flag.
  917. * <p>
  918. * Ths default is "sticky", being a part of the static state of all
  919. * URLConnections. This flag applies to the next, and all following
  920. * URLConnections that are created.
  921. *
  922. * @return the default value of a <code>URLConnection</code>'s
  923. * <code>useCaches</code> flag.
  924. * @see #setDefaultUseCaches(boolean)
  925. */
  926. public boolean getDefaultUseCaches() {
  927. return defaultUseCaches;
  928. }
  929. /**
  930. * Sets the default value of the <code>useCaches</code> field to the
  931. * specified value.
  932. *
  933. * @param defaultusecaches the new value.
  934. * @see #getDefaultUseCaches()
  935. */
  936. public void setDefaultUseCaches(boolean defaultusecaches) {
  937. defaultUseCaches = defaultusecaches;
  938. }
  939. /**
  940. * Sets the general request property. If a property with the key already
  941. * exists, overwrite its value with the new value.
  942. *
  943. * <p> NOTE: HTTP requires all request properties which can
  944. * legally have multiple instances with the same key
  945. * to use a comma-seperated list syntax which enables multiple
  946. * properties to be appended into a single property.
  947. *
  948. * @param key the keyword by which the request is known
  949. * (e.g., "<code>accept</code>").
  950. * @param value the value associated with it.
  951. * @throws IllegalStateException if already connected
  952. * @throws NullPointerException if key is <CODE>null</CODE>
  953. * @see #getRequestProperty(java.lang.String)
  954. */
  955. public void setRequestProperty(String key, String value) {
  956. if (connected)
  957. throw new IllegalStateException("Already connected");
  958. if (key == null)
  959. throw new NullPointerException ("key is null");
  960. }
  961. /**
  962. * Adds a general request property specified by a
  963. * key-value pair. This method will not overwrite
  964. * existing values associated with the same key.
  965. *
  966. * @param key the keyword by which the request is known
  967. * (e.g., "<code>accept</code>").
  968. * @param value the value associated with it.
  969. * @throws IllegalStateException if already connected
  970. * @throws NullPointerException if key is null
  971. * @see #getRequestProperties()
  972. * @since 1.4
  973. */
  974. public void addRequestProperty(String key, String value) {
  975. if (connected)
  976. throw new IllegalStateException("Already connected");
  977. if (key == null)
  978. throw new NullPointerException ("key is null");
  979. }
  980. /**
  981. * Returns the value of the named general request property for this
  982. * connection.
  983. *
  984. * @param key the keyword by which the request is known (e.g., "accept").
  985. * @return the value of the named general request property for this
  986. * connection. If key is null, then null is returned.
  987. * @throws IllegalStateException if already connected
  988. * @see #setRequestProperty(java.lang.String, java.lang.String)
  989. */
  990. public String getRequestProperty(String key) {
  991. if (connected)
  992. throw new IllegalStateException("Already connected");
  993. return null;
  994. }
  995. /**
  996. * Returns an unmodifiable Map of general request
  997. * properties for this connection. The Map keys
  998. * are Strings that represent the request-header
  999. * field names. Each Map value is a unmodifiable List
  1000. * of Strings that represents the corresponding
  1001. * field values.
  1002. *
  1003. * @return a Map of the general request properties for this connection.
  1004. * @throws IllegalStateException if already connected
  1005. * @since 1.4
  1006. */
  1007. public Map<String,List<String>> getRequestProperties() {
  1008. if (connected)
  1009. throw new IllegalStateException("Already connected");
  1010. return Collections.EMPTY_MAP;
  1011. }
  1012. /**
  1013. * Sets the default value of a general request property. When a
  1014. * <code>URLConnection</code> is created, it is initialized with
  1015. * these properties.
  1016. *
  1017. * @param key the keyword by which the request is known
  1018. * (e.g., "<code>accept</code>").
  1019. * @param value the value associated with the key.
  1020. *
  1021. * @see java.net.URLConnection#setRequestProperty(java.lang.String,java.lang.String)
  1022. *
  1023. * @deprecated The instance specific setRequestProperty method
  1024. * should be used after an appropriate instance of URLConnection
  1025. * is obtained. Invoking this method will have no effect.
  1026. *
  1027. * @see #getDefaultRequestProperty(java.lang.String)
  1028. */
  1029. @Deprecated
  1030. public static void setDefaultRequestProperty(String key, String value) {
  1031. }
  1032. /**
  1033. * Returns the value of the default request property. Default request
  1034. * properties are set for every connection.
  1035. *
  1036. * @param key the keyword by which the request is known (e.g., "accept").
  1037. * @return the value of the default request property
  1038. * for the specified key.
  1039. *
  1040. * @see java.net.URLConnection#getRequestProperty(java.lang.String)
  1041. *
  1042. * @deprecated The instance specific getRequestProperty method
  1043. * should be used after an appropriate instance of URLConnection
  1044. * is obtained.
  1045. *
  1046. * @see #setDefaultRequestProperty(java.lang.String, java.lang.String)
  1047. */
  1048. @Deprecated
  1049. public static String getDefaultRequestProperty(String key) {
  1050. return null;
  1051. }
  1052. /**
  1053. * The ContentHandler factory.
  1054. */
  1055. static ContentHandlerFactory factory;
  1056. /**
  1057. * Sets the <code>ContentHandlerFactory</code> of an
  1058. * application. It can be called at most once by an application.
  1059. * <p>
  1060. * The <code>ContentHandlerFactory</code> instance is used to
  1061. * construct a content handler from a content type
  1062. * <p>
  1063. * If there is a security manager, this method first calls
  1064. * the security manager's <code>checkSetFactory</code> method
  1065. * to ensure the operation is allowed.
  1066. * This could result in a SecurityException.
  1067. *
  1068. * @param fac the desired factory.
  1069. * @exception Error if the factory has already been defined.
  1070. * @exception SecurityException if a security manager exists and its
  1071. * <code>checkSetFactory</code> method doesn't allow the operation.
  1072. * @see java.net.ContentHandlerFactory
  1073. * @see java.net.URLConnection#getContent()
  1074. * @see SecurityManager#checkSetFactory
  1075. */
  1076. public static synchronized void setContentHandlerFactory(ContentHandlerFactory fac) {
  1077. if (factory != null) {
  1078. throw new Error("factory already defined");
  1079. }
  1080. SecurityManager security = System.getSecurityManager();
  1081. if (security != null) {
  1082. security.checkSetFactory();
  1083. }
  1084. factory = fac;
  1085. }
  1086. private static Hashtable handlers = new Hashtable();
  1087. private static final ContentHandler UnknownContentHandlerP = new UnknownContentHandler();
  1088. /**
  1089. * Gets the Content Handler appropriate for this connection.
  1090. * @param connection the connection to use.
  1091. */
  1092. synchronized ContentHandler getContentHandler()
  1093. throws UnknownServiceException
  1094. {
  1095. String contentType = stripOffParameters(getContentType());
  1096. ContentHandler handler = null;
  1097. if (contentType == null)
  1098. throw new UnknownServiceException("no content-type");
  1099. try {
  1100. handler = (ContentHandler) handlers.get(contentType);
  1101. if (handler != null)
  1102. return handler;
  1103. } catch(Exception e) {
  1104. }
  1105. if (factory != null)
  1106. handler = factory.createContentHandler(contentType);
  1107. if (handler == null) {
  1108. try {
  1109. handler = lookupContentHandlerClassFor(contentType);
  1110. } catch(Exception e) {
  1111. e.printStackTrace();
  1112. handler = UnknownContentHandlerP;
  1113. }
  1114. handlers.put(contentType, handler);
  1115. }
  1116. return handler;
  1117. }
  1118. /*
  1119. * Media types are in the format: type/subtype*(; parameter).
  1120. * For looking up the content handler, we should ignore those
  1121. * parameters.
  1122. */
  1123. private String stripOffParameters(String contentType)
  1124. {
  1125. if (contentType == null)
  1126. return null;
  1127. int index = contentType.indexOf(';');
  1128. if (index > 0)
  1129. return contentType.substring(0, index);
  1130. else
  1131. return contentType;
  1132. }
  1133. private static final String contentClassPrefix = "sun.net.www.content";
  1134. private static final String contentPathProp = "java.content.handler.pkgs";
  1135. /**
  1136. * Looks for a content handler in a user-defineable set of places.
  1137. * By default it looks in sun.net.www.content, but users can define a
  1138. * vertical-bar delimited set of class prefixes to search through in
  1139. * addition by defining the java.content.handler.pkgs property.
  1140. * The class name must be of the form:
  1141. * <pre>
  1142. * {package-prefix}.{major}.{minor}
  1143. * e.g.
  1144. * YoyoDyne.experimental.text.plain
  1145. * </pre>
  1146. */
  1147. private ContentHandler lookupContentHandlerClassFor(String contentType)
  1148. throws InstantiationException, IllegalAccessException, ClassNotFoundException {
  1149. String contentHandlerClassName = typeToPackageName(contentType);
  1150. String contentHandlerPkgPrefixes =getContentHandlerPkgPrefixes();
  1151. StringTokenizer packagePrefixIter =
  1152. new StringTokenizer(contentHandlerPkgPrefixes, "|");
  1153. while (packagePrefixIter.hasMoreTokens()) {
  1154. String packagePrefix = packagePrefixIter.nextToken().trim();
  1155. try {
  1156. String clsName = packagePrefix + "." + contentHandlerClassName;
  1157. Class cls = null;
  1158. try {
  1159. cls = Class.forName(clsName);
  1160. } catch (ClassNotFoundException e) {
  1161. ClassLoader cl = ClassLoader.getSystemClassLoader();
  1162. if (cl != null) {
  1163. cls = cl.loadClass(clsName);
  1164. }
  1165. }
  1166. if (cls != null) {
  1167. ContentHandler handler =
  1168. (ContentHandler)cls.newInstance();
  1169. return handler;
  1170. }
  1171. } catch(Exception e) {
  1172. }
  1173. }
  1174. return UnknownContentHandlerP;
  1175. }
  1176. /**
  1177. * Utility function to map a MIME content type into an equivalent
  1178. * pair of class name components. For example: "text/html" would
  1179. * be returned as "text.html"
  1180. */
  1181. private String typeToPackageName(String contentType) {
  1182. // make sure we canonicalize the class name: all lower case
  1183. contentType = contentType.toLowerCase();
  1184. int len = contentType.length();
  1185. char nm[] = new char[len];
  1186. contentType.getChars(0, len, nm, 0);
  1187. for (int i = 0; i < len; i++) {
  1188. char c = nm[i];
  1189. if (c == '/') {
  1190. nm[i] = '.';
  1191. } else if (!('A' <= c && c <= 'Z' ||
  1192. 'a' <= c && c <= 'z' ||
  1193. '0' <= c && c <= '9')) {
  1194. nm[i] = '_';
  1195. }
  1196. }
  1197. return new String(nm);
  1198. }
  1199. /**
  1200. * Returns a vertical bar separated list of package prefixes for potential
  1201. * content handlers. Tries to get the java.content.handler.pkgs property
  1202. * to use as a set of package prefixes to search. Whether or not
  1203. * that property has been defined, the sun.net.www.content is always
  1204. * the last one on the returned package list.
  1205. */
  1206. private String getContentHandlerPkgPrefixes() {
  1207. String packagePrefixList = (String) AccessController.doPrivileged(
  1208. new sun.security.action.GetPropertyAction(contentPathProp, ""));
  1209. if (packagePrefixList != "") {
  1210. packagePrefixList += "|";
  1211. }
  1212. return packagePrefixList + contentClassPrefix;
  1213. }
  1214. /**
  1215. * Tries to determine the content type of an object, based
  1216. * on the specified "file" component of a URL.
  1217. * This is a convenience method that can be used by
  1218. * subclasses that override the <code>getContentType</code> method.
  1219. *
  1220. * @param fname a filename.
  1221. * @return a guess as to what the content type of the object is,
  1222. * based upon its file name.
  1223. * @see java.net.URLConnection#getContentType()
  1224. */
  1225. public static String guessContentTypeFromName(String fname) {
  1226. return getFileNameMap().getContentTypeFor(fname);
  1227. }
  1228. /**
  1229. * Tries to determine the type of an input stream based on the
  1230. * characters at the beginning of the input stream. This method can
  1231. * be used by subclasses that override the
  1232. * <code>getContentType</code> method.
  1233. * <p>
  1234. * Ideally, this routine would not be needed. But many
  1235. * <code>http</code> servers return the incorrect content type; in
  1236. * addition, there are many nonstandard extensions. Direct inspection
  1237. * of the bytes to determine the content type is often more accurate
  1238. * than believing the content type claimed by the <code>http</code> server.
  1239. *
  1240. * @param is an input stream that supports marks.
  1241. * @return a guess at the content type, or <code>null</code> if none
  1242. * can be determined.
  1243. * @exception IOException if an I/O error occurs while reading the
  1244. * input stream.
  1245. * @see java.io.InputStream#mark(int)
  1246. * @see java.io.InputStream#markSupported()
  1247. * @see java.net.URLConnection#getContentType()
  1248. */
  1249. static public String guessContentTypeFromStream(InputStream is)
  1250. throws IOException {
  1251. // If we can't read ahead safely, just give up on guessing
  1252. if (!is.markSupported())
  1253. return null;
  1254. is.mark(12);
  1255. int c1 = is.read();
  1256. int c2 = is.read();
  1257. int c3 = is.read();
  1258. int c4 = is.read();
  1259. int c5 = is.read();
  1260. int c6 = is.read();
  1261. int c7 = is.read();
  1262. int c8 = is.read();
  1263. int c9 = is.read();
  1264. int c10 = is.read();
  1265. int c11 = is.read();
  1266. is.reset();
  1267. if (c1 == 0xCA && c2 == 0xFE && c3 == 0xBA && c4 == 0xBE) {
  1268. return "application/java-vm";
  1269. }
  1270. if (c1 == 0xAC && c2 == 0xED) {
  1271. // next two bytes are version number, currently 0x00 0x05
  1272. return "application/x-java-serialized-object";
  1273. }
  1274. if (c1 == '<') {
  1275. if (c2 == '!'
  1276. || ((c2 == 'h' && (c3 == 't' && c4 == 'm' && c5 == 'l' ||
  1277. c3 == 'e' && c4 == 'a' && c5 == 'd') ||
  1278. (c2 == 'b' && c3 == 'o' && c4 == 'd' && c5 == 'y'))) ||
  1279. ((c2 == 'H' && (c3 == 'T' && c4 == 'M' && c5 == 'L' ||
  1280. c3 == 'E' && c4 == 'A' && c5 == 'D') ||
  1281. (c2 == 'B' && c3 == 'O' && c4 == 'D' && c5 == 'Y')))) {
  1282. return "text/html";
  1283. }
  1284. if (c2 == '?' && c3 == 'x' && c4 == 'm' && c5 == 'l' && c6 == ' ') {
  1285. return "application/xml";
  1286. }
  1287. }
  1288. // big and little endian UTF-16 encodings, with byte order mark
  1289. if (c1 == 0xfe && c2 == 0xff) {
  1290. if (c3 == 0 && c4 == '<' && c5 == 0 && c6 == '?' &&
  1291. c7 == 0 && c8 == 'x') {
  1292. return "application/xml";
  1293. }
  1294. }
  1295. if (c1 == 0xff && c2 == 0xfe) {
  1296. if (c3 == '<' && c4 == 0 && c5 == '?' && c6 == 0 &&
  1297. c7 == 'x' && c8 == 0) {
  1298. return "application/xml";
  1299. }
  1300. }
  1301. if (c1 == 'G' && c2 == 'I' && c3 == 'F' && c4 == '8') {
  1302. return "image/gif";
  1303. }
  1304. if (c1 == '#' && c2 == 'd' && c3 == 'e' && c4 == 'f') {
  1305. return "image/x-bitmap";
  1306. }
  1307. if (c1 == '!' && c2 == ' ' && c3 == 'X' && c4 == 'P' &&
  1308. c5 == 'M' && c6 == '2') {
  1309. return "image/x-pixmap";
  1310. }
  1311. if (c1 == 137 && c2 == 80 && c3 == 78 &&
  1312. c4 == 71 && c5 == 13 && c6 == 10 &&
  1313. c7 == 26 && c8 == 10) {
  1314. return "image/png";
  1315. }
  1316. if (c1 == 0xFF && c2 == 0xD8 && c3 == 0xFF) {
  1317. if (c4 == 0xE0) {
  1318. return "image/jpeg";
  1319. }
  1320. /**
  1321. * File format used by digital cameras to store images.
  1322. * Exif Format can be read by any application supporting
  1323. * JPEG. Exif Spec can be found at:
  1324. * http://www.pima.net/standards/it10/PIMA15740/Exif_2-1.PDF
  1325. */
  1326. if ((c4 == 0xE1) &&
  1327. (c7 == 'E' && c8 == 'x' && c9 == 'i' && c10 =='f' &&
  1328. c11 == 0)) {
  1329. return "image/jpeg";
  1330. }
  1331. if (c4 == 0xEE) {
  1332. return "image/jpg";
  1333. }
  1334. }
  1335. if (c1 == 0xD0 && c2 == 0xCF && c3 == 0x11 && c4 == 0xE0 &&
  1336. c5 == 0xA1 && c6 == 0xB1 && c7 == 0x1A && c8 == 0xE1) {
  1337. /* Above is signature of Microsoft Structured Storage.
  1338. * Below this, could have tests for various SS entities.
  1339. * For now, just test for FlashPix.
  1340. */
  1341. if (checkfpx(is)) {
  1342. return "image/vnd.fpx";
  1343. }
  1344. }
  1345. if (c1 == 0x2E && c2 == 0x73 && c3 == 0x6E && c4 == 0x64) {
  1346. return "audio/basic"; // .au format, big endian
  1347. }
  1348. if (c1 == 0x64 && c2 == 0x6E && c3 == 0x73 && c4 == 0x2E) {
  1349. return "audio/basic"; // .au format, little endian
  1350. }
  1351. if (c1 == 'R' && c2 == 'I' && c3 == 'F' && c4 == 'F') {
  1352. /* I don't know if this is official but evidence
  1353. * suggests that .wav files start with "RIFF" - brown
  1354. */
  1355. return "audio/x-wav";
  1356. }
  1357. return null;
  1358. }
  1359. /**
  1360. * Check for FlashPix image data in InputStream is. Return true if
  1361. * the stream has FlashPix data, false otherwise. Before calling this
  1362. * method, the stream should have already been checked to be sure it
  1363. * contains Microsoft Structured Storage data.
  1364. */
  1365. static private boolean checkfpx(InputStream is) throws IOException {
  1366. /* Test for FlashPix image data in Microsoft Structured Storage format.
  1367. * In general, should do this with calls to an SS implementation.
  1368. * Lacking that, need to dig via offsets to get to the FlashPix
  1369. * ClassID. Details:
  1370. *
  1371. * Offset to Fpx ClsID from beginning of stream should be:
  1372. *
  1373. * FpxClsidOffset = rootEntryOffset + clsidOffset
  1374. *
  1375. * where: clsidOffset = 0x50.
  1376. * rootEntryOffset = headerSize + sectorSize*sectDirStart
  1377. * + 128*rootEntryDirectory
  1378. *
  1379. * where: headerSize = 0x200 (always)
  1380. * sectorSize = 2 raised to power of uSectorShift,
  1381. * which is found in the header at
  1382. * offset 0x1E.
  1383. * sectDirStart = found in the header at offset 0x30.
  1384. * rootEntryDirectory = in general, should search for
  1385. * directory labelled as root.
  1386. * We will assume value of 0 (i.e.,
  1387. * rootEntry is in first directory)
  1388. */
  1389. // Mark the stream so we can reset it. 0x100 is enough for the first
  1390. // few reads, but the mark will have to be reset and set again once
  1391. // the offset to the root directory entry is computed. That offset
  1392. // can be very large and isn't know until the stream has been read from
  1393. is.mark(0x100);
  1394. // Get the byte ordering located at 0x1E. 0xFE is Intel,
  1395. // 0xFF is other
  1396. long toSkip = (long)0x1C;
  1397. long posn;
  1398. if ((posn = skipForward(is, toSkip)) < toSkip) {
  1399. is.reset();
  1400. return false;
  1401. }
  1402. int c[] = new int[16];
  1403. if (readBytes(c, 2, is) < 0) {
  1404. is.reset();
  1405. return false;
  1406. }
  1407. int byteOrder = c[0];
  1408. posn+=2;
  1409. int uSectorShift;
  1410. if (readBytes(c, 2, is) < 0) {
  1411. is.reset();
  1412. return false;
  1413. }
  1414. if(byteOrder == 0xFE) {
  1415. uSectorShift = c[0];
  1416. uSectorShift += c[1] << 8;
  1417. }
  1418. else {
  1419. uSectorShift = c[0] << 8;
  1420. uSectorShift += c[1];
  1421. }
  1422. posn += 2;
  1423. toSkip = (long)0x30 - posn;
  1424. long skipped = 0;
  1425. if ((skipped = skipForward(is, toSkip)) < toSkip) {
  1426. is.reset();
  1427. return false;
  1428. }
  1429. posn += skipped;
  1430. if (readBytes(c, 4, is) < 0) {
  1431. is.reset();
  1432. return false;
  1433. }
  1434. int sectDirStart;
  1435. if(byteOrder == 0xFE) {
  1436. sectDirStart = c[0];
  1437. sectDirStart += c[1] << 8;
  1438. sectDirStart += c[2] << 16;
  1439. sectDirStart += c[3] << 24;
  1440. } else {
  1441. sectDirStart = c[0] << 24;
  1442. sectDirStart += c[1] << 16;
  1443. sectDirStart += c[2] << 8;
  1444. sectDirStart += c[3];
  1445. }
  1446. posn += 4;
  1447. is.reset(); // Reset back to the beginning
  1448. toSkip = (long)0x200 +
  1449. (long)((int)1<<uSectorShift)*sectDirStart + (long)0x50;
  1450. // Sanity check!
  1451. if (toSkip < 0) {
  1452. return false;
  1453. }
  1454. /*
  1455. * How far can we skip? Is there any performance problem here?
  1456. * This skip can be fairly long, at least 0x4c650 in at least
  1457. * one case. Have to assume that the skip will fit in an int.
  1458. * Leave room to read whole root dir
  1459. */
  1460. is.mark((int)toSkip+0x30);
  1461. if ((skipForward(is, toSkip)) < toSkip) {
  1462. is.reset();
  1463. return false;
  1464. }
  1465. /* should be at beginning of ClassID, which is as follows
  1466. * (in Intel byte order):
  1467. * 00 67 61 56 54 C1 CE 11 85 53 00 AA 00 A1 F9 5B
  1468. *
  1469. * This is stored from Windows as long,short,short,char[8]
  1470. * so for byte order changes, the order only changes for
  1471. * the first 8 bytes in the ClassID.
  1472. *
  1473. * Test against this, ignoring second byte (Intel) since
  1474. * this could change depending on part of Fpx file we have.
  1475. */
  1476. if (readBytes(c, 16, is) < 0) {
  1477. is.reset();
  1478. return false;
  1479. }
  1480. // intel byte order
  1481. if (byteOrder == 0xFE &&
  1482. c[0] == 0x00 && c[2] == 0x61 && c[3] == 0x56 &&
  1483. c[4] == 0x54 && c[5] == 0xC1 && c[6] == 0xCE &&
  1484. c[7] == 0x11 && c[8] == 0x85 && c[9] == 0x53 &&
  1485. c[10]== 0x00 && c[11]== 0xAA && c[12]== 0x00 &&
  1486. c[13]== 0xA1 && c[14]== 0xF9 && c[15]== 0x5B) {
  1487. is.reset();
  1488. return true;
  1489. }
  1490. // non-intel byte order
  1491. else if (c[3] == 0x00 && c[1] == 0x61 && c[0] == 0x56 &&
  1492. c[5] == 0x54 && c[4] == 0xC1 && c[7] == 0xCE &&
  1493. c[6] == 0x11 && c[8] == 0x85 && c[9] == 0x53 &&
  1494. c[10]== 0x00 && c[11]== 0xAA && c[12]== 0x00 &&
  1495. c[13]== 0xA1 && c[14]== 0xF9 && c[15]== 0x5B) {
  1496. is.reset();
  1497. return true;
  1498. }
  1499. is.reset();
  1500. return false;
  1501. }
  1502. /**
  1503. * Tries to read the specified number of bytes from the stream
  1504. * Returns -1, If EOF is reached before len bytes are read, returns 0
  1505. * otherwise
  1506. */
  1507. static private int readBytes(int c[], int len, InputStream is)
  1508. throws IOException {
  1509. byte buf[] = new byte[len];
  1510. if (is.read(buf, 0, len) < len) {
  1511. return -1;
  1512. }
  1513. // fill the passed in int array
  1514. for (int i = 0; i < len; i++) {
  1515. c[i] = buf[i] & 0xff;
  1516. }
  1517. return 0;
  1518. }
  1519. /**
  1520. * Skips through the specified number of bytes from the stream
  1521. * until either EOF is reached, or the specified
  1522. * number of bytes have been skipped
  1523. */
  1524. static private long skipForward(InputStream is, long toSkip)
  1525. throws IOException {
  1526. long eachSkip = 0;
  1527. long skipped = 0;
  1528. while (skipped != toSkip) {
  1529. eachSkip = is.skip(toSkip - skipped);
  1530. // check if EOF is reached
  1531. if (eachSkip <= 0) {
  1532. if (is.read() == -1) {
  1533. return skipped ;
  1534. } else {
  1535. skipped++;
  1536. }
  1537. }
  1538. skipped += eachSkip;
  1539. }
  1540. return skipped;
  1541. }
  1542. }
  1543. class UnknownContentHandler extends ContentHandler {
  1544. public Object getContent(URLConnection uc) throws IOException {
  1545. return uc.getInputStream();
  1546. }
  1547. }