Merge "Remove test runner tool vogar from Froyo." into froyo
diff --git a/libcore/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/http/HttpConfiguration.java b/libcore/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/http/HttpConfiguration.java
index 55d762d..905d9ab 100644
--- a/libcore/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/http/HttpConfiguration.java
+++ b/libcore/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/http/HttpConfiguration.java
@@ -30,7 +30,7 @@
* and host name (<code>String</code>) or all three, depending on whether or not a
* <code>Proxy</code> is used and the type of <code>Proxy</code> it is.
*
- * <code>HttpConfiguration</code> is used as a key by <code>HttpConnectionManager</code>
+ * <code>HttpConfiguration</code> is used as a key by <code>HttpConnectionPool</code>
* to retrieve <code>HttpConnection</code>s from its connection pool.
*/
public class HttpConfiguration {
diff --git a/libcore/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/http/HttpConnectionManager.java b/libcore/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/http/HttpConnectionManager.java
deleted file mode 100644
index 61d7cbe..0000000
--- a/libcore/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/http/HttpConnectionManager.java
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.harmony.luni.internal.net.www.protocol.http;
-
-import java.io.IOException;
-import java.net.Proxy;
-import java.net.URI;
-import java.security.AccessController;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.harmony.luni.util.PriviAction;
-
-/**
- * <code>HttpConnectionManager</code> manages a pool of <code>HttpConnection</code>s
- * that are not currently in use and is used to get hold of persistent <code>HttpConnection</code>s.
- * Clients should return an <code>HttpConnection</code> to the pool after use by calling
- * <code>returnConnectionToPool</code>
- *
- * Two system properties affect the behaviour of this class - <code>http.maxConnections</code>
- * and <code>http.keepAlive</code>. <code>http.keepAlive</code> determines whether
- * or not connections should be persisted and <code>http.maxConnections</code>
- * determines the maximum number of connections to each individual host that
- * should be kept in the pool.
- */
-public class HttpConnectionManager {
-
- // The maximum number of connections to any location
- private static int maxConnections = 5;
-
- // Keeps connections alive if true
- private static boolean keepAlive = true;
-
- private static HttpConnectionManager defaultConnectionManager;
- private ConnectionPool pool = new ConnectionPool();
-
- /**
- * Returns the default connection manager
- */
- public static HttpConnectionManager getDefault() {
- if(defaultConnectionManager == null) {
- defaultConnectionManager = new HttpConnectionManager();
- }
- return defaultConnectionManager;
- }
-
- public HttpConnection getConnection(URI uri, int connectTimeout) throws IOException {
- checkSystemProperties();
- HttpConfiguration config = new HttpConfiguration(uri);
- return pool.getHttpConnection(config, connectTimeout);
- }
-
- public HttpConnection getConnection(URI uri, Proxy proxy, int connectTimeout) throws IOException {
- checkSystemProperties();
- HttpConfiguration config = new HttpConfiguration(uri, proxy);
- return pool.getHttpConnection(config, connectTimeout);
- }
-
- public void returnConnectionToPool(HttpConnection connection) {
- checkSystemProperties();
- pool.returnConnection(connection);
- }
-
- public int numFreeConnections() {
- return pool.numFreeConnections();
- }
-
- private void checkSystemProperties() {
- String httpMaxConnections = AccessController.doPrivileged(new PriviAction<String>("http.maxConnections"));
- String httpKeepAlive = AccessController.doPrivileged(new PriviAction<String>("http.keepAlive"));
- if(httpMaxConnections != null) {
- maxConnections = Integer.parseInt(httpMaxConnections);
- }
- if(httpKeepAlive != null) {
- keepAlive = Boolean.parseBoolean(httpKeepAlive);
- if(!keepAlive) {
- pool.clear();
- }
- }
- }
-
- private static class ConnectionPool {
-
- private Map<HttpConfiguration, List<HttpConnection>> freeConnectionMap = new HashMap<HttpConfiguration, List<HttpConnection>>(); // Map of free Sockets
-
- public synchronized void clear() {
- for (Iterator<List<HttpConnection>> iter = freeConnectionMap.values().iterator(); iter.hasNext();) {
- List<HttpConnection> connections = iter.next();
- for (Iterator<HttpConnection> iterator = connections.iterator(); iterator.hasNext();) {
- HttpConnection connection = iterator.next();
- connection.closeSocketAndStreams();
- }
- }
- freeConnectionMap.clear();
- }
-
- public synchronized void returnConnection(HttpConnection connection) {
- // BEGIN android-note
- // Simplified the following test.
- // END android-note
- if(keepAlive && connection.isEligibleForRecycling()) {
- HttpConfiguration config = connection.getHttpConfiguration();
- List<HttpConnection> connections = freeConnectionMap.get(config);
- if(connections == null) {
- connections = new ArrayList<HttpConnection>();
- freeConnectionMap.put(config, connections);
- }
- if(connections.size() < HttpConnectionManager.maxConnections) {
- if(!connections.contains(connection)) {
- connections.add(connection);
- }
- } else {
- connection.closeSocketAndStreams();
- }
- } else {
- // Make sure all streams are closed etc.
- connection.closeSocketAndStreams();
- }
- }
-
- public synchronized HttpConnection getHttpConnection(HttpConfiguration config, int connectTimeout) throws IOException {
- List<HttpConnection> connections = freeConnectionMap.get(config);
- if(keepAlive && connections == null) {
- connections = new ArrayList<HttpConnection>();
- freeConnectionMap.put(config, connections);
- }
- if(!keepAlive || connections.isEmpty()) {
- HttpConnection connection = new HttpConnection(config, connectTimeout);
- return connection;
- } else {
- HttpConnection connection = connections.get(0);
- connections.remove(0);
- if(!connection.isStale()) {
- SecurityManager security = System.getSecurityManager();
- if (security != null) {
- security.checkConnect(connection.getSocket().getInetAddress().getHostName(), connection.getSocket().getPort());
- }
- return connection;
- } else {
- return getHttpConnection(config, connectTimeout);
- }
- }
- }
-
- public int numFreeConnections() {
- int numFree = 0;
- for (Iterator<List<HttpConnection>> iter = freeConnectionMap.values().iterator(); iter.hasNext();) {
- List<HttpConnection> connections = iter.next();
- numFree += connections.size();
- }
- return numFree;
- }
- }
-
- public void reset() {
- pool.clear();
- }
-
-}
\ No newline at end of file
diff --git a/libcore/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/http/HttpConnectionPool.java b/libcore/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/http/HttpConnectionPool.java
new file mode 100644
index 0000000..c3a997b
--- /dev/null
+++ b/libcore/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/http/HttpConnectionPool.java
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.luni.internal.net.www.protocol.http;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * A pool of HTTP connections. This class exposes its tuning parameters as
+ * system properties:
+ * <ul>
+ * <li>{@code http.keepAlive} true if HTTP connections should be pooled at
+ * all. Default is true.
+ * <li>{@code http.maxConnections} maximum number of connections to each URI.
+ * Default is 5.
+ * </ul>
+ *
+ * <p>This class <i>doesn't</i> adjust its configuration as system properties
+ * are changed. This assumes that the applications that set these parameters do
+ * so before making HTTP connections, and that this class is initialized lazily.
+ *
+ * <p>If a security manager is in place, HTTP connection pooling will be
+ * disabled and these system properties will be ignored.
+ */
+public final class HttpConnectionPool {
+
+ public static final HttpConnectionPool INSTANCE = new HttpConnectionPool();
+
+ private final int maxConnections;
+ private final HashMap<HttpConfiguration, List<HttpConnection>> connectionPool
+ = new HashMap<HttpConfiguration, List<HttpConnection>>();
+
+ private HttpConnectionPool() {
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) {
+ maxConnections = 0;
+ return;
+ }
+
+ String keepAlive = System.getProperty("http.keepAlive");
+ if (keepAlive != null && !Boolean.parseBoolean(keepAlive)) {
+ maxConnections = 0;
+ return;
+ }
+
+ String maxConnectionsString = System.getProperty("http.maxConnections");
+ this.maxConnections = maxConnectionsString != null
+ ? Integer.parseInt(maxConnectionsString)
+ : 5;
+ }
+
+ public HttpConnection get(HttpConfiguration config, int connectTimeout) throws IOException {
+ // First try to reuse an existing HTTP connection.
+ synchronized (connectionPool) {
+ List<HttpConnection> connections = connectionPool.get(config);
+ if (connections != null) {
+ while (!connections.isEmpty()) {
+ HttpConnection connection = connections.remove(connections.size() - 1);
+ if (!connection.isStale()) {
+ return connection;
+ }
+ }
+ connectionPool.remove(config);
+ }
+ }
+
+ /*
+ * We couldn't find a reusable connection, so we need to create a new
+ * connection. We're careful not to do so while holding a lock!
+ */
+ return new HttpConnection(config, connectTimeout);
+ }
+
+ public void recycle(HttpConnection connection) {
+ if (maxConnections > 0 && connection.isEligibleForRecycling()) {
+ HttpConfiguration config = connection.getHttpConfiguration();
+ synchronized (connectionPool) {
+ List<HttpConnection> connections = connectionPool.get(config);
+ if (connections == null) {
+ connections = new ArrayList<HttpConnection>();
+ connectionPool.put(config, connections);
+ }
+ if (connections.size() < maxConnections) {
+ connections.add(connection);
+ return; // keep the connection open
+ }
+ }
+ }
+
+ // don't close streams while holding a lock!
+ connection.closeSocketAndStreams();
+ }
+}
\ No newline at end of file
diff --git a/libcore/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/http/HttpURLConnectionImpl.java b/libcore/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/http/HttpURLConnectionImpl.java
index 687a4f3..c8c9600 100644
--- a/libcore/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/http/HttpURLConnectionImpl.java
+++ b/libcore/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/http/HttpURLConnectionImpl.java
@@ -917,14 +917,14 @@
* Returns connected socket to be used for this HTTP connection.
*/
protected HttpConnection getHTTPConnection(Proxy proxy) throws IOException {
- HttpConnection connection;
+ HttpConfiguration configuration;
if (proxy == null || proxy.type() == Proxy.Type.DIRECT) {
- this.proxy = null; // not using proxy
- connection = HttpConnectionManager.getDefault().getConnection(uri, getConnectTimeout());
+ this.proxy = null; // not using proxy
+ configuration = new HttpConfiguration(uri);
} else {
- connection = HttpConnectionManager.getDefault().getConnection(uri, proxy, getConnectTimeout());
+ configuration = new HttpConfiguration(uri, proxy);
}
- return connection;
+ return HttpConnectionPool.INSTANCE.get(configuration, getConnectTimeout());
}
/**
@@ -1000,8 +1000,7 @@
*/
connection.closeSocketAndStreams();
} else {
- HttpConnectionManager.getDefault().returnConnectionToPool(
- connection);
+ HttpConnectionPool.INSTANCE.recycle(connection);
}
connection = null;
}
diff --git a/libcore/luni/src/test/java/java/net/URLConnectionTest.java b/libcore/luni/src/test/java/java/net/URLConnectionTest.java
index bb517cc..263c961 100644
--- a/libcore/luni/src/test/java/java/net/URLConnectionTest.java
+++ b/libcore/luni/src/test/java/java/net/URLConnectionTest.java
@@ -16,9 +16,7 @@
package java.net;
-import java.net.*;
import java.io.BufferedReader;
-import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.Arrays;
@@ -60,6 +58,14 @@
mServer.setMaxChunkSize(8);
assertTrue(readFirstLine().equals("<html>"));
assertTrue(readFirstLine().equals("<html>"));
+ assertEquals(1, mServer.getNumAcceptedConnections());
+ }
+
+ public void testConnectionsArePooled() throws Exception {
+ readFirstLine();
+ readFirstLine();
+ readFirstLine();
+ assertEquals(1, mServer.getNumAcceptedConnections());
}
enum UploadKind { CHUNKED, FIXED_LENGTH };
diff --git a/libcore/support/src/test/java/tests/support/Support_TestWebServer.java b/libcore/support/src/test/java/tests/support/Support_TestWebServer.java
index 7d20237..3d6b2b1 100644
--- a/libcore/support/src/test/java/tests/support/Support_TestWebServer.java
+++ b/libcore/support/src/test/java/tests/support/Support_TestWebServer.java
@@ -226,6 +226,10 @@
return pathToRequest;
}
+ public int getNumAcceptedConnections() {
+ return acceptedConnections;
+ }
+
/**
* Cause the thread accepting connections on the server socket to close
*/
@@ -274,23 +278,19 @@
*/
public synchronized void run() {
running = true;
- try {
- while (running) {
- // Log.d(LOGTAG, "TestWebServer run() calling accept()");
+ while (running) {
+ try {
Socket s = ss.accept();
acceptedConnections++;
if (acceptedConnections >= acceptLimit) {
running = false;
}
-
new Thread(new Worker(s), "additional worker").start();
+ } catch (SocketException e) {
+ log(e.getMessage());
+ } catch (IOException e) {
+ log(e.getMessage());
}
- } catch (SocketException e) {
- log("SocketException in AcceptThread: probably closed during accept");
- running = false;
- } catch (IOException e) {
- log("IOException in AcceptThread");
- running = false;
}
log("AcceptThread terminated" + this);
}
diff --git a/libcore/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSocketImpl.java b/libcore/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSocketImpl.java
index 8006757..83e0b63 100644
--- a/libcore/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSocketImpl.java
+++ b/libcore/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSocketImpl.java
@@ -991,75 +991,27 @@
private native void nativefree();
protected void finalize() throws IOException {
+ /*
+ * Just worry about our own state. Notably we do not try and
+ * close anything. The SocketImpl, either our own
+ * PlainSocketImpl, or the Socket we are wrapping, will do
+ * that. This might mean we do not properly SSL_shutdown, but
+ * if you want to do that, properly close the socket yourself.
+ *
+ * The reason why we don't try to SSL_shutdown is that there
+ * can be a race between finalizers where the PlainSocketImpl
+ * finalizer runs first and closes the socket. However, in the
+ * meanwhile, the underlying file descriptor could be reused
+ * for another purpose. If we call SSL_shutdown after that, the
+ * underlying socket BIOs still have the older file descriptor
+ * and will write the close notify to some unsuspecting
+ * reader.
+ */
updateInstanceCount(-1);
-
if (ssl == 0) {
- /*
- * It's already been closed, so there's no need to do anything
- * more at this point.
- */
return;
}
-
- // Note the underlying socket up-front, for possible later use.
- Socket underlyingSocket = socket;
-
- // Fire up a thread to (hopefully) do all the real work.
- Finalizer f = new Finalizer();
- f.setDaemon(true);
- f.start();
-
- /*
- * Give the finalizer thread one second to run. If it fails to
- * terminate in that time, interrupt it (which may help if it
- * is blocked on an interruptible I/O operation), make a note
- * in the log, and go ahead and close the underlying socket if
- * possible.
- */
- try {
- f.join(1000);
- } catch (InterruptedException ex) {
- // Reassert interrupted status.
- Thread.currentThread().interrupt();
- }
-
- if (f.isAlive()) {
- f.interrupt();
- Logger.global.log(Level.SEVERE,
- "Slow finalization of SSL socket (" + this + ", for " +
- underlyingSocket + ")");
- if ((underlyingSocket != null) && !underlyingSocket.isClosed()) {
- underlyingSocket.close();
- }
- }
- }
-
- /**
- * Helper class for a thread that knows how to call
- * {@link OpenSSLSocketImpl#close} on behalf of instances being finalized,
- * since that call can take arbitrarily long (e.g., due to a slow network),
- * and an overly long-running finalizer will cause the process to be
- * totally aborted.
- */
- private class Finalizer extends Thread {
- public void run() {
- Socket underlyingSocket = socket; // for error reporting
- try {
- close();
- } catch (IOException ex) {
- /*
- * Clear interrupted status, so that the Logger call
- * immediately below won't get spuriously interrupted.
- */
- Thread.interrupted();
-
- Logger.global.log(Level.SEVERE,
- "Trouble finalizing SSL socket (" +
- OpenSSLSocketImpl.this + ", for " + underlyingSocket +
- ")",
- ex);
- }
- }
+ nativefree();
}
/**