8163520: Reuse cache entries
authordfuchs
Thu, 20 Oct 2016 15:10:52 +0100
changeset 44753 37d4270a2a8d
parent 44752 97a2817b5a9b
child 44754 cc5c1fb080a3
8163520: Reuse cache entries Reviewed-by: chegar, michaelm, weijun, aefimov, ahgross
jdk/src/java.base/share/classes/sun/net/www/http/HttpClient.java
jdk/src/java.base/share/classes/sun/net/www/protocol/http/AuthenticationInfo.java
jdk/src/java.base/unix/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java
jdk/src/java.base/windows/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java
--- a/jdk/src/java.base/share/classes/sun/net/www/http/HttpClient.java	Mon Oct 03 19:55:49 2016 +0300
+++ b/jdk/src/java.base/share/classes/sun/net/www/http/HttpClient.java	Thu Oct 20 15:10:52 2016 +0100
@@ -102,7 +102,15 @@
     // from previous releases.
     private static boolean retryPostProp = true;
 
+    /* Value of the system property jdk.ntlm.cache;
+       if false, then NTLM connections will not be cached.
+       The default value is 'true'. */
+    private static final boolean cacheNTLMProp;
+
     volatile boolean keepingAlive;    /* this is a keep-alive connection */
+    volatile boolean disableKeepAlive;/* keep-alive has been disabled for this
+                                         connection - this will be used when
+                                         recomputing the value of keepingAlive */
     int keepAliveConnections = -1;    /* number of keep-alives left */
 
     /**Idle timeout value, in milliseconds. Zero means infinity,
@@ -152,6 +160,7 @@
         Properties props = GetPropertyAction.privilegedGetProperties();
         String keepAlive = props.getProperty("http.keepAlive");
         String retryPost = props.getProperty("sun.net.http.retryPost");
+        String cacheNTLM = props.getProperty("jdk.ntlm.cache");
 
         if (keepAlive != null) {
             keepAliveProp = Boolean.parseBoolean(keepAlive);
@@ -161,8 +170,15 @@
 
         if (retryPost != null) {
             retryPostProp = Boolean.parseBoolean(retryPost);
-        } else
+        } else {
             retryPostProp = true;
+        }
+
+        if (cacheNTLM != null) {
+            cacheNTLMProp = Boolean.parseBoolean(cacheNTLM);
+        } else {
+            cacheNTLMProp = true;
+        }
 
     }
 
@@ -723,6 +739,7 @@
                 nread += r;
             }
             String keep=null;
+            String authenticate=null;
             ret = b[0] == 'H' && b[1] == 'T'
                     && b[2] == 'T' && b[3] == 'P' && b[4] == '/' &&
                 b[5] == '1' && b[6] == '.';
@@ -751,17 +768,37 @@
                  */
                 if (usingProxy) { // not likely a proxy will return this
                     keep = responses.findValue("Proxy-Connection");
+                    authenticate = responses.findValue("Proxy-Authenticate");
                 }
                 if (keep == null) {
                     keep = responses.findValue("Connection");
+                    authenticate = responses.findValue("WWW-Authenticate");
                 }
