Bug 60798 - Nested Jar entry could not be read twice consecutively
Summary: Nested Jar entry could not be read twice consecutively
Status: RESOLVED FIXED
Alias: None
Product: Tomcat 8
Classification: Unclassified
Component: Jasper (show other bugs)
Version: 8.5.11
Hardware: PC Linux
: P2 regression (vote)
Target Milestone: ----
Assignee: Tomcat Developers Mailing List
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2017-03-01 22:38 UTC by Charles-Edouard Poisnel
Modified: 2017-03-03 12:08 UTC (History)
1 user (show)



Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Charles-Edouard Poisnel 2017-03-01 22:38:03 UTC
We are using fat war packaging for one of our webapps. There are JSP tags (/META-INF/tags/**/*.tag), inside required jars (/WEB-INF/lib/*.jar).

During JSP compilation, when calling a jar entry (a tag inside a nested jar) this entry is called twice, with same name, but the InputStream is not at same position.

# Explanation

1. JSP compilation of a JSP: This JSP references tld (in lib-tld.jar), and this tld uses a tag (standard syntax) :

Ex:
<tag-file>
   <name>autocomplete</name>
   <path>/META-INF/tags/autocomplete/autocomplete.tag</path>
</tag-file>


2. The tag is loaded one first time, to determine syntax and encoding (org.apache.jasper.compiler.ParserController#determineSyntaxAndEncoding).

It calls:

org.apache.jasper.compiler.JspUtil#getInputStream -> jar.getInputStream(jarEntryName);


3. The tag is loaded a second time to parse content, but the return value is an InputStream at a different position (called by ParseController#doParse)

4. Tag is not properly parsed (no attributes) and JSP does not compile.


# Cause

org.apache.tomcat.util.scan.AbstractInputStreamJar


>    private void gotoEntry(String name) throws IOException {
>        if (entry != null && name.equals(entry.getName())) {
>            return;
>        }
>        reset();
>        JarEntry jarEntry = jarInputStream.getNextJarEntry();
>        while (jarEntry != null) {
>            if (name.equals(jarEntry.getName())) {
>                entry = jarEntry;
>                break;
>            }
>            jarEntry = jarInputStream.getNextJarEntry();
>        }
>    }

When calling the same entry twice consecutively, entry is not null and parameter name is same as entry.getName(), it loads the same attribute jarInputStream (org.apache.tomcat.util.scan.AbstractInputStreamJar#getInputStream)

I've patched the class AbstractInputStreamJar and removed the first three lines of gotoEntry (reset unconditionnally), and it solved this problem.

# Workaround

It's not reproducible if the war is unpacked (no problem with JarFileUrlJar)
For information, this behavior does not seem to be reproducible with this revision:  http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/scan/JarFileUrlNestedJar.java?view=markup&pathrev=1742245#l76

Regards,
Comment 1 Charles-Edouard Poisnel 2017-03-01 22:40:40 UTC
Note: tomcat-embed-core-8.5.11 is used.
Comment 2 Mark Thomas 2017-03-03 12:08:29 UTC
Thanks for the report. I created a simple test that confirmed the issue and I have fixed the root cause.

Fixed in:
- trunk for 9.0.0.M18 onwards
- 8.5.x for 8.5.12 onwards
- 8.0.x for 8.0.42 onwards