0N/A/*
3261N/A * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
0N/A * published by the Free Software Foundation.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/A/**
0N/A * @test
0N/A * @bug 4507412
0N/A * @bug 4506998
0N/A * @summary Check that a 304 "Not-Modified" response from a server
0N/A * doesn't cause http client to close a keep-alive
0N/A * connection.
0N/A * Check that a content-length of 0 results in an
0N/A * empty input stream.
0N/A */
0N/Aimport java.net.*;
0N/Aimport java.io.*;
0N/A
0N/Apublic class ZeroContentLength {
0N/A
0N/A /*
0N/A * Is debugging enabled - start with -d to enable.
0N/A */
0N/A static boolean debug = false;
0N/A
0N/A static void debug(String msg) {
0N/A if (debug)
0N/A System.out.println(msg);
0N/A }
0N/A
0N/A /*
0N/A * The response string and content-length that
0N/A * the server should return;
0N/A */
0N/A static String response;
0N/A static int contentLength;
0N/A
0N/A static synchronized void setResponse(String rsp, int cl) {
0N/A response = rsp;
0N/A contentLength = cl;
0N/A }
0N/A
2612N/A static synchronized String getResponse() {
2612N/A return response;
2612N/A }
2612N/A
2612N/A static synchronized int getContentLength() {
2612N/A return contentLength;
2612N/A }
2612N/A
0N/A /*
0N/A * Worker thread to service single connection - can service
0N/A * multiple http requests on same connection.
0N/A */
0N/A class Worker extends Thread {
0N/A Socket s;
0N/A int id;
0N/A
0N/A Worker(Socket s, int id) {
0N/A this.s = s;
0N/A this.id = id;
0N/A }
0N/A
2612N/A final int CR = '\r';
2612N/A final int LF = '\n';
2612N/A
0N/A public void run() {
0N/A try {
0N/A
0N/A s.setSoTimeout(2000);
2612N/A int max = 20; // there should only be 20 connections
2612N/A InputStream in = new BufferedInputStream(s.getInputStream());
0N/A
0N/A for (;;) {
2612N/A // read entire request from client, until CR LF CR LF
2612N/A int c, total=0;
0N/A
0N/A try {
2612N/A while ((c = in.read()) > 0) {
2612N/A total++;
2612N/A if (c == CR) {
2612N/A if ((c = in.read()) > 0) {
2612N/A total++;
2612N/A if (c == LF) {
2612N/A if ((c = in.read()) > 0) {
2612N/A total++;
2612N/A if (c == CR) {
2612N/A if ((c = in.read()) > 0) {
2612N/A total++;
2612N/A if (c == LF) {
2612N/A break;
2612N/A }
2612N/A }
2612N/A }
2612N/A }
2612N/A }
2612N/A }
2612N/A }
2612N/A
2612N/A }
2612N/A } catch (SocketTimeoutException e) {}
0N/A
0N/A debug("worker " + id +
0N/A ": Read request from client " +
0N/A "(" + total + " bytes).");
0N/A
0N/A if (total == 0) {
0N/A debug("worker: " + id + ": Shutdown");
0N/A return;
0N/A }
0N/A
0N/A // response to client
0N/A PrintStream out = new PrintStream(
0N/A new BufferedOutputStream(
0N/A s.getOutputStream() ));
0N/A
2612N/A out.print("HTTP/1.1 " + getResponse() + "\r\n");
2612N/A int clen = getContentLength();
2612N/A if (clen >= 0) {
2612N/A out.print("Content-Length: " + clen +
0N/A "\r\n");
0N/A }
0N/A out.print("\r\n");
2612N/A for (int i=0; i<clen; i++) {
0N/A out.write( (byte)'.' );
0N/A }
0N/A out.flush();
0N/A
0N/A debug("worked " + id +
2612N/A ": Sent response to client, length: " + clen);
0N/A
0N/A if (--max == 0) {
0N/A s.close();
0N/A return;
0N/A }
0N/A }
0N/A
0N/A } catch (Exception e) {
0N/A e.printStackTrace();
0N/A } finally {
0N/A try {
0N/A s.close();
0N/A } catch (Exception e) { }
0N/A }
0N/A }
0N/A }
0N/A
0N/A /*
0N/A * Server thread to accept connection and create worker threads
0N/A * to service each connection.
0N/A */
0N/A class Server extends Thread {
0N/A ServerSocket ss;
0N/A int connectionCount;
0N/A boolean shutdown = false;
0N/A
0N/A Server(ServerSocket ss) {
0N/A this.ss = ss;
0N/A }
0N/A
0N/A public synchronized int connectionCount() {
0N/A return connectionCount;
0N/A }
0N/A
0N/A public synchronized void shutdown() {
0N/A shutdown = true;
0N/A }
0N/A
0N/A public void run() {
0N/A try {
0N/A ss.setSoTimeout(2000);
0N/A
0N/A for (;;) {
0N/A Socket s;
0N/A try {
0N/A debug("server: Waiting for connections");
0N/A s = ss.accept();
0N/A } catch (SocketTimeoutException te) {
0N/A synchronized (this) {
0N/A if (shutdown) {
0N/A debug("server: Shuting down.");
0N/A return;
0N/A }
0N/A }
0N/A continue;
0N/A }
0N/A
0N/A int id;
0N/A synchronized (this) {
0N/A id = connectionCount++;
0N/A }
0N/A
0N/A Worker w = new Worker(s, id);
0N/A w.start();
0N/A debug("server: Started worker " + id);
0N/A }
0N/A
0N/A } catch (Exception e) {
0N/A e.printStackTrace();
0N/A } finally {
0N/A try {
0N/A ss.close();
0N/A } catch (Exception e) { }
0N/A }
0N/A }
0N/A }
0N/A
0N/A /*
0N/A * Make a single http request and return the content length
0N/A * received. Also do sanity check to ensure that the
0N/A * content-length header matches the total received on
0N/A * the input stream.
0N/A */
0N/A int doRequest(String uri) throws Exception {
0N/A URL url = new URL(uri);
0N/A HttpURLConnection http = (HttpURLConnection)url.openConnection();
0N/A
0N/A int cl = http.getContentLength();
0N/A
0N/A InputStream in = http.getInputStream();
0N/A byte b[] = new byte[100];
0N/A int total = 0;
0N/A int n;
0N/A do {
0N/A n = in.read(b);
0N/A if (n > 0) total += n;
0N/A } while (n > 0);
0N/A in.close();
0N/A
0N/A if (cl >= 0 && total != cl) {
0N/A System.err.println("content-length header indicated: " + cl);
0N/A System.err.println("Actual received: " + total);
0N/A throw new Exception("Content-length didn't match actual received");
0N/A }
0N/A
0N/A return total;
0N/A }
0N/A
0N/A
0N/A /*
0N/A * Send http requests to "server" and check that they all
0N/A * use the same network connection and that the content
0N/A * length corresponds to the content length expected.
0N/A * stream.
0N/A */
0N/A ZeroContentLength() throws Exception {
0N/A
0N/A /* start the server */
0N/A ServerSocket ss = new ServerSocket(0);
0N/A Server svr = new Server(ss);
0N/A svr.start();
0N/A
0N/A String uri = "http://localhost:" +
0N/A Integer.toString(ss.getLocalPort()) +
0N/A "/foo.html";
0N/A
0N/A int expectedTotal = 0;
0N/A int actualTotal = 0;
0N/A
0N/A System.out.println("**********************************");
0N/A System.out.println("200 OK, content-length:1024 ...");
0N/A setResponse("200 OK", 1024);
0N/A for (int i=0; i<5; i++) {
0N/A actualTotal += doRequest(uri);
0N/A expectedTotal += 1024;
0N/A }
0N/A
0N/A System.out.println("**********************************");
0N/A System.out.println("200 OK, content-length:0 ...");
0N/A setResponse("200 OK", 0);
0N/A for (int i=0; i<5; i++) {
0N/A actualTotal += doRequest(uri);
0N/A }
0N/A
0N/A System.out.println("**********************************");
0N/A System.out.println("304 Not-Modified, (no content-length) ...");
0N/A setResponse("304 Not-Modifed", -1);
0N/A for (int i=0; i<5; i++) {
0N/A actualTotal += doRequest(uri);
0N/A }
0N/A
0N/A System.out.println("**********************************");
0N/A System.out.println("204 No-Content, (no content-length) ...");
0N/A setResponse("204 No-Content", -1);
0N/A for (int i=0; i<5; i++) {
0N/A actualTotal += doRequest(uri);
0N/A }
0N/A
0N/A // shutdown server - we're done.
0N/A svr.shutdown();
0N/A
0N/A System.out.println("**********************************");
0N/A
0N/A if (actualTotal == expectedTotal) {
0N/A System.out.println("Passed: Actual total equal to expected total");
0N/A } else {
0N/A throw new Exception("Actual total != Expected total!!!");
0N/A }
0N/A
0N/A int cnt = svr.connectionCount();
0N/A if (cnt == 1) {
0N/A System.out.println("Passed: Only 1 connection established");
0N/A } else {
0N/A throw new Exception("Test failed: Number of connections " +
0N/A "established: " + cnt + " - see log for details.");
0N/A }
0N/A }
0N/A
0N/A public static void main(String args[]) throws Exception {
0N/A
0N/A if (args.length > 0 && args[0].equals("-d")) {
0N/A debug = true;
0N/A }
0N/A
0N/A new ZeroContentLength();
0N/A }
0N/A
0N/A}