1/*
2 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24/**
25 * @test
26 * @bug 6725892
27 * @run main/othervm -Dsun.net.httpserver.maxReqTime=2 Test
28 * @summary
29 */
30
31import com.sun.net.httpserver.*;
32
33import java.util.concurrent.*;
34import java.util.logging.*;
35import java.io.*;
36import java.net.*;
37import javax.net.ssl.*;
38
39public class Test {
40
41    static HttpServer s1;
42    static int port;
43    static URL url;
44    static final String RESPONSE_BODY = "response";
45    static boolean failed = false;
46
47    static class Handler implements HttpHandler {
48
49        public void handle (HttpExchange t)
50            throws IOException
51        {
52            InputStream is = t.getRequestBody();
53            InetSocketAddress rem = t.getRemoteAddress();
54            System.out.println ("Request from: " + rem);
55            while (is.read () != -1) ;
56            is.close();
57            String requrl = t.getRequestURI().toString();
58            OutputStream os = t.getResponseBody();
59            t.sendResponseHeaders (200, RESPONSE_BODY.length());
60            os.write (RESPONSE_BODY.getBytes());
61            t.close();
62        }
63    }
64
65    public static void main (String[] args) throws Exception {
66
67        ExecutorService exec = Executors.newCachedThreadPool();
68
69        try {
70            InetSocketAddress addr = new InetSocketAddress (0);
71            s1 = HttpServer.create (addr, 100);
72            HttpHandler h = new Handler ();
73            HttpContext c1 = s1.createContext ("/", h);
74            s1.setExecutor(exec);
75            s1.start();
76
77            port = s1.getAddress().getPort();
78            System.out.println ("Server on port " + port);
79            url = new URL ("http://127.0.0.1:"+port+"/foo");
80            test1();
81            test2();
82            test3();
83            Thread.sleep (2000);
84        } catch (Exception e) {
85            e.printStackTrace();
86            System.out.println ("FAIL");
87            throw new RuntimeException ();
88        } finally {
89            s1.stop(0);
90            System.out.println ("After Shutdown");
91            exec.shutdown();
92        }
93    }
94
95    // open TCP connection without sending anything. Check server closes it.
96
97    static void test1() throws IOException {
98        failed = false;
99        Socket s = new Socket ("127.0.0.1", port);
100        InputStream is = s.getInputStream();
101        // server should close connection after 2 seconds. We wait up to 10
102        s.setSoTimeout (10000);
103        try {
104            is.read();
105        } catch (SocketTimeoutException e) {
106            failed = true;
107        }
108        s.close();
109        if (failed) {
110            System.out.println ("test1: FAIL");
111            throw new RuntimeException ();
112        } else {
113            System.out.println ("test1: OK");
114        }
115    }
116
117    // send request and don't read response. Check server closes connection
118
119    static void test2() throws IOException {
120        HttpURLConnection urlc = (HttpURLConnection) url.openConnection();
121        urlc.setReadTimeout (20 * 1000);
122        InputStream is = urlc.getInputStream();
123        // we won't read response and check if it times out
124        // on server. If it timesout at client then there is a problem
125        try {
126            Thread.sleep (10 * 1000);
127            while (is.read() != -1) ;
128        } catch (InterruptedException e) {
129            System.out.println (e);
130            System.out.println ("test2: FAIL");
131            throw new RuntimeException ("unexpected error");
132        } catch (SocketTimeoutException e1) {
133            System.out.println (e1);
134            System.out.println ("test2: FAIL");
135            throw new RuntimeException ("client timedout");
136        } finally {
137            is.close();
138        }
139        System.out.println ("test2: OK");
140    }
141
142    // same as test2, but repeated with multiple connections
143    // including a number of valid request/responses
144
145    // Worker: a thread opens a connection to the server in one of three modes.
146    // NORMAL - sends a request, waits for response, and checks valid response
147    // REQUEST - sends a partial request, and blocks, to see if
148    //                  server closes the connection.
149    // RESPONSE - sends a request, partially reads response and blocks,
150    //                  to see if server closes the connection.
151
152    static class Worker extends Thread {
153        CountDownLatch latch;
154        Mode mode;
155
156        enum Mode {
157            REQUEST,    // block during sending of request
158            RESPONSE,   // block during reading of response
159            NORMAL      // don't block
160        };
161
162        Worker (CountDownLatch latch, Mode mode) {
163            this.latch = latch;
164            this.mode = mode;
165        }
166
167        void fail(String msg) {
168            System.out.println (msg);
169            failed = true;
170        }
171
172        public void run () {
173            HttpURLConnection urlc;
174            InputStream is = null;
175
176            try {
177                urlc = (HttpURLConnection) url.openConnection();
178                urlc.setReadTimeout (20 * 1000);
179                urlc.setDoOutput(true);
180            } catch (IOException e) {
181                fail("Worker: failed to connect to server");
182                latch.countDown();
183                return;
184            }
185            try {
186                OutputStream os = urlc.getOutputStream();
187                os.write ("foo".getBytes());
188                if (mode == Mode.REQUEST) {
189                    Thread.sleep (3000);
190                }
191                os.close();
192                is = urlc.getInputStream();
193                if (mode == Mode.RESPONSE) {
194                    Thread.sleep (3000);
195                }
196                if (!checkResponse (is, RESPONSE_BODY)) {
197                    fail ("Worker: response");
198                }
199                is.close();
200                return;
201            } catch (InterruptedException e0) {
202                fail("Worker: timedout");
203            } catch (SocketTimeoutException e1) {
204                fail("Worker: timedout");
205            } catch (IOException e2) {
206                switch (mode) {
207                  case NORMAL:
208                    fail ("Worker: " + e2.getMessage());
209                    break;
210                  case RESPONSE:
211                    if (is == null) {
212                        fail ("Worker: " + e2.getMessage());
213                        break;
214                    }
215                  // default: is ok
216                }
217            } finally {
218                latch.countDown();
219            }
220        }
221    }
222
223    static final int NUM = 20;
224
225    static void test3() throws Exception {
226        failed = false;
227        CountDownLatch l = new CountDownLatch (NUM*3);
228        Worker[] workers = new Worker[NUM*3];
229        for (int i=0; i<NUM; i++) {
230            workers[i*3] = new Worker (l, Worker.Mode.NORMAL);
231            workers[i*3+1] = new Worker (l, Worker.Mode.REQUEST);
232            workers[i*3+2] = new Worker (l, Worker.Mode.RESPONSE);
233            workers[i*3].start();
234            workers[i*3+1].start();
235            workers[i*3+2].start();
236        }
237        l.await();
238        for (int i=0; i<NUM*3; i++) {
239            workers[i].join();
240        }
241        if (failed) {
242            throw new RuntimeException ("test3: failed");
243        }
244        System.out.println ("test3: OK");
245    }
246
247    static boolean checkResponse (InputStream is, String resp) {
248        try {
249            ByteArrayOutputStream bos = new ByteArrayOutputStream();
250            byte[] buf = new byte [64];
251            int c;
252            while ((c=is.read(buf)) != -1) {
253                bos.write (buf, 0, c);
254            }
255            bos.close();
256            if (!bos.toString().equals(resp)) {
257                System.out.println ("Wrong response: " + bos.toString());
258                return false;
259            }
260        } catch (IOException e) {
261            System.out.println (e);
262            return false;
263        }
264        return true;
265    }
266}
267