1 /*
2  * Copyright (c) 2006, 2019, 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 6361557
27  * @run main/othervm B6361557
28  * @summary  Lightweight HTTP server quickly runs out of file descriptors on Linux
29  */
30 
31 import com.sun.net.httpserver.*;
32 
33 import java.util.*;
34 import java.util.concurrent.*;
35 import java.io.*;
36 import java.nio.*;
37 import java.nio.channels.*;
38 import java.net.*;
39 
40 /**
41  * The test simply opens 1,000 separate connections
42  * and invokes one http request on each. The client does
43  * not close any sockets until after they are closed
44  * by the server. This verifies the basic ability
45  * of the server to manage a reasonable number of connections
46  */
47 public class B6361557 {
48 
49     public static boolean error = false;
50     static final int NUM = 1000;
51 
52     static class Handler implements HttpHandler {
53         int invocation = 1;
handle(HttpExchange t)54         public void handle (HttpExchange t)
55             throws IOException
56         {
57             InputStream is = t.getRequestBody();
58             Headers map = t.getRequestHeaders();
59             Headers rmap = t.getResponseHeaders();
60             while (is.read () != -1) ;
61             is.close();
62             t.sendResponseHeaders (200, -1);
63             t.close();
64         }
65     }
66 
67     final static String request = "GET /test/foo.html HTTP/1.1\r\nContent-length: 0\r\n\r\n";
68     final static ByteBuffer requestBuf = ByteBuffer.allocate(64).put(request.getBytes());
69 
main(String[] args)70     public static void main (String[] args) throws Exception {
71         Handler handler = new Handler();
72         InetAddress loopback = InetAddress.getLoopbackAddress();
73         InetSocketAddress addr = new InetSocketAddress (loopback, 0);
74         HttpServer server = HttpServer.create (addr, 0);
75         HttpContext ctx = server.createContext ("/test", handler);
76 
77         ExecutorService executor = Executors.newCachedThreadPool();
78         server.setExecutor (executor);
79         server.start ();
80 
81         InetSocketAddress destaddr = new InetSocketAddress (
82                 loopback, server.getAddress().getPort()
83         );
84         System.out.println ("destaddr " + destaddr);
85 
86         Selector selector = Selector.open ();
87         int requests = 0;
88         int responses = 0;
89         while (true) {
90             // we need to read responses from time to time: slightly
91             // increase the timeout with the amount of pending responses
92             // to give a chance to the server to reply.
93             int selres = selector.select (requests - responses + 1);
94             Set<SelectionKey> selkeys = selector.selectedKeys();
95             for (SelectionKey key : selkeys) {
96                 if (key.isReadable()) {
97                     SocketChannel chan = (SocketChannel)key.channel();
98                     ByteBuffer buf = (ByteBuffer)key.attachment();
99                     try {
100                         int x = chan.read(buf);
101                         if (x == -1 || responseComplete(buf)) {
102                             System.out.print("_");
103                             key.attach(null);
104                             chan.close();
105                             responses++;
106                         }
107                     } catch (IOException e) {
108                         System.out.println(e);
109                     }
110                 }
111             }
112             if (requests < NUM) {
113                 System.out.print(".");
114                 SocketChannel schan = SocketChannel.open(destaddr);
115                 requestBuf.rewind();
116                 int c = 0;
117                 while (requestBuf.remaining() > 0) {
118                     c += schan.write(requestBuf);
119                 }
120                 schan.configureBlocking(false);
121                 schan.register(selector, SelectionKey.OP_READ, ByteBuffer.allocate(100));
122                 requests++;
123             }
124             if (responses == NUM) {
125                 System.out.println ("Finished clients");
126                 break;
127             }
128         }
129         server.stop (1);
130         selector.close();
131         executor.shutdown ();
132 
133     }
134 
135     /* Look for CR LF CR LF */
responseComplete(ByteBuffer buf)136     static boolean responseComplete(ByteBuffer buf) {
137         int pos = buf.position();
138         buf.flip();
139         byte[] lookingFor = new byte[] {'\r', '\n', '\r', '\n' };
140         int lookingForCount = 0;
141         while (buf.hasRemaining()) {
142             byte b = buf.get();
143             if (b == lookingFor[lookingForCount]) {
144                 lookingForCount++;
145                 if (lookingForCount == 4) {
146                     return true;
147                 }
148             } else {
149                 lookingForCount = 0;
150             }
151         }
152         buf.position(pos);
153         buf.limit(buf.capacity());
154         return false;
155     }
156 }
157