--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/URLConnection/ZeroContentLength.java Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,308 @@
+/*
+ * Copyright 2001 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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;
+ }
+
+ /*
+ * 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;
+ }
+
+ public void run() {
+ try {
+
+ s.setSoTimeout(2000);
+ int max = 100;
+
+ for (;;) {
+
+ // read entire request from client
+ byte b[] = new byte[100];
+ InputStream in = s.getInputStream();
+ int n, total=0;
+
+ try {
+ do {
+ n = in.read(b);
+ if (n > 0) total += n;
+ } while (n > 0);
+ } 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 " + response + "\r\n");
+ if (contentLength >= 0) {
+ out.print("Content-Length: " + contentLength +
+ "\r\n");
+ }
+ out.print("\r\n");
+ for (int i=0; i<contentLength; i++) {
+ out.write( (byte)'.' );
+ }
+ out.flush();
+
+ debug("worked " + id +
+ ": Sent response to client, length: " + contentLength);
+
+ 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();
+ }
+
+}