URLConnection.java 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776
  1. // URLConnection.java - Superclass of all communications links between
  2. // an application and a URL.
  3. /* Copyright (C) 1999, 2000 Free Software Foundation
  4. This file is part of libgcj.
  5. This software is copyrighted work licensed under the terms of the
  6. Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
  7. details. */
  8. package java.net;
  9. import java.io.*;
  10. import java.text.ParsePosition;
  11. import java.text.SimpleDateFormat;
  12. import java.util.Date;
  13. import java.util.Locale;
  14. import java.util.Hashtable;
  15. import java.util.Map;
  16. import java.util.StringTokenizer;
  17. import java.security.Permission;
  18. import java.security.AllPermission;
  19. import gnu.gcj.io.MimeTypes;
  20. /**
  21. * @author Warren Levy <warrenl@cygnus.com>
  22. * @date March 5, 1999.
  23. */
  24. /**
  25. * Written using on-line Java Platform 1.2 API Specification, as well
  26. * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998).
  27. * Status: One guessContentTypeFrom... methods not implemented.
  28. * getContent method assumes content type from response; see comment there.
  29. */
  30. public abstract class URLConnection
  31. {
  32. protected URL url;
  33. protected boolean doInput = true;
  34. protected boolean doOutput = false;
  35. protected boolean allowUserInteraction;
  36. protected boolean useCaches;
  37. protected long ifModifiedSince = 0L;
  38. protected boolean connected = false;
  39. private static boolean defaultAllowUserInteraction = false;
  40. private static boolean defaultUseCaches = true;
  41. private static FileNameMap fileNameMap; // Set by the URLConnection subclass.
  42. private static ContentHandlerFactory factory;
  43. private static ContentHandler contentHandler;
  44. private static Hashtable handlers = new Hashtable();
  45. private static Locale locale;
  46. private static SimpleDateFormat dateFormat1, dateFormat2, dateFormat3;
  47. private static boolean dateformats_initialized = false;
  48. /**
  49. * Creates a URL connection to a given URL. A real connection is not made.
  50. * Use #connect to do this.
  51. *
  52. * @param url The Object to create the URL connection to
  53. *
  54. * @see URLConnection:connect
  55. */
  56. protected URLConnection(URL url)
  57. {
  58. this.url = url;
  59. allowUserInteraction = defaultAllowUserInteraction;
  60. useCaches = defaultUseCaches;
  61. }
  62. /**
  63. * Creates a real connection to the object references by the URL given
  64. * to the constructor
  65. *
  66. * @exception IOException If an error occurs
  67. */
  68. public abstract void connect() throws IOException;
  69. /**
  70. * Returns ths URL to the object.
  71. */
  72. public URL getURL()
  73. {
  74. return url;
  75. }
  76. /**
  77. * Returns the value of the content-length header field
  78. */
  79. public int getContentLength()
  80. {
  81. return getHeaderFieldInt("content-length", -1);
  82. }
  83. /**
  84. * Returns the value of the content-type header field
  85. */
  86. public String getContentType()
  87. {
  88. return getHeaderField("content-type");
  89. }
  90. /**
  91. * Returns the value of the content-encoding header field
  92. */
  93. public String getContentEncoding()
  94. {
  95. return getHeaderField("content-encoding");
  96. }
  97. /**
  98. * Returns the value of the expires header field
  99. */
  100. public long getExpiration()
  101. {
  102. return getHeaderFieldDate("expiration", 0L);
  103. }
  104. /**
  105. * Returns the value of the date header field
  106. */
  107. public long getDate()
  108. {
  109. return getHeaderFieldDate("date", 0L);
  110. }
  111. /**
  112. * Returns the value of the last-modified header field
  113. */
  114. public long getLastModified()
  115. {
  116. return getHeaderFieldDate("last-modified", 0L);
  117. }
  118. /**
  119. * Returns the value of the n-th header field
  120. *
  121. * @param num The number of the header field
  122. */
  123. public String getHeaderField(int num)
  124. {
  125. // Subclasses for specific protocols override this.
  126. return null;
  127. }
  128. /**
  129. * Returns the value of the header filed specified by name
  130. *
  131. * @param name The name of the header field
  132. */
  133. public String getHeaderField(String name)
  134. {
  135. // Subclasses for specific protocols override this.
  136. return null;
  137. }
  138. /**
  139. * Returns a map of all sent header fields
  140. *
  141. * @since 1.4
  142. */
  143. public Map getHeaderFields()
  144. {
  145. // Subclasses for specific protocols override this.
  146. return null;
  147. }
  148. /**
  149. * Returns the value of the header filed name as int.
  150. *
  151. * @param name The name of the header field
  152. * @param val The default value
  153. *
  154. * @return Returns the value of the header filed or the default value
  155. * if the field is missing or malformed
  156. */
  157. public int getHeaderFieldInt(String name, int val)
  158. {
  159. String str = getHeaderField(name);
  160. try
  161. {
  162. if (str != null)
  163. val = Integer.parseInt(str);
  164. }
  165. catch (NumberFormatException e)
  166. {
  167. ; // Do nothing; val is the default.
  168. }
  169. return val;
  170. }
  171. /**
  172. * Returns the value of a header field parsed as date. The result is then
  173. * number of milliseconds since January 1st, 1970 GMT.
  174. *
  175. * @param name The name of the header field
  176. * @param val The dafault date
  177. *
  178. * @return Returns the date value of the header filed or the default value
  179. * if the field is missing or malformed
  180. */
  181. public long getHeaderFieldDate(String name, long val)
  182. {
  183. if (! dateformats_initialized)
  184. initializeDateFormats();
  185. String str = getHeaderField(name);
  186. if (str != null)
  187. {
  188. Date date;
  189. if ((date = dateFormat1.parse(str, new ParsePosition(0))) != null)
  190. val = date.getTime();
  191. else if ((date = dateFormat2.parse(str, new ParsePosition(0))) != null)
  192. val = date.getTime();
  193. else if ((date = dateFormat3.parse(str, new ParsePosition(0))) != null)
  194. val = date.getTime();
  195. }
  196. return val;
  197. }
  198. /**
  199. * Returns the key of the n-th header field
  200. *
  201. * @param num The number of the header field
  202. */
  203. public String getHeaderFieldKey(int num)
  204. {
  205. // Subclasses for specific protocols override this.
  206. return null;
  207. }
  208. /**
  209. * Retrieves the content of this URLConnection
  210. *
  211. * @exception IOException If an error occurs
  212. * @exception UnknownServiceException If the protocol does not support the
  213. * content type
  214. */
  215. public Object getContent() throws IOException
  216. {
  217. // FIXME: Doc indicates that other criteria should be applied as
  218. // heuristics to determine the true content type, e.g. see
  219. // guessContentTypeFromName() and guessContentTypeFromStream methods
  220. // as well as FileNameMap class & fileNameMap field & get/set methods.
  221. String cType = getContentType();
  222. contentHandler = setContentHandler(cType);
  223. if (contentHandler == null)
  224. return getInputStream();
  225. return contentHandler.getContent(this);
  226. }
  227. /**
  228. * Retrieves the content of this URLConnection
  229. *
  230. * @exception IOException If an error occurs
  231. * @exception UnknownServiceException If the protocol does not support the
  232. * content type
  233. */
  234. public Object getContent(Class[] classes) throws IOException
  235. {
  236. // FIXME: implement this
  237. return getContent ();
  238. }
  239. /**
  240. * Returns a permission object representing the permission necessary to make
  241. * the connection represented by this object. This method returns null if no
  242. * permission is required to make the connection.
  243. *
  244. * @exception IOException If the computation of the permission requires
  245. * network or file I/O and an exception occurs while computing it
  246. */
  247. public Permission getPermission() throws IOException
  248. {
  249. // Subclasses may override this.
  250. return new java.security.AllPermission();
  251. }
  252. /**
  253. * Returns the input stream of the URL connection
  254. *
  255. * @exception IOException If an error occurs
  256. * @exception UnknownServiceException If the protocol does not support input
  257. */
  258. public InputStream getInputStream() throws IOException
  259. {
  260. // Subclasses for specific protocols override this.
  261. throw new UnknownServiceException("Protocol " + url.getProtocol() +
  262. " does not support input.");
  263. }
  264. /**
  265. * Returns the output stream of the URL connection
  266. *
  267. * @exception IOException If an error occurs
  268. * @exception UnknownServiceException If the protocol does not support output
  269. */
  270. public OutputStream getOutputStream() throws IOException
  271. {
  272. // Subclasses for specific protocols override this.
  273. throw new UnknownServiceException("Protocol " + url.getProtocol() +
  274. " does not support output.");
  275. }
  276. /**
  277. * Returns a string representation of the URL connection object
  278. */
  279. public String toString()
  280. {
  281. return this.getClass().getName() + ":" + url.toString();
  282. }
  283. /**
  284. * Sets tha value of the doInput field.
  285. *
  286. * @param doinput The new value of the doInput field
  287. *
  288. * @exception IllegalStateException If already connected
  289. */
  290. public void setDoInput(boolean doinput)
  291. {
  292. if (connected)
  293. throw new IllegalStateException ("Already connected");
  294. doInput = doinput;
  295. }
  296. /**
  297. * Returns the current value of the doInput field
  298. */
  299. public boolean getDoInput()
  300. {
  301. return doInput;
  302. }
  303. /**
  304. * Sets the value of the doOutput field
  305. *
  306. * @param dooutput The new value of the doOutput field
  307. *
  308. * @exception IllegalStateException If already connected
  309. */
  310. public void setDoOutput(boolean dooutput)
  311. {
  312. if (connected)
  313. throw new IllegalStateException ("Already connected");
  314. doOutput = dooutput;
  315. }
  316. /**
  317. * Returns the current value of the doOutput field
  318. */
  319. public boolean getDoOutput()
  320. {
  321. return doOutput;
  322. }
  323. /**
  324. * Sets a new value to the allowUserInteraction field
  325. *
  326. * @param allowed The new value
  327. *
  328. * @exception IllegalStateException If already connected
  329. */
  330. public void setAllowUserInteraction(boolean allowed)
  331. {
  332. if (connected)
  333. throw new IllegalStateException ("Already connected");
  334. allowUserInteraction = allowed;
  335. }
  336. /**
  337. * Returns the current value of the allowUserInteraction field
  338. */
  339. public boolean getAllowUserInteraction()
  340. {
  341. return allowUserInteraction;
  342. }
  343. /**
  344. * Sets the default value if the allowUserInteraction field
  345. *
  346. * @param allowed The new default value
  347. */
  348. public static void setDefaultAllowUserInteraction(boolean allowed)
  349. {
  350. defaultAllowUserInteraction = allowed;
  351. }
  352. /**
  353. * Returns the default value of the allowUserInteraction field
  354. */
  355. public static boolean getDefaultAllowUserInteraction()
  356. {
  357. return defaultAllowUserInteraction;
  358. }
  359. /**
  360. * Sets a new value to the useCaches field
  361. *
  362. * @param usecaches The new value
  363. *
  364. * @exception IllegalStateException If already connected
  365. */
  366. public void setUseCaches(boolean usecaches)
  367. {
  368. if (connected)
  369. throw new IllegalStateException ("Already connected");
  370. useCaches = usecaches;
  371. }
  372. /**
  373. * The current value of the useCaches field
  374. */
  375. public boolean getUseCaches()
  376. {
  377. return useCaches;
  378. }
  379. /**
  380. * Sets the value of the ifModifiedSince field
  381. *
  382. * @param ifmodifiedsince The new value in milliseconds
  383. * since January 1, 1970 GMT
  384. *
  385. * @exception IllegalStateException If already connected
  386. */
  387. public void setIfModifiedSince(long ifmodifiedsince)
  388. {
  389. if (connected)
  390. throw new IllegalStateException ("Already connected");
  391. ifModifiedSince = ifmodifiedsince;
  392. }
  393. /**
  394. * Returns the current value of the ifModifiedSince field
  395. */
  396. public long getIfModifiedSince()
  397. {
  398. return ifModifiedSince;
  399. }
  400. /**
  401. * Returns the default value of the useCaches field
  402. */
  403. public boolean getDefaultUseCaches()
  404. {
  405. return defaultUseCaches;
  406. }
  407. /**
  408. * Sets the default value of the useCaches field
  409. *
  410. * @param defaultusecaches The new default value
  411. */
  412. public void setDefaultUseCaches(boolean defaultusecaches)
  413. {
  414. defaultUseCaches = defaultusecaches;
  415. }
  416. /**
  417. * Sets a property specified by key to value.
  418. *
  419. * @param key Key of the property to set
  420. * @param value Value of the Property to set
  421. *
  422. * @exception IllegalStateException If already connected
  423. * @exception NullPointerException If key is null
  424. *
  425. * @see URLConnection:getRequestProperty(String key)
  426. * @see URLConnection:addRequestProperty(String key, String value)
  427. */
  428. public void setRequestProperty(String key, String value)
  429. {
  430. if (connected)
  431. throw new IllegalStateException ("Already connected");
  432. // Do nothing unless overridden by subclasses that support setting
  433. // header fields in the request.
  434. }
  435. /**
  436. * Sets a property specified by key to value. If the property key already
  437. * is assigned to a value it does nothing.
  438. *
  439. * @param key Key of the property to add
  440. * @param value Value of the Property to add
  441. *
  442. * @exception IllegalStateException If already connected
  443. * @exception NullPointerException If key is null
  444. *
  445. * @see URLConnection:getRequestProperty(String key)
  446. * @see URLConnection:setRequestProperty(String key, String value)
  447. *
  448. * @since 1.4
  449. */
  450. public void addRequestProperty(String key, String value)
  451. {
  452. if (connected)
  453. throw new IllegalStateException ("Already connected");
  454. if (getRequestProperty (key) == null)
  455. {
  456. setRequestProperty (key, value);
  457. }
  458. }
  459. /**
  460. * Returns a property value specified by key.
  461. *
  462. * @param key Key of the property to return
  463. *
  464. * @exception IllegalStateException If already connected
  465. *
  466. * @see URLConnection:setRequestProperty(String key, String value)
  467. * @see URLConnection:addRequestProperty(String key, String value)
  468. *
  469. * @return Value of the property.
  470. */
  471. public String getRequestProperty(String key)
  472. {
  473. if (connected)
  474. throw new IllegalStateException ("Already connected");
  475. // Overridden by subclasses that support reading header fields from the
  476. // request.
  477. return null;
  478. }
  479. /**
  480. * Returns a map that contains all properties of the request
  481. *
  482. * @exception IllegalStateException If already connected
  483. *
  484. * @return The map of properties
  485. */
  486. public Map getRequestProperties()
  487. {
  488. // Overridden by subclasses that support reading header fields from the
  489. // request.
  490. return null;
  491. }
  492. /**
  493. * Defines a default request property
  494. *
  495. * @param key The key of the property
  496. * @param value The value of the property
  497. *
  498. * @deprecated 1.3 The method setRequestProperty should be used instead
  499. *
  500. * @see URLConnection:setRequestProperty
  501. */
  502. public static void setDefaultRequestProperty(String key, String value)
  503. {
  504. // Do nothing unless overridden by subclasses that support setting
  505. // default request properties.
  506. }
  507. /**
  508. * Returns the value of a default request property
  509. *
  510. * @param key The key of the default property
  511. *
  512. * @return The value of the default property or null if not available
  513. *
  514. * @deprecated 1.3 The method getRequestProperty should be used instead
  515. *
  516. * @see URLConnection:getRequestProperty
  517. */
  518. public static String getDefaultRequestProperty(String key)
  519. {
  520. // Overridden by subclasses that support default request properties.
  521. return null;
  522. }
  523. /**
  524. * Sets a ContentHandlerFactory
  525. *
  526. * @param fac The ContentHandlerFactory
  527. *
  528. * @exception Error If the factory has already been defined
  529. * @exception SecurityException If a security manager exists and its
  530. * checkSetFactory method doesn't allow the operation
  531. */
  532. public static void setContentHandlerFactory(ContentHandlerFactory fac)
  533. {
  534. if (factory != null)
  535. throw new Error("ContentHandlerFactory already set");
  536. // Throw an exception if an extant security mgr precludes
  537. // setting the factory.
  538. SecurityManager s = System.getSecurityManager();
  539. if (s != null)
  540. s.checkSetFactory();
  541. factory = fac;
  542. }
  543. /**
  544. * Tries to determine the content type of an object, based on the
  545. * specified file name
  546. *
  547. * @param fname The filename to guess the content type from
  548. *
  549. * @specnote public since JDK 1.4
  550. */
  551. public static String guessContentTypeFromName(String fname)
  552. {
  553. int dot = fname.lastIndexOf (".");
  554. if (dot != -1)
  555. {
  556. if (dot == fname.length())
  557. return ("application/octet-stream");
  558. else
  559. fname = fname.substring (dot + 1);
  560. }
  561. String type = MimeTypes.getMimeTypeFromExtension (fname);
  562. if (type == null)
  563. return("application/octet-stream");
  564. return(type);
  565. }
  566. /**
  567. * Tries to guess the content type of an object, based on the characters
  568. * at the beginning of then input stream
  569. *
  570. * @param is The input stream to guess from
  571. *
  572. * @exception IOException If an error occurs
  573. */
  574. public static String guessContentTypeFromStream(InputStream is)
  575. throws IOException
  576. {
  577. is.mark(1024);
  578. // FIXME: Implement this. Use system mimetype informations (like "file").
  579. is.reset();
  580. return null;
  581. }
  582. /**
  583. * Returns a filename map (a mimetable)
  584. *
  585. * @since 1.2
  586. */
  587. public static FileNameMap getFileNameMap()
  588. {
  589. return fileNameMap;
  590. }
  591. /**
  592. * Sets a FileNameMap
  593. *
  594. * @param map The new FileNameMap
  595. *
  596. * @exception SecurityException If a security manager exists and its
  597. * checkSetFactory method doesn't allow the operation
  598. *
  599. * @since 1.2
  600. */
  601. public static void setFileNameMap(FileNameMap map)
  602. {
  603. // Throw an exception if an extant security mgr precludes
  604. // setting the factory.
  605. SecurityManager s = System.getSecurityManager();
  606. if (s != null)
  607. s.checkSetFactory();
  608. fileNameMap = map;
  609. }
  610. private ContentHandler setContentHandler(String contentType)
  611. {
  612. ContentHandler handler;
  613. // No content type so just handle it as the default.
  614. if (contentType == null || contentType == "")
  615. return null;
  616. // See if a handler has been cached for this content type.
  617. // For efficiency, if a content type has been searched for but not
  618. // found, it will be in the hash table but as the contentType String
  619. // instead of a ContentHandler.
  620. if ((handler = (ContentHandler) handlers.get(contentType)) != null)
  621. if (handler instanceof ContentHandler)
  622. return handler;
  623. else
  624. return null;
  625. // If a non-default factory has been set, use it to find the content type.
  626. if (factory != null)
  627. handler = factory.createContentHandler(contentType);
  628. // Non-default factory may have returned null or a factory wasn't set.
  629. // Use the default search algorithm to find a handler for this content type.
  630. if (handler == null)
  631. {
  632. // Get the list of packages to check and append our default handler
  633. // to it, along with the JDK specified default as a last resort.
  634. // Except in very unusual environments the JDK specified one shouldn't
  635. // ever be needed (or available).
  636. String propVal = System.getProperty("java.content.handler.pkgs");
  637. propVal = (propVal == null) ? "" : (propVal + "|");
  638. propVal = propVal + "gnu.gcj.content|sun.net.www.content";
  639. // Replace the '/' character in the content type with '.' and
  640. // all other non-alphabetic, non-numeric characters with '_'.
  641. StringTokenizer pkgPrefix = new StringTokenizer(propVal, "|");
  642. char[] cArray = contentType.toCharArray();
  643. for (int i = 0; i < cArray.length; i++)
  644. {
  645. if (cArray[i] == '/')
  646. cArray[i] = '.';
  647. else if (! ((cArray[i] >= 'A' && cArray[i] <= 'Z') ||
  648. (cArray[i] >= 'a' && cArray[i] <= 'z') ||
  649. (cArray[i] >= '0' && cArray[i] <= '9')))
  650. cArray[i] = '_';
  651. }
  652. String contentClass = new String(cArray);
  653. // See if a class of this content type exists in any of the packages.
  654. do
  655. {
  656. String facName = pkgPrefix.nextToken() + "." + contentClass;
  657. try
  658. {
  659. handler =
  660. (ContentHandler) Class.forName(facName).newInstance();
  661. }
  662. catch (Exception e)
  663. {
  664. // Can't instantiate; handler still null, go on to next element.
  665. }
  666. } while ((handler == null ||
  667. ! (handler instanceof ContentHandler)) &&
  668. pkgPrefix.hasMoreTokens());
  669. }
  670. // Update the hashtable with the new content handler.
  671. if (handler != null && handler instanceof ContentHandler)
  672. {
  673. handlers.put(contentType, handler);
  674. return handler;
  675. }
  676. // For efficiency on subsequent searches, put a dummy entry in the hash
  677. // table for content types that don't have a non-default ContentHandler.
  678. handlers.put(contentType, contentType);
  679. return null;
  680. }
  681. // We don't put these in a static initializer, because it creates problems
  682. // with initializer co-dependency: SimpleDateFormat's constructors eventually
  683. // depend on URLConnection (via the java.text.*Symbols classes).
  684. private synchronized void initializeDateFormats()
  685. {
  686. if (dateformats_initialized)
  687. return;
  688. locale = new Locale("En", "Us", "Unix");
  689. dateFormat1 = new SimpleDateFormat("EEE, dd MMM yyyy hh:mm:ss 'GMT'",
  690. locale);
  691. dateFormat2 = new SimpleDateFormat("EEEE, dd-MMM-yy hh:mm:ss 'GMT'",
  692. locale);
  693. dateFormat3 = new SimpleDateFormat("EEE MMM d hh:mm:ss yyyy", locale);
  694. dateformats_initialized = true;
  695. }
  696. }