Lines 19-30
package org.apache.catalina.webresources;
Link Here
|
19 |
import java.io.File; |
19 |
import java.io.File; |
20 |
import java.io.IOException; |
20 |
import java.io.IOException; |
21 |
import java.io.InputStream; |
21 |
import java.io.InputStream; |
|
|
22 |
import java.io.FilterInputStream; |
23 |
import java.io.PushbackInputStream; |
24 |
import java.util.zip.ZipInputStream; |
25 |
import java.util.zip.ZipEntry; |
22 |
import java.net.MalformedURLException; |
26 |
import java.net.MalformedURLException; |
23 |
import java.util.HashMap; |
27 |
import java.util.HashMap; |
|
|
28 |
import java.util.Map; |
24 |
import java.util.jar.JarEntry; |
29 |
import java.util.jar.JarEntry; |
25 |
import java.util.jar.JarFile; |
30 |
import java.util.jar.JarFile; |
26 |
import java.util.jar.JarInputStream; |
31 |
import java.util.jar.JarInputStream; |
27 |
import java.util.jar.Manifest; |
32 |
import java.util.jar.Manifest; |
|
|
33 |
import java.util.Collections; |
28 |
|
34 |
|
29 |
import org.apache.catalina.LifecycleException; |
35 |
import org.apache.catalina.LifecycleException; |
30 |
import org.apache.catalina.WebResource; |
36 |
import org.apache.catalina.WebResource; |
Lines 39-44
import org.apache.tomcat.util.buf.UriUtil;
Link Here
|
39 |
public class JarWarResourceSet extends AbstractArchiveResourceSet { |
45 |
public class JarWarResourceSet extends AbstractArchiveResourceSet { |
40 |
|
46 |
|
41 |
private final String archivePath; |
47 |
private final String archivePath; |
|
|
48 |
private Map<String, Long> archiveEntryPositions; |
42 |
|
49 |
|
43 |
/** |
50 |
/** |
44 |
* Creates a new {@link org.apache.catalina.WebResourceSet} based on a JAR |
51 |
* Creates a new {@link org.apache.catalina.WebResourceSet} based on a JAR |
Lines 94-111
public class JarWarResourceSet extends AbstractArchiveResourceSet {
Link Here
|
94 |
* returned. |
101 |
* returned. |
95 |
*/ |
102 |
*/ |
96 |
@Override |
103 |
@Override |
97 |
protected HashMap<String,JarEntry> getArchiveEntries(boolean single) { |
104 |
protected Map<String,JarEntry> getArchiveEntries(boolean single) { |
98 |
synchronized (archiveLock) { |
105 |
synchronized (archiveLock) { |
99 |
if (archiveEntries == null) { |
106 |
if (archiveEntries == null) { |
100 |
JarFile warFile = null; |
107 |
JarFile warFile = null; |
101 |
InputStream jarFileIs = null; |
|
|
102 |
archiveEntries = new HashMap<>(); |
108 |
archiveEntries = new HashMap<>(); |
|
|
109 |
archiveEntryPositions = new HashMap<>(); |
110 |
|
103 |
try { |
111 |
try { |
104 |
warFile = openJarFile(); |
112 |
warFile = openJarFile(); |
105 |
JarEntry jarFileInWar = warFile.getJarEntry(archivePath); |
113 |
JarEntry jarFileInWar = warFile.getJarEntry(archivePath); |
106 |
jarFileIs = warFile.getInputStream(jarFileInWar); |
|
|
107 |
|
114 |
|
108 |
try (JarInputStream jarIs = new JarInputStream(jarFileIs)) { |
115 |
/* process and validate the JAR file */ |
|
|
116 |
try (InputStream jarFileIs = warFile.getInputStream(jarFileInWar); |
117 |
JarInputStream jarIs = new JarInputStream(jarFileIs)) { |
109 |
JarEntry entry = jarIs.getNextJarEntry(); |
118 |
JarEntry entry = jarIs.getNextJarEntry(); |
110 |
while (entry != null) { |
119 |
while (entry != null) { |
111 |
archiveEntries.put(entry.getName(), entry); |
120 |
archiveEntries.put(entry.getName(), entry); |
Lines 113-118
public class JarWarResourceSet extends AbstractArchiveResourceSet {
Link Here
|
113 |
} |
122 |
} |
114 |
setManifest(jarIs.getManifest()); |
123 |
setManifest(jarIs.getManifest()); |
115 |
} |
124 |
} |
|
|
125 |
|
126 |
/* process again, this time with positions of PK entries */ |
127 |
try (InputStream jarFileIs = warFile.getInputStream(jarFileInWar); |
128 |
ZipInputStreamWithPosition zipIs = new ZipInputStreamWithPosition(jarFileIs)) { |
129 |
long posBefore = zipIs.getBytesRead(); |
130 |
ZipEntry entry = zipIs.getNextEntry(); |
131 |
while (entry != null) { |
132 |
if(archiveEntries.containsKey(entry.getName())) { |
133 |
archiveEntryPositions.put(entry.getName(), posBefore); |
134 |
} |
135 |
zipIs.closeEntry(); |
136 |
|
137 |
posBefore = zipIs.getBytesRead(); |
138 |
entry = zipIs.getNextEntry(); |
139 |
} |
140 |
} |
116 |
} catch (IOException ioe) { |
141 |
} catch (IOException ioe) { |
117 |
// Should never happen |
142 |
// Should never happen |
118 |
archiveEntries = null; |
143 |
archiveEntries = null; |
Lines 121-136
public class JarWarResourceSet extends AbstractArchiveResourceSet {
Link Here
|
121 |
if (warFile != null) { |
146 |
if (warFile != null) { |
122 |
closeJarFile(); |
147 |
closeJarFile(); |
123 |
} |
148 |
} |
124 |
if (jarFileIs != null) { |
|
|
125 |
try { |
126 |
jarFileIs.close(); |
127 |
} catch (IOException e) { |
128 |
// Ignore |
129 |
} |
130 |
} |
131 |
} |
149 |
} |
132 |
} |
150 |
} |
133 |
return archiveEntries; |
151 |
return Collections.unmodifiableMap(archiveEntries); |
134 |
} |
152 |
} |
135 |
} |
153 |
} |
136 |
|
154 |
|
Lines 146-151
public class JarWarResourceSet extends AbstractArchiveResourceSet {
Link Here
|
146 |
throw new IllegalStateException("Coding error"); |
164 |
throw new IllegalStateException("Coding error"); |
147 |
} |
165 |
} |
148 |
|
166 |
|
|
|
167 |
public Map<String, Long> getArchiveEntryPositions() { |
168 |
return Collections.unmodifiableMap(archiveEntryPositions); |
169 |
} |
149 |
|
170 |
|
150 |
//-------------------------------------------------------- Lifecycle methods |
171 |
//-------------------------------------------------------- Lifecycle methods |
151 |
@Override |
172 |
@Override |
Lines 169-171
public class JarWarResourceSet extends AbstractArchiveResourceSet {
Link Here
|
169 |
} |
190 |
} |
170 |
} |
191 |
} |
171 |
} |
192 |
} |
|
|
193 |
|
194 |
class ZipInputStreamWithPosition extends ZipInputStream { |
195 |
|
196 |
public ZipInputStreamWithPosition(final InputStream in) throws IOException { |
197 |
super(in); |
198 |
this.in = new PushbackCountingInputStream(in, 512); |
199 |
} |
200 |
|
201 |
/** |
202 |
* Returns the current number of bytes read from this stream. |
203 |
* @return the number of read bytes |
204 |
*/ |
205 |
public long getBytesRead() { |
206 |
return ((PushbackCountingInputStream)in).getBytesRead(); |
207 |
} |
208 |
} |
209 |
|
210 |
/** |
211 |
* Stream that tracks the number of bytes read. |
212 |
* @NotThreadSafe |
213 |
*/ |
214 |
class PushbackCountingInputStream extends PushbackInputStream { |
215 |
private long bytesRead; |
216 |
|
217 |
public PushbackCountingInputStream(final InputStream in, int size) { |
218 |
super(in, size); |
219 |
} |
220 |
|
221 |
@Override |
222 |
public int read() throws IOException { |
223 |
final int r = super.read(); |
224 |
if (r >= 0) { |
225 |
count(1); |
226 |
} |
227 |
return r; |
228 |
} |
229 |
@Override |
230 |
public int read(final byte[] b) throws IOException { |
231 |
return read(b, 0, b.length); |
232 |
} |
233 |
@Override |
234 |
public int read(final byte[] b, final int off, final int len) throws IOException { |
235 |
final int r = super.read(b, off, len); |
236 |
if (r >= 0) { |
237 |
count(r); |
238 |
} |
239 |
return r; |
240 |
} |
241 |
/** |
242 |
* Increments the counter of already read bytes. |
243 |
* Doesn't increment if the EOF has been hit (read == -1) |
244 |
* |
245 |
* @param read the number of bytes read |
246 |
*/ |
247 |
protected final void count(final long read) { |
248 |
if (read != -1) { |
249 |
bytesRead += read; |
250 |
} |
251 |
} |
252 |
|
253 |
/** |
254 |
* Returns the current number of bytes read from this stream. |
255 |
* @return the number of read bytes |
256 |
*/ |
257 |
public long getBytesRead() { |
258 |
return bytesRead; |
259 |
} |
260 |
|
261 |
@Override |
262 |
public void unread(int b) throws IOException { |
263 |
super.unread(b); |
264 |
bytesRead--; |
265 |
} |
266 |
|
267 |
@Override |
268 |
public void unread(byte[] b, int off, int len) throws IOException { |
269 |
super.unread(b,off,len); |
270 |
bytesRead -= len; |
271 |
} |
272 |
} |