JDK-8166541 : HTTPS requests with invalid proxy information do not use keep-alive
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.net
  • Affected Version: 7u40,8u20
  • Priority: P3
  • Status: Open
  • Resolution: Unresolved
  • OS: windows_7
  • CPU: x86_64
  • Submitted: 2015-10-02
  • Updated: 2021-08-04
Related Reports
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.8.0_60"
Java(TM) SE Runtime Environment (build 1.8.0_60-b27)
Java HotSpot(TM) 64-Bit Server VM (build 25.60-b23, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 6.1.7601]

A DESCRIPTION OF THE PROBLEM :
When making HTTPS requests to a web server which is configured with Keep-Alive: timeout=45, if the proxy information is invalid (non-existent proxy server and port), each request will result in a new socket being created resulting in slower performance (including SSL handshaking, etc).

In older Java versions like 1.7.0_17, in the same scenario, the code will respect the Keep-Alive setting from the web server, and reuse the same socket across multiple requests, and the time taken for each request after the first one is much faster.

Not sure if this is incorrect behavior or not, but it is a change in the behavior, in a negative way.

The earliest java versions which I tested that has this problem are Java 1.7.0_40 and above and in Java 1.8.0_20 and above.  I tested those two versions, and several other later versions, including the latest ones.

This problem does not occur in Java 1.7.0_17.

This problem may be related to a similar issue with HTTPS connection + Proxy + keep-alive which was reported and patched in the latest Java versions.  That problem started at the same java versions as this one, and had the same problem, but was specific to using a valid NTLM proxy server.

That problem was resolved, but this issue still remains.

Related links:

Oracle SR# SR 3-9925092909 : HTTP Tunnel connections to NTLM proxy reauthenticates instead of using keep-alive

https://bugs.openjdk.java.net/browse/JDK-8065994 (Linked to the SR)

https://bugs.openjdk.java.net/browse/JDK-8059444 (Duplicate)



ADDITIONAL REGRESSION INFORMATION: 
Works correctly in Java 1.7.0_17:

java version "1.7.0_17"
Java(TM) SE Runtime Environment (build 1.7.0_17-b02)
Java HotSpot(TM) Client VM (build 23.7-b01, mixed mode)

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Specify a nonexistent https.proxyHost and https.proxyPort, then use URLConnection.connect() and get the response code and inputStream.  Then call getInputStream().close().  Repeat this multiple times with a delay of 1 second to a web server which has keep-alive configured to 45 seconds, using HTTPS.

Time each request, and grab the socket from the HttpsURLConnection (via reflection), and check if the local port has changed from the previous one.  That tells you if a new socket is created.  You can also use wireshark to see if new sockets are created or not.



EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The initial request should take some time (seconds), but subsequent requests should be very fast (milliseconds).  The local port number for the socket in the HttpsURLConnection should not change between requests.  Wireshark should show that the same socket is being used to send multiple requests.
ACTUAL -
All request are taking a long time (seconds).  The local port number for the socket in the HttpsURLConnection is changing between requests.  Wireshark shows that each request is using a new socket.

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
System.setProperty("https.proxyHost", "dummy");
System.setProperty("https.proxyPort", "99999");

		for (int i = 0; i < num; i++) {
			Long startTime = System.currentTimeMillis();

			URLConnection urlConnection = url.openConnection();

			urlConnection.setUseCaches(false);
			urlConnection.setAllowUserInteraction(false);
			urlConnection.setRequestProperty("Cache-Control", "no-cache");
			urlConnection.setRequestProperty("accept", "*");

			urlConnection.connect();

			// After making the connection, check the local port number to see
			// if we are using keepalive or creating new sockets...
			Socket newSocket = null;
			if (urlConnection instanceof HttpsURLConnection) {
				newSocket = extractHttpsSock((HttpsURLConnection) urlConnection);
			} else if (urlConnection instanceof HttpURLConnection) {
				newSocket = extractHttpSock((HttpURLConnection) urlConnection);
			}

			if (newSocket.getLocalPort() != currentPort) {
				currentPort = newSocket.getLocalPort();
				localPortCount++;
			}

			HttpURLConnection conn = (HttpURLConnection) urlConnection;

			try {
				conn.getResponseCode();
				conn.getInputStream();
			} catch (IOException e) {
				conn.getResponseCode();
				conn.getErrorStream();
			}

			conn.getInputStream().close();
			
			LOGGER.info("\nRequest duration (ms): " + (System.currentTimeMillis() - startTime) + ".  Local port creation count: " + localPortCount + "");
			LOGGER.info("-----------------------");

			// Sleep between requests
			Thread.sleep(delay * 1000);
		}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Make sure invalid proxy settings are not used.