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