aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Hawke <paul.hawke@gmail.com>2013-10-30 09:13:09 -0700
committerPaul Hawke <paul.hawke@gmail.com>2013-10-30 09:13:09 -0700
commit13aa4686b5af377c971b198b4a932590b859a6e7 (patch)
tree4872c0bf958024b1c6700ed01fc1ad0a5d6f078e
parent12e45c1e4150d8a4405e3e68b2b8d9993b7e7add (diff)
parent0a35219489d8f19d13197bc60eec168dd6b3089d (diff)
downloadnanohttpd-13aa4686b5af377c971b198b4a932590b859a6e7.tar.gz
Merge pull request #76 from AlbinTheander/albin_theander
Closes all existing connections at shutdown.
-rw-r--r--core/src/main/java/fi/iki/elonen/NanoHTTPD.java33
-rw-r--r--core/src/test/java/fi/iki/elonen/integration/ShutdownTest.java53
2 files changed, 86 insertions, 0 deletions
diff --git a/core/src/main/java/fi/iki/elonen/NanoHTTPD.java b/core/src/main/java/fi/iki/elonen/NanoHTTPD.java
index 5ce08e7..424856b 100644
--- a/core/src/main/java/fi/iki/elonen/NanoHTTPD.java
+++ b/core/src/main/java/fi/iki/elonen/NanoHTTPD.java
@@ -73,6 +73,7 @@ public abstract class NanoHTTPD {
private final String hostname;
private final int myPort;
private ServerSocket myServerSocket;
+ private Set<Socket> openConnections = new HashSet<Socket>();
private Thread myThread;
/**
* Pluggable strategy for asynchronously executing requests.
@@ -142,10 +143,12 @@ public abstract class NanoHTTPD {
do {
try {
final Socket finalAccept = myServerSocket.accept();
+ registerConnection(finalAccept);
finalAccept.setSoTimeout(SOCKET_READ_TIMEOUT);
final InputStream inputStream = finalAccept.getInputStream();
if (inputStream == null) {
safeClose(finalAccept);
+ unRegisterConnection(finalAccept);
} else {
asyncRunner.exec(new Runnable() {
@Override
@@ -168,6 +171,7 @@ public abstract class NanoHTTPD {
safeClose(outputStream);
safeClose(inputStream);
safeClose(finalAccept);
+ unRegisterConnection(finalAccept);
}
}
});
@@ -188,12 +192,41 @@ public abstract class NanoHTTPD {
public void stop() {
try {
safeClose(myServerSocket);
+ closeAllConnections();
myThread.join();
} catch (Exception e) {
e.printStackTrace();
}
}
+ /**
+ * Registers that a new connection has been set up.
+ *
+ * @param socket
+ * the {@link Socket} for the connection.
+ */
+ public synchronized void registerConnection(Socket socket) {
+ openConnections.add(socket);
+ }
+
+ /**
+ * Registers that a connection has been closed
+ *
+ * @param socket
+ * the {@link Socket} for the connection.
+ */
+ public synchronized void unRegisterConnection(Socket socket) {
+ openConnections.remove(socket);
+ }
+
+ /**
+ * Forcibly closes all connections that are open.
+ */
+ public synchronized void closeAllConnections() {
+ for (Socket socket : openConnections) {
+ safeClose(socket);
+ }
+ }
public final int getListeningPort() {
return myServerSocket == null ? -1 : myServerSocket.getLocalPort();
diff --git a/core/src/test/java/fi/iki/elonen/integration/ShutdownTest.java b/core/src/test/java/fi/iki/elonen/integration/ShutdownTest.java
new file mode 100644
index 0000000..0fcb275
--- /dev/null
+++ b/core/src/test/java/fi/iki/elonen/integration/ShutdownTest.java
@@ -0,0 +1,53 @@
+package fi.iki.elonen.integration;
+
+import static org.junit.Assert.*;
+import fi.iki.elonen.NanoHTTPD;
+
+import org.junit.Test;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+public class ShutdownTest {
+
+ @Test
+ public void connectionsAreClosedWhenServerStops() throws IOException {
+ TestServer server = new TestServer();
+ server.start();
+ makeRequest();
+ server.stop();
+ try {
+ makeRequest();
+ fail("Connection should be closed!");
+ } catch (IOException e) {
+ // Expected exception
+ }
+ }
+
+ private void makeRequest() throws MalformedURLException, IOException {
+ HttpURLConnection connection = (HttpURLConnection) new URL("http://localhost:8092/").openConnection();
+ // Keep-alive seems to be on by default, but just in case that changes.
+ connection.addRequestProperty("Connection", "keep-alive");
+ InputStream in = connection.getInputStream();
+ while (in.available() > 0) {
+ in.read();
+ }
+ in.close();
+ }
+
+ private class TestServer extends NanoHTTPD {
+
+ public TestServer() {
+ super(8092);
+ }
+
+ @Override
+ public Response serve(IHTTPSession session) {
+ return new Response("Whatever");
+ }
+ }
+
+}