aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSleekWeasel <sleekweasel@gmail.com>2013-09-14 19:54:34 +0100
committerSleekWeasel <sleekweasel@gmail.com>2013-09-14 20:26:15 +0100
commitfe1961e39809c90a76422332e91af67a5c65c31c (patch)
tree7bbb9b94bb6070be3b708a68359d88500ef4f63b
parentbf93f366554a38177e7ed73a53d9da7449aeedec (diff)
downloadnanohttpd-fe1961e39809c90a76422332e91af67a5c65c31c.tar.gz
Add chunked support from PipeInputStreams
-rw-r--r--core/src/main/java/fi/iki/elonen/NanoHTTPD.java59
-rw-r--r--core/src/test/java/fi/iki/elonen/HttpChunkedResponseTest.java58
2 files changed, 100 insertions, 17 deletions
diff --git a/core/src/main/java/fi/iki/elonen/NanoHTTPD.java b/core/src/main/java/fi/iki/elonen/NanoHTTPD.java
index bfe08a5..f058365 100644
--- a/core/src/main/java/fi/iki/elonen/NanoHTTPD.java
+++ b/core/src/main/java/fi/iki/elonen/NanoHTTPD.java
@@ -570,25 +570,12 @@ public abstract class NanoHTTPD {
}
}
- int pending = data != null ? data.available() : 0; // This is to support partial sends, see serveFile()
pw.print("Connection: keep-alive\r\n");
- pw.print("Content-Length: "+pending+"\r\n");
- pw.print("\r\n");
- pw.flush();
-
- if (requestMethod != Method.HEAD && data != null) {
- int BUFFER_SIZE = 16 * 1024;
- byte[] buff = new byte[BUFFER_SIZE];
- while (pending > 0) {
- int read = data.read(buff, 0, ((pending > BUFFER_SIZE) ? BUFFER_SIZE : pending));
- if (read <= 0) {
- break;
- }
- outputStream.write(buff, 0, read);
-
- pending -= read;
- }
+ if (requestMethod != Method.HEAD && data instanceof PipedInputStream) {
+ sendAsChunked(outputStream, pw);
+ } else {
+ sendAsFixedLength(outputStream, pw);
}
outputStream.flush();
safeClose(data);
@@ -597,6 +584,44 @@ public abstract class NanoHTTPD {
}
}
+ private void sendAsChunked(OutputStream outputStream, PrintWriter pw) throws IOException {
+ pw.print("Transfer-Encoding: chunked\r\n");
+ pw.print("\r\n");
+ pw.flush();
+ int BUFFER_SIZE = 16 * 1024;
+ byte[] CRLF = "\r\n".getBytes();
+ byte[] buff = new byte[BUFFER_SIZE];
+ int read;
+ while ((read = data.read(buff)) > 0) {
+ outputStream.write(String.format("%x\r\n", read).getBytes());
+ outputStream.write(buff, 0, read);
+ outputStream.write(CRLF);
+ }
+ outputStream.write(String.format("0\r\n\r\n").getBytes());
+ }
+
+ private void sendAsFixedLength(OutputStream outputStream, PrintWriter pw) throws IOException {
+ int pending = data != null ? data.available() : 0; // This is to support partial sends, see serveFile()
+ pw.print("Content-Length: "+pending+"\r\n");
+
+ pw.print("\r\n");
+ pw.flush();
+
+ if (requestMethod != Method.HEAD && data != null) {
+ int BUFFER_SIZE = 16 * 1024;
+ byte[] buff = new byte[BUFFER_SIZE];
+ while (pending > 0) {
+ int read = data.read(buff, 0, ((pending > BUFFER_SIZE) ? BUFFER_SIZE : pending));
+ if (read <= 0) {
+ break;
+ }
+ outputStream.write(buff, 0, read);
+
+ pending -= read;
+ }
+ }
+ }
+
public Status getStatus() {
return status;
}
diff --git a/core/src/test/java/fi/iki/elonen/HttpChunkedResponseTest.java b/core/src/test/java/fi/iki/elonen/HttpChunkedResponseTest.java
new file mode 100644
index 0000000..04bb7b7
--- /dev/null
+++ b/core/src/test/java/fi/iki/elonen/HttpChunkedResponseTest.java
@@ -0,0 +1,58 @@
+package fi.iki.elonen;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PipedInputStream;
+
+import static fi.iki.elonen.NanoHTTPD.Response.Status.OK;
+
+public class HttpChunkedResponseTest extends HttpServerTest {
+ @org.junit.Test
+ public void thatChunkedContentIsChunked() throws Exception {
+ PipedInputStream pipedInputStream = new ChunkedInputStream(new String[]{
+ "some",
+ "thing which is longer than sixteen characters",
+ "whee!",
+ ""
+ });
+ String[] expected = {
+ "HTTP/1.1 200 OK",
+ "Content-Type: what/ever",
+ "Date: .*",
+ "Connection: keep-alive",
+ "Transfer-Encoding: chunked",
+ "",
+ "4",
+ "some",
+ "2d",
+ "thing which is longer than sixteen characters",
+ "5",
+ "whee!",
+ "0",
+ ""
+ };
+ testServer.response = new NanoHTTPD.Response(OK, "what/ever", pipedInputStream);
+
+ ByteArrayOutputStream byteArrayOutputStream = invokeServer("GET / HTTP/1.0");
+
+ assertResponse(byteArrayOutputStream, expected);
+ }
+
+ private static class ChunkedInputStream extends PipedInputStream {
+ int chunk = 0;
+ String[] chunks;
+
+ private ChunkedInputStream(String[] chunks) {
+ this.chunks = chunks;
+ }
+
+ @Override
+ public synchronized int read(byte[] buffer) throws IOException {
+ // Too implementation-linked, but...
+ for (int i = 0; i < chunks[chunk].length(); ++i) {
+ buffer[i] = (byte) chunks[chunk].charAt(i);
+ }
+ return chunks[chunk++].length();
+ }
+ }
+}