8009650: HttpClient available() check throws SocketException when connection has been closed
Reviewed-by: chegar, khazra, dsamersoff
Contributed-by: sdouglas@redhat.com
--- 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();
+ }
+}