JarURLConnection.java 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  1. /* Copyright (C) 1999, 2000, 2002 Free Software Foundation
  2. This file is part of libgcj.
  3. This software is copyrighted work licensed under the terms of the
  4. Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
  5. details. */
  6. package java.net;
  7. import java.net.*;
  8. import java.io.*;
  9. import java.util.jar.*;
  10. import java.util.zip.*;
  11. import java.util.Map;
  12. import java.util.Vector;
  13. import java.util.Hashtable;
  14. import java.security.cert.Certificate;
  15. /**
  16. * @author Kresten Krab Thorup <krab@gnu.org>
  17. * @since 1.2
  18. * @date Aug 10, 1999.
  19. */
  20. public abstract class JarURLConnection extends URLConnection
  21. {
  22. // three different ways to say the same thing
  23. private final URL jarFileURL;
  24. /** The connection to the jar file itself. A JarURLConnection
  25. * can represent an entry in a jar file or an entire jar file. In
  26. * either case this describes just the jar file itself. */
  27. protected URLConnection jarFileURLConnection;
  28. // If this is a connection to a jar file element this is set, otherwise null.
  29. private final String element;
  30. // Cached JarURLConnection's
  31. static Hashtable conn_cache = new Hashtable();
  32. public URL getJarFileURL ()
  33. {
  34. return jarFileURL;
  35. }
  36. public String getEntryName ()
  37. {
  38. return element;
  39. }
  40. /**
  41. * Creates a new JarURLConnection
  42. *
  43. * @exception MalformedURLException If url is invalid
  44. *
  45. * @specnote This constructor is protected since JDK 1.4
  46. */
  47. protected JarURLConnection(URL url)
  48. throws MalformedURLException
  49. {
  50. super(url);
  51. String spec = url.getFile();
  52. int bang = spec.indexOf ("!/", 0);
  53. if (bang == -1)
  54. throw new MalformedURLException (url + ": No `!/' in spec.");
  55. // Extact the url for the jar itself.
  56. jarFileURL = new URL(spec.substring (0, bang));
  57. // Get the name of the element, if any.
  58. element = (bang+2==spec.length() ? null : spec.substring (bang+2));
  59. }
  60. public synchronized void connect() throws IOException
  61. {
  62. // Call is ignored if already connected.
  63. if (connected)
  64. return;
  65. if (getUseCaches())
  66. {
  67. jarFileURLConnection = (URLConnection) conn_cache.get (jarFileURL);
  68. if (jarFileURLConnection == null)
  69. {
  70. jarFileURLConnection = jarFileURL.openConnection ();
  71. jarFileURLConnection.setUseCaches (true);
  72. jarFileURLConnection.connect ();
  73. conn_cache.put (jarFileURL, jarFileURLConnection);
  74. }
  75. }
  76. else
  77. {
  78. jarFileURLConnection = jarFileURL.openConnection ();
  79. jarFileURLConnection.connect ();
  80. }
  81. connected = true;
  82. }
  83. public InputStream getInputStream() throws IOException
  84. {
  85. if (!connected)
  86. connect();
  87. if (! doInput)
  88. throw new ProtocolException("Can't open InputStream if doInput is false");
  89. if (element == null)
  90. {
  91. // This is a JarURLConnection for the entire jar file.
  92. InputStream jar_is = new BufferedInputStream(
  93. jarFileURLConnection.getInputStream ());
  94. return new JarInputStream(jar_is);
  95. }
  96. // Reaching this point, we're looking for an element of a jar file.
  97. JarFile jarfile = null;
  98. try
  99. {
  100. jarfile = getJarFile ();
  101. }
  102. catch (java.io.IOException x)
  103. {
  104. /* ignore */
  105. }
  106. if (jarfile != null)
  107. {
  108. // this is the easy way...
  109. ZipEntry entry = jarfile.getEntry(element);
  110. if (entry != null)
  111. return jarfile.getInputStream (entry);
  112. else
  113. return null;
  114. }
  115. else
  116. {
  117. // If the jar file is not local, ...
  118. JarInputStream zis = new JarInputStream(
  119. jarFileURLConnection.getInputStream ());
  120. // This is hideous, we're doing a linear search...
  121. for (ZipEntry ent = zis.getNextEntry ();
  122. ent != null;
  123. ent = zis.getNextEntry ())
  124. {
  125. if (element.equals (ent.getName ()))
  126. {
  127. int size = (int)ent.getSize();
  128. byte[] data = new byte[size];
  129. zis.read (data, 0, size);
  130. return new ByteArrayInputStream (data);
  131. }
  132. }
  133. }
  134. return null;
  135. }
  136. /**
  137. * Return the JAR entry object for this connection, if any
  138. *
  139. * @exception IOException If an error occurs
  140. */
  141. public JarEntry getJarEntry () throws IOException
  142. {
  143. JarFile jarfile = null;
  144. if (element == null)
  145. return null;
  146. if (! doInput)
  147. throw new ProtocolException("Can't open JarEntry if doInput is false");
  148. try
  149. {
  150. jarfile = getJarFile ();
  151. }
  152. catch (IOException x)
  153. {
  154. /* ignore */
  155. }
  156. if (jarfile == null)
  157. {
  158. JarInputStream zis = new JarInputStream(
  159. jarFileURLConnection.getInputStream ());
  160. // This is hideous, we're doing a linear search for the thing...
  161. for (ZipEntry ent = zis.getNextEntry ();
  162. ent != null;
  163. ent = zis.getNextEntry ())
  164. {
  165. if (element.equals (ent.getName ()))
  166. {
  167. return new JarEntry (ent);
  168. }
  169. }
  170. }
  171. else
  172. {
  173. return jarfile.getJarEntry (element);
  174. }
  175. return null;
  176. }
  177. /**
  178. * Return the JAR file for this connection
  179. *
  180. * @exception IOException If an error occurs
  181. */
  182. public abstract JarFile getJarFile() throws IOException;
  183. // Steal and borrow from protocol/file/Connection.java
  184. private Hashtable hdrHash = new Hashtable();
  185. private Vector hdrVec = new Vector();
  186. private boolean gotHeaders = false;
  187. // Override default method in URLConnection.
  188. public String getHeaderField(String name)
  189. {
  190. try
  191. {
  192. getHeaders();
  193. }
  194. catch (IOException x)
  195. {
  196. return null;
  197. }
  198. return (String) hdrHash.get(name.toLowerCase());
  199. }
  200. // Override default method in URLConnection.
  201. public Map getHeaderFields()
  202. {
  203. try
  204. {
  205. getHeaders();
  206. }
  207. catch (IOException x)
  208. {
  209. return null;
  210. }
  211. return hdrHash;
  212. }
  213. // Override default method in URLConnection.
  214. public String getHeaderField(int n)
  215. {
  216. try
  217. {
  218. getHeaders();
  219. }
  220. catch (IOException x)
  221. {
  222. return null;
  223. }
  224. if (n < hdrVec.size())
  225. return getField((String) hdrVec.elementAt(n));
  226. return null;
  227. }
  228. // Override default method in URLConnection.
  229. public String getHeaderFieldKey(int n)
  230. {
  231. try
  232. {
  233. getHeaders();
  234. }
  235. catch (IOException x)
  236. {
  237. return null;
  238. }
  239. if (n < hdrVec.size())
  240. return getKey((String) hdrVec.elementAt(n));
  241. return null;
  242. }
  243. private String getKey(String str)
  244. {
  245. if (str == null)
  246. return null;
  247. int index = str.indexOf(':');
  248. if (index >= 0)
  249. return str.substring(0, index);
  250. else
  251. return null;
  252. }
  253. private String getField(String str)
  254. {
  255. if (str == null)
  256. return null;
  257. int index = str.indexOf(':');
  258. if (index >= 0)
  259. return str.substring(index + 1).trim();
  260. else
  261. return str;
  262. }
  263. private void getHeaders() throws IOException
  264. {
  265. if (gotHeaders)
  266. return;
  267. gotHeaders = true;
  268. connect();
  269. // Yes, it is overkill to use the hash table and vector here since
  270. // we're only putting one header in the file, but in case we need
  271. // to add others later and for consistency, we'll implement it this way.
  272. // Add the only header we know about right now: Content-length.
  273. long len = -1;
  274. if (element == null)
  275. if (jarFileURLConnection != null)
  276. len = jarFileURLConnection.getContentLength ();
  277. else
  278. {
  279. JarEntry entry = getJarEntry();
  280. if (entry != null)
  281. len = entry.getSize ();
  282. }
  283. String line = "Content-length: " + len;
  284. hdrVec.addElement(line);
  285. // The key will never be null in this scenario since we build up the
  286. // headers ourselves. If we ever rely on getting a header from somewhere
  287. // else, then we may have to check if the result of getKey() is null.
  288. String key = getKey(line);
  289. hdrHash.put(key.toLowerCase(), Long.toString(len));
  290. }
  291. /**
  292. * Returns an array of Certificate objects for the jar file entry specified
  293. * by this URL or null if there are none
  294. *
  295. * @return A Certificate array
  296. *
  297. * @exception IOException If an error occurs
  298. */
  299. public Certificate[] getCertificates() throws IOException
  300. {
  301. return getJarEntry().getCertificates();
  302. }
  303. /**
  304. * Returns the main Attributes for the JAR file for this connection
  305. *
  306. * @exception IOException If an error occurs
  307. */
  308. public Attributes getMainAttributes () throws IOException
  309. {
  310. return getManifest ().getMainAttributes ();
  311. }
  312. /**
  313. * Return the Attributes object for this connection if the URL for it points
  314. * to a JAR file entry, null otherwise
  315. *
  316. * @exception IOException If an error occurs
  317. */
  318. public Attributes getAttributes () throws IOException
  319. {
  320. // FIXME: implement this
  321. return null;
  322. }
  323. /**
  324. * Returns the Manifest for this connection, or null if none
  325. *
  326. * @exception IOException If an error occurs
  327. */
  328. public Manifest getManifest () throws IOException
  329. {
  330. JarFile file = getJarFile ();
  331. return (file != null) ? file.getManifest() : null;
  332. }
  333. }