Prerequisites:
OS: Windows Server 2012 R2
Java: checked on both jdk1.8.0_162 jdk1.8.0_181
Tomcat: windows x64 builds checked on 9.0.12, 9.0.16, 9.0.17-dev
Valid SSL certificates
Content of file located at webapp/ROOT/1.txt: []
Tomcat's connector settings:
<Connector port="443"
protocol="org.apache.coyote.http11.Http11Nio2Protocol"
sslImplementationName="org.apache.tomcat.util.net.openssl.OpenSSLImplementation"
connectionTimeout="5000"
SSLEnabled="true"
scheme="https"
secure="true"
>
This configuration leads to 50% of the traffic to be rejected with
Connection resets. First socket connects and receives the service, but
every second is resetted.
Exactly this combination leads to connection resets:
protocol="org.apache.coyote.http11.Http11Nio2Protocol"
sslImplementationName="org.apache.tomcat.util.net.openssl.OpenSSLImplementation"
Configurations that work well without connection resets:
protocol="org.apache.coyote.http11.Http11Nio2Protocol"
sslImplementationName="org.apache.tomcat.util.net.jsse.JSSEImplementation"
or
protocol="org.apache.coyote.http11.Http11NioProtocol"
sslImplementationName="org.apache.tomcat.util.net.openssl.OpenSSLImplementation"
Java code to reproduce the connection resets (works well with any
other secure server):
(there is no resets if a variable named FIX__gotoSleepAfterHandshake = true)
public class CheckConnectionResets{
static String host = "your-test-host";
public static void main( String[] args ) throws
InterruptedException, IOException{
SSLSocketFactory factory =
(SSLSocketFactory)SSLSocketFactory.getDefault();
int nRuns = 4;
int success = 0;
int denial = 0;
boolean FIX__gotoSleepAfterHandshake = false;
for( int i = 0; i < nRuns; i++ ){
try ( SSLSocket socket = (SSLSocket)factory.createSocket(
host, 443 ) ){
if( FIX__gotoSleepAfterHandshake ){
socket.startHandshake();
Thread.sleep( 500 );
}
try ( PrintWriter out = new PrintWriter( new
BufferedWriter( new OutputStreamWriter( socket.getOutputStream() ) )
);
InputStream is = socket.getInputStream(); ){
out.println( "GET /1.txt HTTP/1.1" );
out.println( "Host: " + host );
out.println( "Accept: */*" );
out.println();
out.flush();
if( out.checkError() ){
System.out.println( "SSLSocketClient:
java.io.PrintWriter error" );
}
Instant start = Instant.now();
/* read full response */
byte[] buff = new byte[ 1024 ];
int read = is.read( buff );
success++;
System.out.println( "success: " + success + ",
read " + read + " bytes for: " + start.until( Instant.now(),
ChronoUnit.MILLIS ) + "ms" );
} catch ( IOException e ) {
denial++;
System.err.println( "denial: " + denial + ", " +
e.getMessage() );
}}}}}
Sample output:
success: 1, read 73 bytes for: 78ms
denial: 1, Connection reset
success: 2, read 73 bytes for: 78ms
denial: 2, Connection reset
The bug is stable, and always reproducible.
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]