+
+                // 'disableKeepAlive' starts with the value false.
+                // It can transition from false to true, but once true
+                // it stays true.
+                // If cacheNTLMProp is false, and disableKeepAlive is false,
+                // then we need to examine the response headers to figure out
+                // whether we are doing NTLM authentication. If we do NTLM,
+                // and cacheNTLMProp is false, than we can't keep this connection
+                // alive: we will switch disableKeepAlive to true.
+                boolean canKeepAlive = !disableKeepAlive;
+                if (canKeepAlive && cacheNTLMProp == false && authenticate != null) {
+                    authenticate = authenticate.toLowerCase(Locale.US);
+                    canKeepAlive = !authenticate.startsWith("ntlm ");
+                }
+                disableKeepAlive |= !canKeepAlive;
+
                 if (keep != null && keep.toLowerCase(Locale.US).equals("keep-alive")) {
                     /* some servers, notably Apache1.1, send something like:
                      * "Keep-Alive: timeout=15, max=1" which we should respect.
                      */
-                    HeaderParser p = new HeaderParser(
+                    if (disableKeepAlive) {
+                        keepAliveConnections = 1;
+                    } else {
+                        HeaderParser p = new HeaderParser(
                             responses.findValue("Keep-Alive"));
-                    if (p != null) {
                         /* default should be larger in case of proxy */
                         keepAliveConnections = p.findInt("max", usingProxy?50:5);
                         keepAliveTimeout = p.findInt("timeout", usingProxy?60:5);
@@ -771,7 +808,7 @@
                      * We're talking 1.1 or later. Keep persistent until
                      * the server says to close.
                      */
-                    if (keep != null) {
+                    if (keep != null || disableKeepAlive) {
                         /*
                          * The only Connection token we understand is close.
                          * Paranoia: if there is any Connection header then
@@ -853,7 +890,7 @@
                 keepAliveConnections = 1;
                 keepingAlive = false;
             } else {
-                keepingAlive = true;
+                keepingAlive = !disableKeepAlive;
             }
             failedOnce = false;
         } else {
@@ -886,7 +923,7 @@
                 (cl >= 0 ||
                  code == HttpURLConnection.HTTP_NOT_MODIFIED ||
                  code == HttpURLConnection.HTTP_NO_CONTENT)) {
-                keepingAlive = true;
+                keepingAlive = !disableKeepAlive;
                 failedOnce = false;
             } else if (keepingAlive) {
                 /* Previously we were keeping alive, and now we're not.  Remove
--- a/jdk/src/java.base/share/classes/sun/net/www/protocol/http/AuthenticationInfo.java	Mon Oct 03 19:55:49 2016 +0300
+++ b/jdk/src/java.base/share/classes/sun/net/www/protocol/http/AuthenticationInfo.java	Thu Oct 20 15:10:52 2016 +0100
@@ -65,8 +65,7 @@
      * repeatedly, via the Authenticator. Default is false, which means that this
      * behavior is switched off.
      */
-    static boolean serializeAuth;
-
+    static final boolean serializeAuth;
     static {
         serializeAuth = java.security.AccessController.doPrivileged(
             new sun.security.action.GetBooleanAction(
@@ -106,6 +105,16 @@
     public String getProtocolScheme() {
         return protocol;
     }
+    /**
+     * Whether we should cache this instance in the AuthCache.
+     * This method returns {@code true} by default.
+     * Subclasses may override this method to add
+     * additional restrictions.
+     * @return {@code true} by default.
+     */
+    protected boolean useAuthCache() {
+        return true;
+    }
 
     /**
      * requests is used to ensure that interaction with the
@@ -373,9 +382,11 @@
      */
     void addToCache() {
         String key = cacheKey(true);
-        cache.put(key, this);
-        if (supportsPreemptiveAuthorization()) {
-            cache.put(cacheKey(false), this);
+        if (useAuthCache()) {
+            cache.put(key, this);
+            if (supportsPreemptiveAuthorization()) {
+                cache.put(cacheKey(false), this);
+            }
         }
         endAuthRequest(key);
     }
--- a/jdk/src/java.base/unix/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java	Mon Oct 03 19:55:49 2016 +0300
+++ b/jdk/src/java.base/unix/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java	Thu Oct 20 15:10:52 2016 +0100
@@ -35,6 +35,7 @@
 import java.security.GeneralSecurityException;
 import java.util.Base64;
 import java.util.Objects;
+import java.util.Properties;
 
 import sun.net.www.HeaderParser;
 import sun.net.www.protocol.http.AuthenticationInfo;
@@ -76,8 +77,15 @@
 
     private String hostname;
     /* Domain to use if not specified by user */
-    private static String defaultDomain =
-            GetPropertyAction.privilegedGetProperty("http.auth.ntlm.domain", "");
+    private static final String defaultDomain;
+    /* Whether cache is enabled for NTLM */
+    private static final boolean ntlmCache;
+    static {
+        Properties props = GetPropertyAction.privilegedGetProperties();
+        defaultDomain = props.getProperty("http.auth.ntlm.domain", "");
+        String ntlmCacheProp = props.getProperty("jdk.ntlm.cache", "true");
+        ntlmCache = Boolean.parseBoolean(ntlmCacheProp);
+    }
 
     public static boolean supportsTransparentAuth () {
         return false;
@@ -171,6 +179,11 @@
         init (pw);
     }
 
+    @Override
+    protected boolean useAuthCache() {
+        return ntlmCache && super.useAuthCache();
+    }
+
     /**
      * @return true if this authentication supports preemptive authorization
      */
--- a/jdk/src/java.base/windows/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java	Mon Oct 03 19:55:49 2016 +0300
+++ b/jdk/src/java.base/windows/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java	Thu Oct 20 15:10:52 2016 +0100
@@ -31,6 +31,7 @@
 import java.net.UnknownHostException;
 import java.net.URL;
 import java.util.Objects;
+import java.util.Properties;
 import sun.net.www.HeaderParser;
 import sun.net.www.protocol.http.AuthenticationInfo;
 import sun.net.www.protocol.http.AuthScheme;
@@ -51,12 +52,16 @@
         NTLMAuthenticationCallback.getNTLMAuthenticationCallback();
 
     private String hostname;
-    private static String defaultDomain; /* Domain to use if not specified by user */
-
+    /* Domain to use if not specified by user */
+    private static final String defaultDomain;
+    /* Whether cache is enabled for NTLM */
+    private static final boolean ntlmCache;
     static {
-        defaultDomain = GetPropertyAction
-                .privilegedGetProperty("http.auth.ntlm.domain", "domain");
-    };
+        Properties props = GetPropertyAction.privilegedGetProperties();
+        defaultDomain = props.getProperty("http.auth.ntlm.domain", "domain");
+        String ntlmCacheProp = props.getProperty("jdk.ntlm.cache", "true");
+        ntlmCache = Boolean.parseBoolean(ntlmCacheProp);
+    }
 
     private void init0() {
 
@@ -136,6 +141,11 @@
         init (pw);
     }
 
+    @Override
+    protected boolean useAuthCache() {
+        return ntlmCache && super.useAuthCache();
+    }
+
     /**
      * @return true if this authentication supports preemptive authorization
      */