8009650: HttpClient available() check throws SocketException when connection has been closed
authorrobm
Thu, 14 Mar 2013 00:21:34 +0000
changeset 16477 15ee12718efe
parent 16476 e269be167fae
child 16478 52ea0de470fd
8009650: HttpClient available() check throws SocketException when connection has been closed Reviewed-by: chegar, khazra, dsamersoff Contributed-by: sdouglas@redhat.com
jdk/src/share/classes/sun/net/www/http/HttpClient.java
jdk/test/sun/net/www/http/HttpClient/IsAvailable.java
--- a/jdk/src/share/classes/sun/net/www/http/HttpClient.java	Wed Mar 13 14:50:40 2013 -0700
+++ b/jdk/src/share/classes/sun/net/www/http/HttpClient.java	Thu Mar 14 00:21:34 2013 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -121,7 +121,14 @@
     public boolean reuse = false;
 
     // Traffic capture tool, if configured. See HttpCapture class for info
-     private HttpCapture capture = null;
+    private HttpCapture capture = null;
+
+    private static final PlatformLogger logger = HttpURLConnection.getHttpLogger();
+    private static void logFinest(String msg) {
+        if (logger.isLoggable(PlatformLogger.FINEST)) {
+            logger.finest(msg);
+        }
+    }
 
     /**
      * A NOP method kept for backwards binary compatibility
@@ -266,8 +273,11 @@
             if (ret != null && httpuc != null &&
                 httpuc.streaming() &&
                 httpuc.getRequestMethod() == "POST") {
-                if (!ret.available())
+                if (!ret.available()) {
+                    ret.inCache = false;
+                    ret.closeServer();
                     ret = null;
+                }
             }
 
             if (ret != null) {
@@ -279,10 +289,7 @@
                         ret.inCache = false;
                         if (httpuc != null && ret.needsTunneling())
                             httpuc.setTunnelState(TUNNELING);
-                        PlatformLogger logger = HttpURLConnection.getHttpLogger();
-                        if (logger.isLoggable(PlatformLogger.FINEST)) {
-                            logger.finest("KeepAlive stream retrieved from the cache, " + ret);
-                        }
+                        logFinest("KeepAlive stream retrieved from the cache, " + ret);
                     }
                 } else {
                     // We cannot return this connection to the cache as it's
@@ -360,30 +367,33 @@
         }
     }
 
-    protected synchronized boolean available() throws IOException {
+    protected synchronized boolean available() {
         boolean available = true;
-        int old = serverSocket.getSoTimeout();
-        serverSocket.setSoTimeout(1);
-        BufferedInputStream tmpbuf =
-            new BufferedInputStream(serverSocket.getInputStream());
+        int old = -1;
 
-        PlatformLogger logger = HttpURLConnection.getHttpLogger();
         try {
-            int r = tmpbuf.read();
-            if (r == -1) {
-                if (logger.isLoggable(PlatformLogger.FINEST)) {
-                    logger.finest("HttpClient.available(): " +
-                        "read returned -1: not available");
+            try {
+                old = serverSocket.getSoTimeout();
+                serverSocket.setSoTimeout(1);
+                BufferedInputStream tmpbuf =
+                        new BufferedInputStream(serverSocket.getInputStream());
+                int r = tmpbuf.read();
+                if (r == -1) {
+                    logFinest("HttpClient.available(): " +
+                            "read returned -1: not available");
+                    available = false;
                 }
-                available = false;
+            } catch (SocketTimeoutException e) {
+                logFinest("HttpClient.available(): " +
+                        "SocketTimeout: its available");
+            } finally {
+                if (old != -1)
+                    serverSocket.setSoTimeout(old);
             }
-        } catch (SocketTimeoutException e) {
-            if (logger.isLoggable(PlatformLogger.FINEST)) {
-                logger.finest("HttpClient.available(): " +
-                    "SocketTimeout: its available");
-            }
-        } finally {
-            serverSocket.setSoTimeout(old);
+        } catch (IOException e) {
+            logFinest("HttpClient.available(): " +
+                        "SocketException: not available");
+            available = false;
         }
         return available;
     }
@@ -865,10 +875,7 @@
 
             if (isKeepingAlive())   {
                 // Wrap KeepAliveStream if keep alive is enabled.
-                PlatformLogger logger = HttpURLConnection.getHttpLogger();
-                if (logger.isLoggable(PlatformLogger.FINEST)) {
-                    logger.finest("KeepAlive stream used: " + url);
-                }
+                logFinest("KeepAlive stream used: " + url);
                 serverInput = new KeepAliveStream(serverInput, pi, cl, this);
                 failedOnce = false;
             }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/net/www/http/HttpClient/IsAvailable.java	Thu Mar 14 00:21:34 2013 +0000
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8009650
+ * @summary HttpClient available() check throws SocketException when connection
+ * has been closed
+ */
+
+import java.net.URL;
+import java.net.ServerSocket;
+import sun.net.www.http.HttpClient;
+import java.security.*;
+import java.lang.reflect.Method;
+
+public class IsAvailable {
+
+    public static void main(String[] args) throws Exception {
+        int readTimeout = 20;
+        ServerSocket ss = new ServerSocket(0);
+
+        URL url1 = new URL("http://localhost:" + ss.getLocalPort());
+        HttpClient c1 = HttpClient.New(url1);
+
+        Method available = HttpClient.class.
+                getDeclaredMethod("available", null);
+        available.setAccessible(true);
+
+        c1.setReadTimeout(readTimeout);
+        boolean a = (boolean) available.invoke(c1);
+        if (!a) {
+            throw new RuntimeException("connection should be available");
+        }
+        if (c1.getReadTimeout() != readTimeout) {
+            throw new RuntimeException("read timeout has been altered");
+        }
+
+        c1.closeServer();
+
+        a = (boolean) available.invoke(c1);
+        if (a) {
+            throw new RuntimeException("connection shouldn't be available");
+        }
+
+        ss.close();
+    }
+}