blob: 4388f79d8910685921e8a0ddea9b9e11cf2d3512 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2001-2006 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.net.www.protocol.jar;
27
28import java.io.*;
29import java.net.*;
30import java.util.*;
31import java.util.jar.*;
32import java.util.zip.ZipFile;
33import java.util.zip.ZipEntry;
34import java.security.CodeSigner;
35import java.security.cert.Certificate;
36import java.security.AccessController;
37import java.security.PrivilegedAction;
38import java.security.PrivilegedExceptionAction;
39import java.security.PrivilegedActionException;
40import sun.net.www.ParseUtil;
41
42/* URL jar file is a common JarFile subtype used for JarURLConnection */
43public class URLJarFile extends JarFile {
44
45 /*
46 * Interface to be able to call retrieve() in plugin if
47 * this variable is set.
48 */
49 private static URLJarFileCallBack callback = null;
50
51 /* Controller of the Jar File's closing */
52 private URLJarFileCloseController closeController = null;
53
54 private static int BUF_SIZE = 2048;
55
56 private Manifest superMan;
57 private Attributes superAttr;
58 private Map superEntries;
59
60 static JarFile getJarFile(URL url) throws IOException {
61 return getJarFile(url, null);
62 }
63
64 static JarFile getJarFile(URL url, URLJarFileCloseController closeController) throws IOException {
65 if (isFileURL(url))
66 return new URLJarFile(url, closeController);
67 else {
68 return retrieve(url, closeController);
69 }
70 }
71
72 /*
73 * Changed modifier from private to public in order to be able
74 * to instantiate URLJarFile from sun.plugin package.
75 */
76 public URLJarFile(File file) throws IOException {
77 this(file, null);
78 }
79
80 /*
81 * Changed modifier from private to public in order to be able
82 * to instantiate URLJarFile from sun.plugin package.
83 */
84 public URLJarFile(File file, URLJarFileCloseController closeController) throws IOException {
85 super(file, true, ZipFile.OPEN_READ | ZipFile.OPEN_DELETE);
86 this.closeController = closeController;
87 }
88
89 private URLJarFile(URL url, URLJarFileCloseController closeController) throws IOException {
90 super(ParseUtil.decode(url.getFile()));
91 this.closeController = closeController;
92 }
93
94 private static boolean isFileURL(URL url) {
95 if (url.getProtocol().equalsIgnoreCase("file")) {
96 /*
97 * Consider this a 'file' only if it's a LOCAL file, because
98 * 'file:' URLs can be accessible through ftp.
99 */
100 String host = url.getHost();
101 if (host == null || host.equals("") || host.equals("~") ||
102 host.equalsIgnoreCase("localhost"))
103 return true;
104 }
105 return false;
106 }
107
108 /*
109 * close the jar file.
110 */
111 protected void finalize() throws IOException {
112 close();
113 }
114
115 /**
116 * Returns the <code>ZipEntry</code> for the given entry name or
117 * <code>null</code> if not found.
118 *
119 * @param name the JAR file entry name
120 * @return the <code>ZipEntry</code> for the given entry name or
121 * <code>null</code> if not found
122 * @see java.util.zip.ZipEntry
123 */
124 public ZipEntry getEntry(String name) {
125 ZipEntry ze = super.getEntry(name);
126 if (ze != null) {
127 if (ze instanceof JarEntry)
128 return new URLJarFileEntry((JarEntry)ze);
129 else
130 throw new InternalError(super.getClass() +
131 " returned unexpected entry type " +
132 ze.getClass());
133 }
134 return null;
135 }
136
137 public Manifest getManifest() throws IOException {
138
139 if (!isSuperMan()) {
140 return null;
141 }
142
143 Manifest man = new Manifest();
144 Attributes attr = man.getMainAttributes();
145 attr.putAll((Map)superAttr.clone());
146
147 // now deep copy the manifest entries
148 if (superEntries != null) {
149 Map entries = man.getEntries();
150 Iterator it = superEntries.keySet().iterator();
151 while (it.hasNext()) {
152 Object key = it.next();
153 Attributes at = (Attributes)superEntries.get(key);
154 entries.put(key, at.clone());
155 }
156 }
157
158 return man;
159 }
160
161 /* If close controller is set the notify the controller about the pending close */
162 public void close() throws IOException {
163 if (closeController != null) {
164 closeController.close(this);
165 }
166 super.close();
167 }
168
169 // optimal side-effects
170 private synchronized boolean isSuperMan() throws IOException {
171
172 if (superMan == null) {
173 superMan = super.getManifest();
174 }
175
176 if (superMan != null) {
177 superAttr = superMan.getMainAttributes();
178 superEntries = superMan.getEntries();
179 return true;
180 } else
181 return false;
182 }
183
184 /**
185 * Given a URL, retrieves a JAR file, caches it to disk, and creates a
186 * cached JAR file object.
187 */
188 private static JarFile retrieve(final URL url) throws IOException {
189 return retrieve(url, null);
190 }
191
192 /**
193 * Given a URL, retrieves a JAR file, caches it to disk, and creates a
194 * cached JAR file object.
195 */
196 private static JarFile retrieve(final URL url, final URLJarFileCloseController closeController) throws IOException {
197 /*
198 * See if interface is set, then call retrieve function of the class
199 * that implements URLJarFileCallBack interface (sun.plugin - to
200 * handle the cache failure for JARJAR file.)
201 */
202 if (callback != null)
203 {
204 return callback.retrieve(url);
205 }
206
207 else
208 {
209
210 JarFile result = null;
211
212 /* get the stream before asserting privileges */
213 final InputStream in = url.openConnection().getInputStream();
214
215 try {
216 result = (JarFile)
217 AccessController.doPrivileged(new PrivilegedExceptionAction() {
218 public Object run() throws IOException {
219 OutputStream out = null;
220 File tmpFile = null;
221 try {
222 tmpFile = File.createTempFile("jar_cache", null);
223 tmpFile.deleteOnExit();
224 out = new FileOutputStream(tmpFile);
225 int read = 0;
226 byte[] buf = new byte[BUF_SIZE];
227 while ((read = in.read(buf)) != -1) {
228 out.write(buf, 0, read);
229 }
230 out.close();
231 out = null;
232 return new URLJarFile(tmpFile, closeController);
233 } catch (IOException e) {
234 if (tmpFile != null) {
235 tmpFile.delete();
236 }
237 throw e;
238 } finally {
239 if (in != null) {
240 in.close();
241 }
242 if (out != null) {
243 out.close();
244 }
245 }
246 }
247 });
248 } catch (PrivilegedActionException pae) {
249 throw (IOException) pae.getException();
250 }
251
252 return result;
253 }
254 }
255
256 /*
257 * Set the call back interface to call retrive function in sun.plugin
258 * package if plugin is running.
259 */
260 public static void setCallBack(URLJarFileCallBack cb)
261 {
262 callback = cb;
263 }
264
265
266 private class URLJarFileEntry extends JarEntry {
267 private JarEntry je;
268
269 URLJarFileEntry(JarEntry je) {
270 super(je);
271 this.je=je;
272 }
273
274 public Attributes getAttributes() throws IOException {
275 if (URLJarFile.this.isSuperMan()) {
276 Map e = URLJarFile.this.superEntries;
277 if (e != null) {
278 Attributes a = (Attributes)e.get(getName());
279 if (a != null)
280 return (Attributes)a.clone();
281 }
282 }
283 return null;
284 }
285
286 public java.security.cert.Certificate[] getCertificates() {
287 Certificate[] certs = je.getCertificates();
288 return certs == null? null: certs.clone();
289 }
290
291 public CodeSigner[] getCodeSigners() {
292 CodeSigner[] csg = je.getCodeSigners();
293 return csg == null? null: csg.clone();
294 }
295 }
296
297 public interface URLJarFileCloseController {
298 public void close(JarFile jarFile);
299 }
300}