JDK-6549146 : Java resource cache is corrupt
  • Type: Bug
  • Component: deploy
  • Sub-Component: deployment_toolkit
  • Affected Version: 6u1
  • Priority: P2
  • Status: Closed
  • Resolution: Duplicate
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2007-04-23
  • Updated: 2010-05-09
  • Resolved: 2007-05-01
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 6
6u2Resolved
Related Reports
Duplicate :  
Description
The customer's applet runs fine the first time, or if caching is disabled. When
it tries to read a video file (via JMF), through the cache, the data is corrupt.

To reproduce this problem:
goto:

http://smartscienceusa.com/smartscienceserver/servlet/ChooseUser?ORG=DemoMix

Select "Tony Wyant - Science Lab Sample"

Select "Tony Wyant" as the user, and enter "potato35" as the password.

Select the "titration" activity example,

Then click on the "Lab" activity.

Click "View Experiment".

The first time, or uncached times, a video window will play the experiment.
Once it is cached, there are several errors on the Java Console. (can be seen
by clicking the "View Experiment" button again.

Comments
EVALUATION after discussion with networking team, the problem is in the networking code, see bug: 6550798: Using InputStream.skip with ResponseCache will cause partial data to be cached also, it is suggested that it would be safer and simpler to assume that ResponseCache.put() always puts the entire resource because that is how it is documented to behave. closing this bug as duplicate of 6550798
01-05-2007

WORK AROUND Call URLConnection.setDefaultUseCaches(false) before creating the URLConnection instance. This can be done from the Applet itself and has no dependency on the server headers. So the Applet could be modified to look something like: URLConnection.setDefaultUseCaches(false); <call to jmf code with URL> URLConnection.setDefaultUseCaches(true); Of course no content will be cached until the jmf code returns and setDefaultUseCaches(true) is called.
27-04-2007

WORK AROUND The workaround for this problem is in the applet code, if they can set the "cache-control: no-store, no-cache" http header for the movie url request, then the movie file won't be cached at all by java plug-in, and will not run into this problem. Not sure if they can do this, depends on whether jmf code or the applet code is actually making the url connection. Another workaround is in the applet code, they read in the movie file once first, so plugin can create a good cache entry for it (to bypass the InputStream.skip calls made in the jmf code). Then when the jmf code tries to load the movie, it will be loaded from the good cache entry. This is what they need to load the movie first, before calling into jmf code: URL u = new URL("http://foo.com/foo.mov"); URLConnection conn = u.openConnection(); InputStream is = null; try { byte[] buf = new byte[8192]; is = new BufferedInputStream(conn.getInputStream()); while (is.read(buf) != -1) { // this download the complete movie file } } finally { if (is != null) { // this calls into DeployCacheHandler.put, and store the cache entry is.close(); } } // now use their original jmf code to load/show the movie // there won't be extra download, as subsequent requests to http://foo.com/foo.mov will be returned from cache
25-04-2007

EVALUATION First, the problem occurs only on Java 6 because: 1. We now cache every resource loaded by applets, where as in Java 5, only certain file extensions are cached. In this case the file extension is ".mov", and it's not cached in Java 5. 2. We now implement the java.net.ResponseCache correctly. In Java 5, we only implement the ResponseCache.get method, and do the resource downloading ourselves. In Java 6, we implement both get and put method, so the actual downloading is done by the underlying networking code. For this applet, under Java 5, when a movie (.mov) gets loaded, everytime it will be downloaded from the network. Everything works. For Java 6, if cache is disabled, it works the same way as Java 5. When cache is enabled in Java 6, the movie file gets downloaded by the new plugin cache, however the downloaded movie file is corrupted. This is because in the jmf code, it uses InputStream.skip on the movie file serveral times (see com.sun.media.protocol.BasicPullSourceStream.seek), before actually reading in the complete file contents. When skip is used, when the responseCache write out the contents to the cache, the skipped bytes won't be downloaded, causing the movie file to be corrupted. The problem of using InputStream.skip and java.net.ResponseCache together can be reproduced even with a simple standalone java application. I will talk to the networking team and see if it's a bug in the networking code itself. Problem is sun.net.www.protocol.http.HttpURLConnection, inner class HttpInputStream, does not override the skip method. It will only write to the cache file on read, but skip is ignored. The corrupted cache problem can be fixed in the plugin code itself; in our cache handler, we can compare the content-length header of the file to the actual size of the file downloaded by the ResponseCache. If it does not match, we should not write into our cache. With this fix, the cache won't be corrupted anymore, because we won't cache the .mov file entry anymore. However, if the user tries to view the same movie again in the same applet session, the jmf code will go into a infinite loop: (launching new applet session works, as there is no more corrupted cache entry) java.lang.Exception: Stack trace at java.lang.Thread.dumpStack(Unknown Source) at sun.net.www.protocol.http.HttpURLConnection$HttpInputStream.skip(HttpURLConnection.java:2361) at com.sun.media.protocol.BasicPullSourceStream.skip(BasicPullSourceStream.java:307) at com.sun.media.protocol.BasicPullSourceStream.seek(BasicPullSourceStream.java:195) at com.sun.media.parser.video.QuicktimeParser$VideoTrack.doReadFrame(QuicktimeParser.java:2730) at com.sun.media.parser.video.QuicktimeParser$MediaTrack.readFrame(QuicktimeParser.java:2451) at com.sun.media.SourceThread.process(BasicSourceModule.java:664) at com.sun.media.util.LoopThread.run(LoopThread.java:135) I will work with Tony together on this to see why it is looping. Seems like it's just keep trying on skipping the same amount of bytes.
25-04-2007