-
CSR
-
Resolution: Approved
-
P4
-
None
-
behavioral
-
minimal
-
-
Other
-
Implementation
Summary
Change the behavior of the TLS stack to pass through SocketException
instead of wrapping it into an SSLException.
Problem
OpenJDK 8 (up to 8u265 for OpenJDK and 8u251 for Oracle JDK), 9 and 10 imposed the following contract between the sun.security.ssl.SSLSocketImpl
class and its clients (see SSLSocketImpl.java#l69):
* ERROR HANDLING GUIDELINES
* (which exceptions to throw and catch and which not to throw and catch)
*
* . if there is an IOException (SocketException) when accessing the
* underlying Socket, pass it through
*
* . do not throw IOExceptions, throw SSLExceptions (or a subclass)
The TLS stack would pass through SocketException
s unchanged but would wrap other IOException
s into SSLException
s.
However, this contract was changed without notice in OpenJDK 11 by the new TLS1.3 stack JDK-8196584. The new implementation now started wrapping all IOException
s including SocketException
s into SSLException
s.
The error handling guidelines present in the OpenJDK implementations before 11 were used by the application layer to determine how to react to the exception. The application layer (e.g the popular Apache HTTPClient library) would consider SocketException
s to be retry-able and retry the request. Starting with JDK 11, such applications started seeing unhandled "SSLException: Broken Pipe
" exceptions because now SocketException
s were converted to SSLException
s. Apache HTTPClient for example reported this as "HTTPCLIENT-2032: Sometimes get a broken pipe error in Java 11..".
The general problem with the new implementation is that application are now unable to determine if a failure was due to a retry-able SocketException
or a more permanent SSLException
. The blast radius of this behavioural change became a lot wider after the new TLS 1.3 stack was downported to jdk 8.
"JDK-8214339: SSLSocketImpl erroneously wraps SocketException" attempted to fix this issue, however, it was still wrapping SocketException
s and passing them to the application layer as SSLException
s. Consequently, the new issue "JDK-8237578: JDK-8214339 (SSLSocketImpl wraps SocketException)" appears to not be fully fixed" was raised which was finally fixed for jdk 17 but unfortunately had to be backed out immediately because it had missed to update some tests. During the backout discussion the initial reviewers came to the conclusion that a CSR should have been raised for JDK-8237578. Finally, this CSR has been created for JDK-8259662 which is the redo of JDK-8237578.
Solution
- Change the implementation of
SSLSocketImpl
in the new TLS 1.3 stack back to the old error handling protocol defined in JDK 8 (see PR-2057). - Add a comment back to
SSLSocketImpl
class which documents this behaviour:
/*
* ERROR HANDLING GUIDELINES
* (which exceptions to throw and catch and which not to throw and catch)
*
* - if there is an IOException (SocketException) when accessing the
* underlying Socket, pass it through
*
* - do not throw IOExceptions, throw SSLExceptions (or a subclass)
*/
Specification
No specification change.
- csr of
-
JDK-8259662 Don't wrap SocketExceptions into SSLExceptions in SSLSocketImpl
-
- Resolved
-
-
JDK-8263435 Don't wrap SocketExceptions into SSLExceptions in SSLSocketImpl
-
- Resolved
-
-
JDK-8264627 Don't wrap SocketExceptions into SSLExceptions in SSLSocketImpl
-
- Resolved
-