test/jdk/java/net/URLConnection/ZeroContentLength.java
changeset 47216 71c04702a3d5
parent 7668 d4a77089c587
child 55047 3131927311ee
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/URLConnection/ZeroContentLength.java	Tue Sep 12 19:03:39 2017 +0200
@@ -0,0 +1,336 @@
+/*
+ * Copyright (c) 2001, 2010, 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 4507412
+ * @bug 4506998
+ * @summary Check that a 304 "Not-Modified" response from a server
+ *          doesn't cause http client to close a keep-alive
+ *          connection.
+ *          Check that a content-length of 0 results in an
+ *          empty input stream.
+ */
+import java.net.*;
+import java.io.*;
+
+public class ZeroContentLength {
+
+    /*
+     * Is debugging enabled - start with -d to enable.
+     */
+    static boolean debug = false;
+
+    static void debug(String msg) {
+        if (debug)
+            System.out.println(msg);
+    }
+
+    /*
+     * The response string and content-length that
+     * the server should return;
+     */
+    static String response;
+    static int contentLength;
+
+    static synchronized void setResponse(String rsp, int cl) {
+        response = rsp;
+        contentLength = cl;
+    }
+
+    static synchronized String getResponse() {
+        return response;
+    }
+
+    static synchronized int getContentLength() {
+        return contentLength;
+    }
+
+    /*
+     * Worker thread to service single connection - can service
+     * multiple http requests on same connection.
+     */
+    class Worker extends Thread {
+        Socket s;
+        int id;
+
+        Worker(Socket s, int id) {
+            this.s = s;
+            this.id = id;
+        }
+
+        final int CR = '\r';
+        final int LF = '\n';
+
+        public void run() {
+            try {
+
+                s.setSoTimeout(2000);
+                int max = 20; // there should only be 20 connections
+                InputStream in = new BufferedInputStream(s.getInputStream());
+
+                for (;;) {
+                    // read entire request from client, until CR LF CR LF
+                    int c, total=0;
+
+                    try {
+                        while ((c = in.read()) > 0) {
+                            total++;
+                            if (c == CR) {
+                                if ((c = in.read()) > 0) {
+                                    total++;
+                                    if (c == LF) {
+                                        if ((c = in.read()) > 0) {
+                                            total++;
+                                            if (c == CR) {
+                                                if ((c = in.read()) > 0) {
+                                                    total++;
+                                                    if (c == LF) {
+                                                        break;
+                                                    }
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+
+                        }
+                    } catch (SocketTimeoutException e) {}
+
+                    debug("worker " + id +
+                        ": Read request from client " +
+                        "(" + total + " bytes).");
+
+                    if (total == 0) {
+                        debug("worker: " + id + ": Shutdown");
+                        return;
+                    }
+
+                    // response to client
+                    PrintStream out = new PrintStream(
+                                        new BufferedOutputStream(
+                                                s.getOutputStream() ));
+
+                    out.print("HTTP/1.1 " + getResponse() + "\r\n");
+                    int clen = getContentLength();
+                    if (clen >= 0) {
+                        out.print("Content-Length: " + clen +
+                                    "\r\n");
+                    }
+                    out.print("\r\n");
+                    for (int i=0; i<clen; i++) {
+                        out.write( (byte)'.' );
+                    }
+                    out.flush();
+
+                    debug("worked " + id +
+                        ": Sent response to client, length: " + clen);
+
+                    if (--max == 0) {
+                        s.close();
+                        return;
+                    }
+                }
+
+            } catch (Exception e) {
+                e.printStackTrace();
+            } finally {
+                try {
+                    s.close();
+                } catch (Exception e) { }
+            }
+        }
+    }
+
+    /*
+     * Server thread to accept connection and create worker threads
+     * to service each connection.
+     */
+    class Server extends Thread {
+        ServerSocket ss;
+        int connectionCount;
+        boolean shutdown = false;
+
+        Server(ServerSocket ss) {
+            this.ss = ss;
+        }
+
+        public synchronized int connectionCount() {
+            return connectionCount;
+        }
+
+        public synchronized void shutdown() {
+            shutdown = true;
+        }
+
+        public void run() {
+            try {
+                ss.setSoTimeout(2000);
+
+                for (;;) {
+                    Socket s;
+                    try {
+                        debug("server: Waiting for connections");
+                        s = ss.accept();
+                    } catch (SocketTimeoutException te) {
+                        synchronized (this) {
+                            if (shutdown) {
+                                debug("server: Shuting down.");
+                                return;
+                            }
+                        }
+                        continue;
+                    }
+
+                    int id;
+                    synchronized (this) {
+                        id = connectionCount++;
+                    }
+
+                    Worker w = new Worker(s, id);
+                    w.start();
+                    debug("server: Started worker " + id);
+                }
+
+            } catch (Exception e) {
+                e.printStackTrace();
+            } finally {
+                try {
+                    ss.close();
+                } catch (Exception e) { }
+            }
+        }
+    }
+
+    /*
+     * Make a single http request and return the content length
+     * received. Also do sanity check to ensure that the
+     * content-length header matches the total received on
+     * the input stream.
+     */
+    int doRequest(String uri) throws Exception {
+        URL url = new URL(uri);
+        HttpURLConnection http = (HttpURLConnection)url.openConnection();
+
+        int cl = http.getContentLength();
+
+        InputStream in = http.getInputStream();
+        byte b[] = new byte[100];
+        int total = 0;
+        int n;
+        do {
+            n = in.read(b);
+            if (n > 0) total += n;
+        } while (n > 0);
+        in.close();
+
+        if (cl >= 0 && total != cl) {
+            System.err.println("content-length header indicated: " + cl);
+            System.err.println("Actual received: " + total);
+            throw new Exception("Content-length didn't match actual received");
+        }
+
+        return total;
+    }
+
+
+    /*
+     * Send http requests to "server" and check that they all
+     * use the same network connection and that the content
+     * length corresponds to the content length expected.
+     * stream.
+     */
+    ZeroContentLength() throws Exception {
+
+        /* start the server */
+        ServerSocket ss = new ServerSocket(0);
+        Server svr = new Server(ss);
+        svr.start();
+
+        String uri = "http://localhost:" +
+                     Integer.toString(ss.getLocalPort()) +
+                     "/foo.html";
+
+        int expectedTotal = 0;
+        int actualTotal = 0;
+
+        System.out.println("**********************************");
+        System.out.println("200 OK, content-length:1024 ...");
+        setResponse("200 OK", 1024);
+        for (int i=0; i<5; i++) {
+            actualTotal += doRequest(uri);
+            expectedTotal += 1024;
+        }
+
+        System.out.println("**********************************");
+        System.out.println("200 OK, content-length:0 ...");
+        setResponse("200 OK", 0);
+        for (int i=0; i<5; i++) {
+            actualTotal += doRequest(uri);
+        }
+
+        System.out.println("**********************************");
+        System.out.println("304 Not-Modified, (no content-length) ...");
+        setResponse("304 Not-Modifed", -1);
+        for (int i=0; i<5; i++) {
+            actualTotal += doRequest(uri);
+        }
+
+        System.out.println("**********************************");
+        System.out.println("204 No-Content, (no content-length) ...");
+        setResponse("204 No-Content", -1);
+        for (int i=0; i<5; i++) {
+            actualTotal += doRequest(uri);
+        }
+
+        // shutdown server - we're done.
+        svr.shutdown();
+
+        System.out.println("**********************************");
+
+        if (actualTotal == expectedTotal) {
+            System.out.println("Passed: Actual total equal to expected total");
+        } else {
+            throw new Exception("Actual total != Expected total!!!");
+        }
+
+        int cnt = svr.connectionCount();
+        if (cnt == 1) {
+            System.out.println("Passed: Only 1 connection established");
+        } else {
+            throw new Exception("Test failed: Number of connections " +
+                "established: " + cnt + " - see log for details.");
+        }
+    }
+
+    public static void main(String args[]) throws Exception {
+
+        if (args.length > 0 && args[0].equals("-d")) {
+            debug = true;
+        }
+
+        new ZeroContentLength();
+    }
+
+}