1
2
3
4
5
6
7
8
9
10
11
12
13 package org.eclipse.jetty.util.resource;
14
15 import java.io.File;
16 import java.io.FileOutputStream;
17 import java.io.FilterInputStream;
18 import java.io.IOException;
19 import java.io.InputStream;
20 import java.net.JarURLConnection;
21 import java.net.URL;
22 import java.util.jar.JarEntry;
23 import java.util.jar.JarInputStream;
24 import java.util.jar.Manifest;
25
26 import org.eclipse.jetty.util.IO;
27 import org.eclipse.jetty.util.log.Log;
28
29
30
31 public class JarResource extends URLResource
32 {
33
34 protected transient JarURLConnection _jarConnection;
35
36
37 JarResource(URL url)
38 {
39 super(url,null);
40 }
41
42
43 JarResource(URL url, boolean useCaches)
44 {
45 super(url, null, useCaches);
46 }
47
48
49 public synchronized void release()
50 {
51 _jarConnection=null;
52 super.release();
53 }
54
55
56 protected boolean checkConnection()
57 {
58 super.checkConnection();
59 try
60 {
61 if (_jarConnection!=_connection)
62 newConnection();
63 }
64 catch(IOException e)
65 {
66 Log.ignore(e);
67 _jarConnection=null;
68 }
69
70 return _jarConnection!=null;
71 }
72
73
74
75
76
77 protected void newConnection() throws IOException
78 {
79 _jarConnection=(JarURLConnection)_connection;
80 }
81
82
83
84
85
86 public boolean exists()
87 {
88 if (_urlString.endsWith("!/"))
89 return checkConnection();
90 else
91 return super.exists();
92 }
93
94
95 public File getFile()
96 throws IOException
97 {
98 return null;
99 }
100
101
102 public InputStream getInputStream()
103 throws java.io.IOException
104 {
105 checkConnection();
106 if (!_urlString.endsWith("!/"))
107 return new FilterInputStream(super.getInputStream())
108 {
109 public void close() throws IOException {this.in=IO.getClosedStream();}
110 };
111
112 URL url = new URL(_urlString.substring(4,_urlString.length()-2));
113 InputStream is = url.openStream();
114 return is;
115 }
116
117
118 @Deprecated
119 public void extract(File dest, boolean deleteOnExit)
120 throws IOException
121 {
122 if (deleteOnExit)
123 dest.deleteOnExit();
124 copyTo(dest);
125 }
126
127
128 @Override
129 public void copyTo(File directory)
130 throws IOException
131 {
132 if(Log.isDebugEnabled())Log.debug("Extract "+this+" to "+directory);
133
134 String urlString = this.getURL().toExternalForm().trim();
135 int endOfJarUrl = urlString.indexOf("!/");
136 int startOfJarUrl = (endOfJarUrl >= 0?4:0);
137
138 if (endOfJarUrl < 0)
139 throw new IOException("Not a valid jar url: "+urlString);
140
141 URL jarFileURL = new URL(urlString.substring(startOfJarUrl, endOfJarUrl));
142 String subEntryName = (endOfJarUrl+2 < urlString.length() ? urlString.substring(endOfJarUrl + 2) : null);
143 boolean subEntryIsDir = (subEntryName != null && subEntryName.endsWith("/")?true:false);
144
145 if (Log.isDebugEnabled()) Log.debug("Extracting entry = "+subEntryName+" from jar "+jarFileURL);
146
147 InputStream is = jarFileURL.openConnection().getInputStream();
148 JarInputStream jin = new JarInputStream(is);
149 JarEntry entry;
150 boolean shouldExtract;
151 while((entry=jin.getNextJarEntry())!=null)
152 {
153 String entryName = entry.getName();
154 if ((subEntryName != null) && (entryName.startsWith(subEntryName)))
155 {
156
157
158 if (subEntryIsDir)
159 {
160
161
162
163
164 entryName = entryName.substring(subEntryName.length());
165 if (!entryName.equals(""))
166 {
167
168 shouldExtract = true;
169 }
170 else
171 shouldExtract = false;
172 }
173 else
174 shouldExtract = true;
175 }
176 else if ((subEntryName != null) && (!entryName.startsWith(subEntryName)))
177 {
178
179
180 shouldExtract = false;
181 }
182 else
183 {
184
185 shouldExtract = true;
186 }
187
188
189 if (!shouldExtract)
190 {
191 if (Log.isDebugEnabled()) Log.debug("Skipping entry: "+entryName);
192 continue;
193 }
194
195
196 File file=new File(directory,entryName);
197
198 if(!file.getCanonicalPath().regionMatches(0,directory.getCanonicalPath()+"/",0,directory.getCanonicalPath().length()+1)) {
199 if (Log.isDebugEnabled()) Log.debug("Invalid entry: " + entryName);
200 continue;
201 }
202
203 if (entry.isDirectory())
204 {
205
206 if (!file.exists())
207 file.mkdirs();
208 }
209 else
210 {
211
212 File dir = new File(file.getParent());
213 if (!dir.exists())
214 dir.mkdirs();
215
216
217 FileOutputStream fout = null;
218 try
219 {
220 fout = new FileOutputStream(file);
221 IO.copy(jin,fout);
222 }
223 finally
224 {
225 IO.close(fout);
226 }
227
228
229 if (entry.getTime()>=0)
230 file.setLastModified(entry.getTime());
231 }
232 }
233
234 if ((subEntryName == null) || (subEntryName != null && subEntryName.equalsIgnoreCase("META-INF/MANIFEST.MF")))
235 {
236 Manifest manifest = jin.getManifest();
237 if (manifest != null)
238 {
239 File metaInf = new File (directory, "META-INF");
240 metaInf.mkdir();
241 File f = new File(metaInf, "MANIFEST.MF");
242 FileOutputStream fout = new FileOutputStream(f);
243 manifest.write(fout);
244 fout.close();
245 }
246 }
247 IO.close(jin);
248 }
249
250 public static Resource newJarResource(Resource resource) throws IOException
251 {
252 if (resource instanceof JarResource)
253 return resource;
254 return Resource.newResource("jar:" + resource + "!/");
255 }
256 }