JDK-6947916 : JarURLConnection does not handle useCaches correctly
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.net
  • Affected Version: 6u19
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2010-04-28
  • Updated: 2017-11-29
  • Resolved: 2016-09-28
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 7 JDK 8 JDK 9
7u131Fixed 8u152Fixed 9Fixed
Related Reports
Duplicate :  
Relates :  
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.6.0_19"
Java(TM) SE Runtime Environment (build 1.6.0_19-b04)
Java HotSpot(TM) Client VM (build 16.2-b04, mixed mode, sharing)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP [Version 5.1.2600]

A DESCRIPTION OF THE PROBLEM :
When opening URLConnections to multiple files contained in a single jar file, the backing JarFile object can be shared between the different URLConnections depending on the useCaches property.

sun.net.www.protocol.jar.JarURLConnection manages this property incorrectly though. It delegates getUseCaches and setUseCaches to another URLConnection which represents the connection to the underlying jar file. In its implementation of connect it first creates a JarFile object based on the current value of getUseCaches. When this is true, multiple connections to resources in the same jar file will reuse the same JarFile instance. Immediately after obtaining the JarFile instance, connect recreates the URLConnection to the jar file. When this happens, the new URLConnection does not take over the current useCaches value though. Instead it uses the current value of URLConnection#getDefaultUseCaches. The net effect of this is that JarURLConnection#getUseCaches can return true before calling connect and false after calling connect.
When an inputstream is then obtained from the JarURLConnection and it is subsequently closed, the inputstream will think that caching is not being used and close the underlying JarFile. In practice the JarFile can be in use by multiple inputstreams, causing an exception when operations are attempted on the other inputstreams.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the included test application.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The application runs without any errors.
ACTUAL -
The second inputstream reports that its underlying zip file has already been closed.

ERROR MESSAGES/STACK TRACES THAT OCCUR :
Exception in thread "main" java.lang.IllegalStateException: zip file closed
	at java.util.zip.ZipFile.ensureOpen(ZipFile.java:403)
	at java.util.zip.ZipFile.getInputStream(ZipFile.java:194)
	at java.util.zip.ZipFile.getInputStream(ZipFile.java:180)
	at java.util.jar.JarFile.getInputStream(JarFile.java:385)
	at sun.net.www.protocol.jar.JarURLConnection.getInputStream(JarURLConnection.java:144)
	at Test.main(Test.java:22)

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;

public class Test {
  public static void main( String[] args ) throws IOException {
    ClassLoader classloader = Test.class.getClassLoader();

    URL url = classloader.getResource( "java/lang/Object.class" );

    JarURLConnection c1 = (JarURLConnection)url.openConnection();
    c1.setDefaultUseCaches( false );
    c1.setUseCaches( true );
    c1.connect();

    JarURLConnection c2 = (JarURLConnection)url.openConnection();
    c2.setDefaultUseCaches( false );
    c2.setUseCaches( true );
    c2.connect();

    c1.getInputStream().close();
    c2.getInputStream().read();
  }
}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Always ensure setUseCaches and setDefaultUseCaches are set to the same value. This is a workaround for some cases, however since setDefaultUseCaches manipulates a static field, the workaround will not work consistently in multi-threaded applications.

Comments
This issue was resolved in jdk-9+137, it cannot be re-used. Best to resolve it again and open a new issue if there is another failure in this area.
28-09-2016

This test fails to remove the jar file, usecache.jar, at the end of the test.
27-09-2016

EVALUATION The description seems accurate.
29-06-2010