8190793: Httpserver does not detect truncated request body
authormichaelm
Mon, 06 Nov 2017 16:32:00 +0000
changeset 47705 a6f8cacdef93
parent 47704 38aa08d2ec6c
child 47706 5d668ad5142f
child 47717 4a00b088902e
8190793: Httpserver does not detect truncated request body Reviewed-by: chegar, dfuchs
src/jdk.httpserver/share/classes/sun/net/httpserver/ChunkedInputStream.java
src/jdk.httpserver/share/classes/sun/net/httpserver/FixedLengthInputStream.java
test/jdk/com/sun/net/httpserver/bugs/TruncatedRequestBody.java
--- a/src/jdk.httpserver/share/classes/sun/net/httpserver/ChunkedInputStream.java	Mon Nov 06 22:05:53 2017 +0530
+++ b/src/jdk.httpserver/share/classes/sun/net/httpserver/ChunkedInputStream.java	Mon Nov 06 16:32:00 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2017, 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
@@ -135,6 +135,8 @@
             needToReadHeader = true;
             consumeCRLF();
         }
+        if (n < 0 && !eof)
+            throw new IOException("connection closed before all data received");
         return n;
     }
 
--- a/src/jdk.httpserver/share/classes/sun/net/httpserver/FixedLengthInputStream.java	Mon Nov 06 22:05:53 2017 +0530
+++ b/src/jdk.httpserver/share/classes/sun/net/httpserver/FixedLengthInputStream.java	Mon Nov 06 16:32:00 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2017, 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
@@ -60,6 +60,8 @@
                 t.getServerImpl().requestCompleted (t.getConnection());
             }
         }
+        if (n < 0 && !eof)
+            throw new IOException("connection closed before all data received");
         return n;
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/com/sun/net/httpserver/bugs/TruncatedRequestBody.java	Mon Nov 06 16:32:00 2017 +0000
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2017, 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 8190793
+ * @summary Httpserver does not detect truncated request body
+ */
+
+import com.sun.net.httpserver.HttpContext;
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.net.httpserver.HttpHandler;
+import com.sun.net.httpserver.HttpServer;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.nio.charset.StandardCharsets;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.logging.ConsoleHandler;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/*
+ * Send two POST requests to the server which are both trucated
+ * and socket closed. Server needs to detect this and throw an IOException
+ * in getRequestBody().read(). Two variants for fixed length and chunked.
+ */
+public class TruncatedRequestBody {
+    static volatile boolean error = false;
+
+    static CountDownLatch latch = new CountDownLatch(2);
+
+    static class Handler implements HttpHandler {
+
+        @Override
+        public void handle(HttpExchange exch) throws IOException {
+            InputStream is = exch.getRequestBody();
+            int c, count = 0;
+            byte[] buf = new byte[128];
+            try {
+            while ((c=is.read(buf)) > 0)
+                count += c;
+            } catch (IOException e) {
+                System.out.println("Exception caught");
+                latch.countDown();
+                throw e;
+            }
+            // shouldn't get to here
+            error = true;
+            latch.countDown();
+            System.out.println("Read " + count + " bytes");
+            is.close();
+            exch.sendResponseHeaders(200, -1);
+        }
+
+    }
+
+    /**
+     * @param args the command line arguments
+     */
+    public static void main(String[] args) throws IOException, InterruptedException {
+        Logger logger = Logger.getLogger("com.sun.net.httpserver");
+        ConsoleHandler h = new ConsoleHandler();
+        h.setLevel(Level.ALL);
+        logger.setLevel(Level.ALL);
+        logger.addHandler(h);
+
+        InetSocketAddress addr = new InetSocketAddress(0);
+        HttpServer server = HttpServer.create(addr, 10);
+        HttpContext ct = server.createContext("/", new Handler());
+        ExecutorService ex = Executors.newCachedThreadPool();
+        server.setExecutor(ex);
+        server.start();
+
+        int port = server.getAddress().getPort();
+
+        // Test 1: fixed length
+
+        Socket sock = new Socket("127.0.0.1", port);
+        String s1 = "POST /foo HTTP/1.1\r\nContent-length: 200000\r\n"
+                + "\r\nfoo bar99";
+
+        OutputStream os = sock.getOutputStream();
+        os.write(s1.getBytes(StandardCharsets.ISO_8859_1));
+        Thread.sleep(500);
+
+        sock.close();
+
+        // Test 2: chunked
+
+        String s2 = "POST /foo HTTP/1.1\r\nTransfer-encoding: chunked\r\n\r\n" +
+                "100\r\nFoo bar";
+        sock = new Socket("127.0.0.1", port);
+        os = sock.getOutputStream();
+        os.write(s2.getBytes(StandardCharsets.ISO_8859_1));
+        Thread.sleep(500);
+        sock.close();
+        latch.await();
+        server.stop(0);
+        ex.shutdownNow();
+        if (error)
+            throw new RuntimeException("Test failed");
+    }
+}