0N/A/*
3261N/A * Copyright (c) 2002, 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 4636628
0N/A * @summary HttpURLConnection duplicates HTTP GET requests when used with multiple threads
0N/A*/
0N/A
0N/A/*
0N/A * This tests keep-alive behavior using chunkedinputstreams
0N/A * It checks that keep-alive connections are used and also
0N/A * that requests are not being repeated (due to errors)
0N/A *
0N/A * It also checks that the keepalive connections are closed eventually
0N/A * because the test will not terminate if the connections
0N/A * are not closed by the keep-alive timer.
0N/A */
0N/A
0N/Aimport java.net.*;
0N/Aimport java.io.*;
0N/A
0N/Apublic class MultiThreadTest extends Thread {
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 Object threadlock = new Object ();
0N/A static int threadCounter = 0;
0N/A
0N/A static Object getLock() { return threadlock; }
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 static int reqnum = 0;
0N/A
0N/A void doRequest(String uri) throws Exception {
0N/A URL url = new URL(uri + "?foo="+reqnum);
0N/A reqnum ++;
0N/A HttpURLConnection http = (HttpURLConnection)url.openConnection();
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 debug ("client: read " + total + " bytes");
0N/A in.close();
0N/A http.disconnect();
0N/A }
0N/A
0N/A String uri;
0N/A byte[] b;
0N/A int requests;
0N/A
0N/A MultiThreadTest(int port, int requests) throws Exception {
0N/A uri = "http://localhost:" +
0N/A port + "/foo.html";
0N/A
0N/A b = new byte [256];
0N/A this.requests = requests;
0N/A
0N/A synchronized (threadlock) {
0N/A threadCounter ++;
0N/A }
0N/A }
0N/A
0N/A public void run () {
0N/A try {
0N/A for (int i=0; i<requests; i++) {
0N/A doRequest (uri);
0N/A }
0N/A } catch (Exception e) {
0N/A throw new RuntimeException (e.getMessage());
2612N/A } finally {
2612N/A synchronized (threadlock) {
2612N/A threadCounter --;
2612N/A if (threadCounter == 0) {
2612N/A threadlock.notifyAll();
2612N/A }
0N/A }
0N/A }
0N/A }
0N/A
0N/A static int threads=5;
0N/A
0N/A public static void main(String args[]) throws Exception {
0N/A
0N/A int x = 0, arg_len = args.length;
0N/A int requests = 20;
0N/A
0N/A if (arg_len > 0 && args[0].equals("-d")) {
0N/A debug = true;
0N/A x = 1;
0N/A arg_len --;
0N/A }
0N/A if (arg_len > 0) {
0N/A threads = Integer.parseInt (args[x]);
0N/A requests = Integer.parseInt (args[x+1]);
0N/A }
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 Object lock = MultiThreadTest.getLock();
0N/A synchronized (lock) {
0N/A for (int i=0; i<threads; i++) {
0N/A MultiThreadTest t = new MultiThreadTest(ss.getLocalPort(), requests);
0N/A t.start ();
0N/A }
0N/A try {
0N/A lock.wait();
0N/A } catch (InterruptedException e) {}
0N/A }
0N/A
0N/A // shutdown server - we're done.
0N/A svr.shutdown();
0N/A
0N/A int cnt = svr.connectionCount();
0N/A MultiThreadTest.debug("Connections = " + cnt);
0N/A int reqs = Worker.getRequests ();
0N/A MultiThreadTest.debug("Requests = " + reqs);
0N/A System.out.println ("Connection count = " + cnt + " Request count = " + reqs);
0N/A if (cnt > threads) { // could be less
0N/A throw new RuntimeException ("Expected "+threads + " connections: used " +cnt);
0N/A }
0N/A if (reqs != threads*requests) {
0N/A throw new RuntimeException ("Expected "+ threads*requests+ " requests: got " +reqs);
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 MultiThreadTest.debug("server: calling accept.");
0N/A s = ss.accept();
0N/A MultiThreadTest.debug("server: return accept.");
0N/A } catch (SocketTimeoutException te) {
0N/A MultiThreadTest.debug("server: STE");
0N/A synchronized (this) {
0N/A if (shutdown) {
0N/A MultiThreadTest.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 MultiThreadTest.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 * 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
0N/A static int requests = 0;
0N/A static Object rlock = new Object();
0N/A
0N/A public static int getRequests () {
0N/A synchronized (rlock) {
0N/A return requests;
0N/A }
0N/A }
0N/A public static void incRequests () {
0N/A synchronized (rlock) {
0N/A requests++;
0N/A }
0N/A }
0N/A
0N/A int readUntil (InputStream in, char[] seq) throws IOException {
0N/A int i=0, count=0;
0N/A while (true) {
0N/A int c = in.read();
0N/A if (c == -1)
0N/A return -1;
0N/A count++;
0N/A if (c == seq[i]) {
0N/A i++;
0N/A if (i == seq.length)
0N/A return count;
0N/A continue;
0N/A } else {
0N/A i = 0;
0N/A }
0N/A }
0N/A }
0N/A
0N/A public void run() {
0N/A try {
0N/A int max = 400;
0N/A byte b[] = new byte[1000];
0N/A InputStream in = new BufferedInputStream (s.getInputStream());
0N/A // response to client
0N/A PrintStream out = new PrintStream(
0N/A new BufferedOutputStream(
0N/A s.getOutputStream() ));
0N/A
0N/A for (;;) {
0N/A
0N/A // read entire request from client
0N/A int n=0;
0N/A
0N/A n = readUntil (in, new char[] {'\r','\n', '\r','\n'});
0N/A
0N/A if (n <= 0) {
0N/A MultiThreadTest.debug("worker: " + id + ": Shutdown");
0N/A s.close();
0N/A return;
0N/A }
0N/A
0N/A MultiThreadTest.debug("worker " + id +
0N/A ": Read request from client " +
0N/A "(" + n + " bytes).");
0N/A
0N/A incRequests();
0N/A out.print("HTTP/1.1 200 OK\r\n");
0N/A out.print("Transfer-Encoding: chunked\r\n");
0N/A out.print("Content-Type: text/html\r\n");
0N/A out.print("Connection: Keep-Alive\r\n");
0N/A out.print ("Keep-Alive: timeout=15, max="+max+"\r\n");
0N/A out.print("\r\n");
0N/A out.print ("6\r\nHello \r\n");
0N/A out.print ("5\r\nWorld\r\n");
0N/A out.print ("0\r\n\r\n");
0N/A out.flush();
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 }