8278067: Make HttpURLConnection default keep alive timeout configurable

Reviewed-by: dfuchs
This commit is contained in:
Michael McMahon 2022-02-16 16:01:01 +00:00
parent 7428b37696
commit d8f44aa39e
4 changed files with 261 additions and 13 deletions

View file

@ -176,6 +176,16 @@ of proxies.</P>
If HTTP keepalive is enabled (see above) this value determines the
maximum number of idle connections that will be simultaneously kept
alive, per destination.</P>
<LI><P><B>{@systemProperty http.keepAlive.time.server}</B> and
<B>{@systemProperty http.keepAlive.time.proxy}</B> </P>
<P>These properties modify the behavior of the HTTP keepalive cache in the case
where the server (or proxy) has not specified a keepalive time. If the
property is set in this case, then idle connections will be closed after the
specified number of seconds. If the property is set, and the server does
specify a keepalive time in a "Keep-Alive" response header, then the time specified
by the server is used. If the property is not set and also the server
does not specify a keepalive time, then connections are kept alive for an
implementation defined time, assuming {@code http.keepAlive} is {@code true}.</P>
<LI><P><B>{@systemProperty http.maxRedirects}</B> (default: {@code 20})<BR>
This integer value determines the maximum number, for a given request,
of HTTP redirects that will be automatically followed by the

View file

@ -122,13 +122,13 @@ public class HttpClient extends NetworkClient {
recomputing the value of keepingAlive */
int keepAliveConnections = -1; /* number of keep-alives left */
/**Idle timeout value, in milliseconds. Zero means infinity,
* iff keepingAlive=true.
* Unfortunately, we can't always believe this one. If I'm connected
* through a Netscape proxy to a server that sent me a keep-alive
* time of 15 sec, the proxy unilaterally terminates my connection
* after 5 sec. So we have to hard code our effective timeout to
* 4 sec for the case where we're using a proxy. *SIGH*
/*
* The timeout if specified by the server. Following values possible
* 0: the server specified no keep alive headers
* -1: the server provided "Connection: keep-alive" but did not specify a
* a particular time in a "Keep-Alive:" headers
* Positive values are the number of seconds specified by the server
* in a "Keep-Alive" header
*/
int keepAliveTimeout = 0;
@ -235,7 +235,6 @@ public class HttpClient extends NetworkClient {
return keepAliveProp;
}
public String getSpnegoCBT() {
return spnegoCBT;
}
@ -898,7 +897,7 @@ public class HttpClient extends NetworkClient {
responses.findValue("Keep-Alive"));
/* default should be larger in case of proxy */
keepAliveConnections = p.findInt("max", usingProxy?50:5);
keepAliveTimeout = p.findInt("timeout", usingProxy?60:5);
keepAliveTimeout = p.findInt("timeout", -1);
}
} else if (b[7] != '0') {
/*
@ -1151,6 +1150,10 @@ public class HttpClient extends NetworkClient {
}
}
public boolean getUsingProxy() {
return usingProxy;
}
/**
* @return the proxy port being used for this client. Meaningless
* if getProxyHostUsed() gives null.

View file

@ -41,6 +41,8 @@ import java.util.concurrent.locks.ReentrantLock;
import jdk.internal.misc.InnocuousThread;
import sun.security.action.GetIntegerAction;
import sun.net.www.protocol.http.HttpURLConnection;
import sun.util.logging.PlatformLogger;
/**
* A class that implements a cache of idle Http connections for keep-alive
@ -54,6 +56,32 @@ public class KeepAliveCache
@java.io.Serial
private static final long serialVersionUID = -2937172892064557949L;
// Keep alive time set according to priority specified here:
// 1. If server specifies a time with a Keep-Alive header
// 2. If user specifies a time with system property below
// 3. Default values which depend on proxy vs server and whether
// a Connection: keep-alive header was sent by server
// name suffixed with "server" or "proxy"
private static final String keepAliveProp = "http.keepAlive.time.";
private static final int userKeepAliveServer;
private static final int userKeepAliveProxy;
static final PlatformLogger logger = HttpURLConnection.getHttpLogger();
@SuppressWarnings("removal")
static int getUserKeepAliveSeconds(String type) {
int v = AccessController.doPrivileged(
new GetIntegerAction(keepAliveProp+type, -1)).intValue();
return v < -1 ? -1 : v;
}
static {
userKeepAliveServer = getUserKeepAliveSeconds("server");
userKeepAliveProxy = getUserKeepAliveSeconds("proxy");
}
/* maximum # keep-alive connections to maintain at once
* This should be 2 by the HTTP spec, but because we don't support pipe-lining
* a larger value is more appropriate. So we now set a default of 5, and the value
@ -127,10 +155,29 @@ public class KeepAliveCache
if (v == null) {
int keepAliveTimeout = http.getKeepAliveTimeout();
v = new ClientVector(keepAliveTimeout > 0 ?
keepAliveTimeout * 1000 : LIFETIME);
v.put(http);
super.put(key, v);
if (keepAliveTimeout == 0) {
keepAliveTimeout = getUserKeepAlive(http.getUsingProxy());
if (keepAliveTimeout == -1) {
// same default for server and proxy
keepAliveTimeout = 5;
}
} else if (keepAliveTimeout == -1) {
keepAliveTimeout = getUserKeepAlive(http.getUsingProxy());
if (keepAliveTimeout == -1) {
// different default for server and proxy
keepAliveTimeout = http.getUsingProxy() ? 60 : 5;
}
}
// at this point keepAliveTimeout is the number of seconds to keep
// alive, which could be 0, if the user specified 0 for the property
assert keepAliveTimeout >= 0;
if (keepAliveTimeout == 0) {
http.closeServer();
} else {
v = new ClientVector(keepAliveTimeout * 1000);
v.put(http);
super.put(key, v);
}
} else {
v.put(http);
}
@ -139,6 +186,11 @@ public class KeepAliveCache
}
}
// returns the keep alive set by user in system property or -1 if not set
private static int getUserKeepAlive(boolean isProxy) {
return isProxy ? userKeepAliveProxy : userKeepAliveServer;
}
/* remove an obsolete HttpClient from its VectorCache */
public void remove(HttpClient h, Object obj) {
cacheLock.lock();
@ -277,6 +329,11 @@ class ClientVector extends ArrayDeque<KeepAliveEntry> {
e.hc.closeServer();
} else {
hc = e.hc;
if (KeepAliveCache.logger.isLoggable(PlatformLogger.Level.FINEST)) {
String msg = "cached HttpClient was idle for "
+ Long.toString(currentTime - e.idleStartTime);
KeepAliveCache.logger.finest(msg);
}
}
} while ((hc == null) && (!isEmpty()));
return hc;