View | Details | Raw Unified | Return to bug 60963
Collapse All | Expand All

(-)a/java/org/apache/catalina/webresources/AbstractArchiveResourceSet.java (-1 / +1 lines)
Lines 179-185 public abstract class AbstractArchiveResourceSet extends AbstractResourceSet { Link Here
179
     * @return The archives entries mapped to their names or null if
178
     * @return The archives entries mapped to their names or null if
180
     *         {@link #getArchiveEntry(String)} should be used.
179
     *         {@link #getArchiveEntry(String)} should be used.
181
     */
180
     */
182
    protected abstract HashMap<String,JarEntry> getArchiveEntries(boolean single);
181
    protected abstract Map<String,JarEntry> getArchiveEntries(boolean single);
183
182
184
183
185
    /**
184
    /**
(-)a/java/org/apache/catalina/webresources/AbstractSingleArchiveResourceSet.java (-1 / +2 lines)
Lines 21-26 import java.io.IOException; Link Here
21
import java.net.MalformedURLException;
21
import java.net.MalformedURLException;
22
import java.util.Enumeration;
22
import java.util.Enumeration;
23
import java.util.HashMap;
23
import java.util.HashMap;
24
import java.util.Map;
24
import java.util.jar.JarEntry;
25
import java.util.jar.JarEntry;
25
import java.util.jar.JarFile;
26
import java.util.jar.JarFile;
26
27
Lines 59-65 public abstract class AbstractSingleArchiveResourceSet extends AbstractArchiveRe Link Here
59
60
60
61
61
    @Override
62
    @Override
62
    protected HashMap<String,JarEntry> getArchiveEntries(boolean single) {
63
    protected Map<String,JarEntry> getArchiveEntries(boolean single) {
63
        synchronized (archiveLock) {
64
        synchronized (archiveLock) {
64
            if (archiveEntries == null && !single) {
65
            if (archiveEntries == null && !single) {
65
                JarFile jarFile = null;
66
                JarFile jarFile = null;
(-)a/java/org/apache/catalina/webresources/JarWarResource.java (-27 / +14 lines)
Lines 21-26 import java.io.InputStream; Link Here
21
import java.util.jar.JarEntry;
21
import java.util.jar.JarEntry;
22
import java.util.jar.JarFile;
22
import java.util.jar.JarFile;
23
import java.util.jar.JarInputStream;
23
import java.util.jar.JarInputStream;
24
import java.util.zip.ZipInputStream;
25
import java.util.zip.ZipEntry;
24
26
25
import org.apache.juli.logging.Log;
27
import org.apache.juli.logging.Log;
26
import org.apache.juli.logging.LogFactory;
28
import org.apache.juli.logging.LogFactory;
Lines 47-72 public class JarWarResource extends AbstractArchiveResource { Link Here
47
49
48
    @Override
50
    @Override
49
    protected JarInputStreamWrapper getJarInputStreamWrapper() {
51
    protected JarInputStreamWrapper getJarInputStreamWrapper() {
50
        JarFile warFile = null;
51
        JarInputStream jarIs = null;
52
        JarEntry entry = null;
53
        try {
52
        try {
54
            warFile = getArchiveResourceSet().openJarFile();
53
            JarEntry entry = getArchiveResourceSet().getArchiveEntries(false).get(getResource().getName());
55
            JarEntry jarFileInWar = warFile.getJarEntry(archivePath);
56
            InputStream isInWar = warFile.getInputStream(jarFileInWar);
57
58
            jarIs = new JarInputStream(isInWar);
59
            entry = jarIs.getNextJarEntry();
60
            while (entry != null &&
61
                    !entry.getName().equals(getResource().getName())) {
62
                entry = jarIs.getNextJarEntry();
63
            }
64
65
            if (entry == null) {
54
            if (entry == null) {
66
                return null;
55
                return null;
67
            }
56
            }
68
57
69
            return new JarInputStreamWrapper(entry, jarIs);
58
            JarFile warFile = getArchiveResourceSet().openJarFile();
59
            JarEntry jarFileInWar = warFile.getJarEntry(archivePath);
60
61
            Long skipPos = ((JarWarResourceSet)getArchiveResourceSet()).getArchiveEntryPositions().get(getResource().getName());
62
            InputStream isInWar = warFile.getInputStream(jarFileInWar);
63
            isInWar.skip(skipPos);
64
65
            /* entry exists and was alread verified */
66
            ZipInputStream zipIs = new ZipInputStream(isInWar);
67
            ZipEntry ze = zipIs.getNextEntry();
68
            return new JarInputStreamWrapper(entry, zipIs);
70
        } catch (IOException e) {
69
        } catch (IOException e) {
71
            if (log.isDebugEnabled()) {
70
            if (log.isDebugEnabled()) {
72
                log.debug(sm.getString("jarResource.getInputStreamFail",
71
                log.debug(sm.getString("jarResource.getInputStreamFail",
Lines 74-91 public class JarWarResource extends AbstractArchiveResource { Link Here
74
            }
73
            }
75
            return null;
74
            return null;
76
        } finally {
75
        } finally {
77
            if (entry == null) {
78
                if (jarIs != null) {
79
                    try {
80
                        jarIs.close();
81
                    } catch (IOException ioe) {
82
                        // Ignore
83
                    }
84
                }
85
                if (warFile != null) {
86
                    getArchiveResourceSet().closeJarFile();
87
                }
88
            }
89
        }
76
        }
90
    }
77
    }
91
78
(-)a/java/org/apache/catalina/webresources/JarWarResourceSet.java (-12 / +113 lines)
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
}

Return to bug 60963