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