JDK-6669543 : Applet updating CacheEntry causes AccessControlException
  • Type: Bug
  • Component: deploy
  • Sub-Component: plugin
  • Affected Version: 6u3
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2008-02-29
  • Updated: 2011-02-16
  • Resolved: 2009-02-17
Related Reports
Duplicate :  
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.6.0_03"
Java(TM) SE Runtime Environment (build 1.6.0_03-b05)
Java HotSpot(TM) Client VM (build 1.6.0_03-b05, mixed mode)

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

EXTRA RELEVANT SYSTEM CONFIGURATION :
Java Plug-in 1.6.0_03
Using JRE version 1.6.0_03 Java HotSpot(TM) Client VM

A DESCRIPTION OF THE PROBLEM :
I have a series of unsigned applets that load audio files from the host server; these were working normally, then I changed the webserver configuration to enable cache expiration headers for the files, for example:
  Cache-Control: max-age=15552000
  Expires: Thu, 31 Jul 2008 10:06:20 GMT

...and this change broke the applets.

When an applet tries to load an audio file, the DeployCacheHandler finds the cached version locally, but tries to write the expiration change to an index file -- this throws a security exception and the load fails.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Step 1:
Deploy the html file and applet below, and an audio file (any will work; rename to 0.au) in the same directory on the server.

Make sure your server is NOT using any cache expiration HTTP headers.

Run the applet in a browser; it should run with no errors.
Shut down the browser.

Step 2:
Change your HTTP servers configuration to return cache headers for the audio file, for example:
  ExpiresByType audio/basic "access plus 6 months"

Run the applet again.  You will get an exception when it accesses the (cached) audio file and attempts to update its cache expiration data.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The applet should run successfully both times, whether loading the au file from network or from cache, and whether or not the HTTP headers from the server have changed.
ACTUAL -
Opening the input stream fails with an AccessControlException (see below), and the file cannot be loaded from the cache.  The method causing the security exception is this:
  CacheEntry.updateExpirationInIndexFile()

ERROR MESSAGES/STACK TRACES THAT OCCUR :
network: Connecting http://test.emusictheory.com/0.au with proxy=DIRECT
url: http://test.emusictheory.com/0.au
trying input stream
network: Cache entry found [url: http://test.emusictheory.com/0.au, version: null]
network: Connecting http://test.emusictheory.com/0.au with proxy=DIRECT
network: ResponseCode for http://test.emusictheory.com/0.au : 304
network: Encoding for http://test.emusictheory.com/0.au : null
network: Disconnect connection to http://test.emusictheory.com/0.au
direct input stream failed:
java.security.AccessControlException: access denied (java.io.FilePermission C:\Documents and Settings\Rob\Application Data\Sun\Java\Deployment\cache\6.0\29\39cc1ddd-4b2e3269.idx read)
	at java.security.AccessControlContext.checkPermission(Unknown Source)
	at java.security.AccessController.checkPermission(Unknown Source)
	at java.lang.SecurityManager.checkPermission(Unknown Source)
	at java.lang.SecurityManager.checkRead(Unknown Source)
	at java.io.RandomAccessFile.<init>(Unknown Source)
	at com.sun.deploy.cache.CacheEntry.updateExpirationInIndexFile(Unknown Source)
	at com.sun.deploy.net.DownloadEngine.isUpdateAvailable(Unknown Source)
	at com.sun.deploy.cache.DeployCacheHandler.get(Unknown Source)
	at sun.net.www.protocol.http.HttpURLConnection.plainConnect(Unknown Source)
	at sun.net.www.protocol.http.HttpURLConnection.connect(Unknown Source)
	at sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source)
	at java.net.URL.openStream(Unknown Source)
	at CachedFileLoadTest.start(Unknown Source)
	at sun.applet.AppletPanel.run(Unknown Source)
	at java.lang.Thread.run(Unknown Source)

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
Apache configuration, step 1:
# no expires headers (default config)
ExpiresActive Off

Apache configuration, step 2:
# expires header for .au files:
ExpiresActive On
ExpiresByType audio/basic "access plus 6 months"

===========================

Applet  CachedFileTest.java

import java.applet.Applet;
import java.io.InputStream;
import java.net.URL;

public class CachedFileTest extends Applet {
	
	public void start() {
		URL url = getClass().getResource("0.au");
		System.out.println("url: " + url);

		try {
			System.out.println("trying input stream");
			InputStream is = url.openStream();
			is.read();
			is.close();
			System.out.println("direct stream succeeded");
		}
		catch( Throwable t ) {
			System.err.println("direct input stream failed:");
			t.printStackTrace();
		}
	}
}

===========================

HTML file for applet:

<applet code="CachedFileTest">
</applet>
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
My fix is to change the paths on the server for ALL loaded files used from all applets -- this will cause a cache miss (and the correct expiration will be written the first time, instead of requiring an update).

Users could also clear their caches from the Java Control Panel -- I think that would solve the problem per-user.

Loading audio files using Applet.getAudioFile() also succeeds (but is not a solution for me, since I need the bytes directly).

Comments
EVALUATION Should be fixed as part of 6791250. Please reopen if problem will be still reproducible with 6u14.
17-02-2009