JDK-6648001 : Cancelling HTTP authentication causes subsequent deadlocks
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.net
  • Affected Version: 6u10,7
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • OS: generic,windows_xp
  • CPU: generic,x86
  • Submitted: 2008-01-08
  • Updated: 2011-03-08
  • Resolved: 2011-03-08
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.
Other JDK 6 JDK 7
1.4.2_21Fixed 6u10Fixed 7 b89Fixed
Related Reports
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Description
During investigation of 6647956 (Browser authenticator not working correctly in new Java Plug-In) it was discovered that it is very easy to cause the HTTP authentication code in the core JRE to deadlock. The steps to reproduce the failure are as follows:

1. Install the JRE. This failure has been reproduced as far back as 1.4.2_16 and may even be reproducible in earlier JREs.
2. Use the Java Control Panel to enable the Java Console.
3. Navigate to the test case for 6647956 (http://j2se.east.sun.com/deployment/www/tests/1.6.0_10/6647956/).
4. Use the second link to open the test applet. (Do not navigate to the topmost link, and do not enter the username or password.)
5. Click "Cancel".
6. Click the browser's back button.
7. Navigate again to the applet.

The applet will fail to load because it is deadlocked waiting for a notification that will never arrive:

"thread applet-AuthApplet-2" prio=4 tid=0x0b3dd800 nid=0x3a8 in Object.wait() [0x0bbcf000..0x0bbcfb94]
   java.lang.Thread.State: WAITING (on object monitor)
	at java.lang.Object.wait(Native Method)
	- waiting on <0x03054848> (a java.util.HashMap)
	at java.lang.Object.wait(Object.java:485)
	at sun.net.www.protocol.http.AuthenticationInfo.requestIsInProgress(AuthenticationInfo.java:117)
	- locked <0x03054848> (a java.util.HashMap)
	at sun.net.www.protocol.http.AuthenticationInfo.getServerAuth(AuthenticationInfo.java:258)
	at sun.net.www.protocol.http.HttpURLConnection.getServerAuthentication(HttpURLConnection.java:1640)
	at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1087)
	- locked <0x02a12cf8> (a sun.net.www.protocol.http.HttpURLConnection)
	at AuthApplet.start(AuthApplet.java:20)
	at sun.plugin2.applet.Applet2Manager$AppletExecutionRunnable.run(Applet2Manager.java:1508)
	at java.lang.Thread.run(Thread.java:619)

It is incredible that such an obvious bug was not discovered until now. The fix should be applied and immediately backported to the latest update releases for all applicable release trains.

Comments
EVALUATION changeset: http://hg.openjdk.java.net/jdk7/tl/jdk/rev/69002275e0e2
06-04-2010

EVALUATION Yes, this is a bug. The suggested fix would work, except that it would remove all requests belonging to the current thread. Normally, there is only one request at a time per-thread, but because we provide a number of callback APIs (eg. Authenticator and ResponseCache), it is possible for multiple HTTP requests to occur re-entrantly. The plugin does actually use this capability (with the ResponseCache). We have another fix which also works, but by exposing the key used in the authentication cache outside of AuthenticationInfo, this allows all requests to be terminated correctly, inlcuding ones, that have no username/password returned.
09-01-2008

SUGGESTED FIX This fix was produced and tested against a 1.6.0_10 workspace but should be obviously applicable to earlier releases. The affected files are in the sun.net.www.protocol.http package. ------- AuthenticationInfo.java ------- *** //C/Users/kbr/forte4j/platform/intel-win/bin/util/tmp/sccs.000292 Mon Jan 7 20:36:51 2008 --- AuthenticationInfo.java Mon Jan 7 20:34:34 2008 *************** *** 9,16 **** --- 9,19 ---- import java.io.*; import java.net.*; + import java.util.ArrayList; import java.util.Hashtable; + import java.util.Iterator; import java.util.LinkedList; + import java.util.List; import java.util.ListIterator; import java.util.Enumeration; import java.util.HashMap; *************** *** 125,134 **** /* signal completion of an authentication (whether it succeeded or not) * so that other threads can continue. */ ! static private void requestCompleted (String key) { synchronized (requests) { ! boolean waspresent = requests.remove (key) != null; ! assert waspresent; requests.notifyAll(); } } --- 128,147 ---- /* signal completion of an authentication (whether it succeeded or not) * so that other threads can continue. */ ! static private void requestCompleted () { synchronized (requests) { ! // Remove any outstanding requests owned by the current thread ! List/*<String>*/ keys = new ArrayList(); ! Thread current = Thread.currentThread(); ! for (Iterator iter = requests.keySet().iterator(); iter.hasNext(); ) { ! String key = (String) iter.next(); ! if (requests.get(key) == current) { ! keys.add(key); ! } ! } ! for (Iterator iter = keys.iterator(); iter.hasNext(); ) { ! requests.remove(iter.next()); ! } requests.notifyAll(); } } *************** *** 314,325 **** endAuthRequest(); } ! void endAuthRequest () { if (!serializeAuth) { return; } synchronized (requests) { ! requestCompleted (cacheKey(true)); } } --- 327,338 ---- endAuthRequest(); } ! static void endAuthRequest () { if (!serializeAuth) { return; } synchronized (requests) { ! requestCompleted (); } } ------- HttpURLConnection.java ------- *** //C/Users/kbr/forte4j/platform/intel-win/bin/util/tmp/sccs.000292 Mon Jan 7 20:36:51 2008 --- HttpURLConnection.java Mon Jan 7 20:22:43 2008 *************** *** 1266,1277 **** } throw e; } finally { ! if (respCode == HTTP_PROXY_AUTH && proxyAuthentication != null) { ! proxyAuthentication.endAuthRequest(); ! } ! else if (respCode == HTTP_UNAUTHORIZED && serverAuthentication != null) { ! serverAuthentication.endAuthRequest(); ! } } } --- 1266,1273 ---- } throw e; } finally { ! // Notify other threads that our authentication requests are complete ! AuthenticationInfo.endAuthRequest(); } } *************** *** 1425,1433 **** statusLine + "\""); } } finally { ! if (respCode == HTTP_PROXY_AUTH && proxyAuthentication != null) { ! proxyAuthentication.endAuthRequest(); ! } } // restore original request headers --- 1421,1427 ---- statusLine + "\""); } } finally { ! AuthenticationInfo.endAuthRequest(); } // restore original request headers
08-01-2008