diff options
Diffstat (limited to 'core')
-rw-r--r-- | core/src/main/java/fi/iki/elonen/NanoHTTPD.java | 42 | ||||
-rw-r--r-- | core/src/test/java/fi/iki/elonen/HttpKeepAliveTest.java | 17 |
2 files changed, 46 insertions, 13 deletions
diff --git a/core/src/main/java/fi/iki/elonen/NanoHTTPD.java b/core/src/main/java/fi/iki/elonen/NanoHTTPD.java index 50e074f..61e7d8d 100644 --- a/core/src/main/java/fi/iki/elonen/NanoHTTPD.java +++ b/core/src/main/java/fi/iki/elonen/NanoHTTPD.java @@ -468,6 +468,8 @@ public abstract class NanoHTTPD { private String remoteIp; + private String protocolVersion; + public HTTPSession(TempFileManager tempFileManager, InputStream inputStream, OutputStream outputStream) { this.tempFileManager = tempFileManager; this.inputStream = new PushbackInputStream(inputStream, HTTPSession.BUFSIZE); @@ -516,15 +518,14 @@ public abstract class NanoHTTPD { } // If there's another token, its protocol version, - // followed by HTTP headers. Ignore version but parse headers. + // followed by HTTP headers. // NOTE: this now forces header names lower case since they are // case insensitive and vary by client. if (st.hasMoreTokens()) { - if (!st.nextToken().equals("HTTP/1.1")) { - throw new ResponseException(Response.Status.UNSUPPORTED_HTTP_VERSION, "Only HTTP/1.1 is supported."); - } + protocolVersion = st.nextToken(); } else { - NanoHTTPD.LOG.log(Level.FINE, "no protocol version specified, strange.."); + protocolVersion = "HTTP/1.1"; + NanoHTTPD.LOG.log(Level.FINE, "no protocol version specified, strange. Assuming HTTP/1.1."); } String line = in.readLine(); while (line != null && line.trim().length() > 0) { @@ -716,6 +717,9 @@ public abstract class NanoHTTPD { this.cookies = new CookieHandler(this.headers); + String connection = this.headers.get("connection"); + boolean keepAlive = protocolVersion.equals("HTTP/1.1") && (connection == null || !connection.matches("(?i).*close.*")); + // Ok, now do the serve() Response r = serve(this); if (r == null) { @@ -725,8 +729,12 @@ public abstract class NanoHTTPD { this.cookies.unloadQueue(r); r.setRequestMethod(this.method); r.setGzipEncoding(acceptEncoding != null && acceptEncoding.contains("gzip")); + r.setKeepAlive(keepAlive); r.send(this.outputStream); } + if (!keepAlive || "close".equalsIgnoreCase(r.getHeader("connection"))) { + throw new SocketException("NanoHttpd Shutdown"); + } } catch (SocketException e) { // throw it out to close socket object (finalAccept) throw e; @@ -1170,6 +1178,8 @@ public abstract class NanoHTTPD { private boolean encodeAsGzip; + private boolean keepAlive; + /** * Creates a fixed length response if totalBytes>=0, otherwise chunked. */ @@ -1184,6 +1194,7 @@ public abstract class NanoHTTPD { this.contentLength = totalBytes; } this.chunkedTransfer = this.contentLength < 0; + keepAlive = true; } /** @@ -1198,7 +1209,12 @@ public abstract class NanoHTTPD { } public String getHeader(String name) { - return this.header.get(name); + for (String headerName : header.keySet()) { + if (headerName.equalsIgnoreCase(name)) { + return header.get(headerName); + } + } + return null; } public String getMimeType() { @@ -1217,6 +1233,10 @@ public abstract class NanoHTTPD { this.encodeAsGzip = encodeAsGzip; } + public void setKeepAlive(boolean useKeepAlive) { + this.keepAlive = useKeepAlive; + } + private boolean headerAlreadySent(Map<String, String> header, String name) { boolean alreadySent = false; for (String headerName : header.keySet()) { @@ -1255,7 +1275,9 @@ public abstract class NanoHTTPD { } } - sendConnectionHeaderIfNotAlreadyPresent(pw, this.header); + if (!headerAlreadySent(header, "connection")) { + pw.print("Connection: " + (this.keepAlive ? "keep-alive" : "close") + "\r\n"); + } if (headerAlreadySent(this.header, "content-length")) { encodeAsGzip = false; @@ -1331,12 +1353,6 @@ public abstract class NanoHTTPD { } } - protected void sendConnectionHeaderIfNotAlreadyPresent(PrintWriter pw, Map<String, String> header) { - if (!headerAlreadySent(header, "connection")) { - pw.print("Connection: keep-alive\r\n"); - } - } - protected long sendContentLengthHeaderIfNotAlreadyPresent(PrintWriter pw, Map<String, String> header, long size) { for (String headerName : header.keySet()) { if (headerName.equalsIgnoreCase("content-length")) { diff --git a/core/src/test/java/fi/iki/elonen/HttpKeepAliveTest.java b/core/src/test/java/fi/iki/elonen/HttpKeepAliveTest.java index b5170db..e168814 100644 --- a/core/src/test/java/fi/iki/elonen/HttpKeepAliveTest.java +++ b/core/src/test/java/fi/iki/elonen/HttpKeepAliveTest.java @@ -99,9 +99,26 @@ public class HttpKeepAliveTest extends HttpServerTest { for (int i = 0; i < 2048; i++) { requestStream.write(request.getBytes()); requestStream.flush(); + outputStream.reset(); session.execute(); assertResponse(outputStream, expected); } + + // Finally, try "Connection: Close" + String closeReq = request.replaceAll("HTTP/1.1", "HTTP/1.1\r\nConnection: Close"); + expected[3] = "Connection: close"; + requestStream.write(closeReq.getBytes()); + outputStream.reset(); + requestStream.flush(); + // Server should now close the socket by throwing a + // SocketException: + try { + session.execute(); + } catch (java.net.SocketException se) { + junit.framework.Assert.assertEquals(se.getMessage(), "NanoHttpd Shutdown"); + } + assertResponse(outputStream, expected); + } finally { tempFileManager.clear(); } |