1/* 2 * Copyright (c) 2006, 2016, 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 6488669 6595324 6993490 27 * @modules jdk.httpserver 28 * @run main/othervm ChunkedErrorStream 29 * @summary Chunked ErrorStream tests 30 */ 31 32import java.net.*; 33import java.io.*; 34import com.sun.net.httpserver.*; 35 36/** 37 * Part 1: 6488669 38 * 1) Http server that responds with an error code (>=400) 39 * and a chunked response body. It also indicates that 40 * the connection will be closed. 41 * 2) Client sends request to server and tries to 42 * getErrorStream(). Some data must be able to be read 43 * from the errorStream. 44 * 45 * Part 2: 6595324 46 * 1) Http server that responds with an error code (>=400) 47 * and a chunked response body greater than 48 * sun.net.http.errorstream.bufferSize, 4K + 10 bytes. 49 * 2) Client sends request to server and tries to 50 * getErrorStream(). 4K + 10 bytes must be read from 51 * the errorStream. 52 * 53 * Part 3: 6993490 54 * Reuse persistent connection from part 2, the error stream 55 * buffering will have set a reduced timeout on the socket and 56 * tried to reset it to the default, infinity. Client must not 57 * throw a timeout exception. If it does, it indicates that the 58 * default timeout was not reset correctly. 59 * If no timeout exception is thrown, it does not guarantee that 60 * the timeout was reset correctly, as there is a potential race 61 * between the sleeping server and the client thread. Typically, 62 * 1000 millis has been enought to reliable reproduce this problem 63 * since the error stream buffering sets the timeout to 60 millis. 64 */ 65 66public class ChunkedErrorStream 67{ 68 com.sun.net.httpserver.HttpServer httpServer; 69 70 static { 71 // Enable ErrorStream buffering 72 System.getProperties().setProperty("sun.net.http.errorstream.enableBuffering", "true"); 73 74 // No need to set this as 4K is the default 75 // System.getProperties().setProperty("sun.net.http.errorstream.bufferSize", "4096"); 76 } 77 78 public static void main(String[] args) { 79 new ChunkedErrorStream(); 80 } 81 82 public ChunkedErrorStream() { 83 try { 84 startHttpServer(); 85 doClient(); 86 } catch (IOException ioe) { 87 ioe.printStackTrace(); 88 } finally { 89 httpServer.stop(1); 90 } 91 } 92 93 void doClient() { 94 for (int times=0; times<3; times++) { 95 HttpURLConnection uc = null; 96 try { 97 InetSocketAddress address = httpServer.getAddress(); 98 String URLStr = "http://localhost:" + address.getPort() + "/test/"; 99 if (times == 0) { 100 URLStr += "first"; 101 } else { 102 URLStr += "second"; 103 } 104 105 System.out.println("Trying " + URLStr); 106 URL url = new URL(URLStr); 107 uc = (HttpURLConnection)url.openConnection(); 108 uc.getInputStream(); 109 110 throw new RuntimeException("Failed: getInputStream should throw and IOException"); 111 } catch (IOException e) { 112 if (e instanceof SocketTimeoutException) { 113 e.printStackTrace(); 114 throw new RuntimeException("Failed: SocketTimeoutException should not happen"); 115 } 116 117 // This is what we expect to happen. 118 InputStream es = uc.getErrorStream(); 119 byte[] ba = new byte[1024]; 120 int count = 0, ret; 121 try { 122 while ((ret = es.read(ba)) != -1) 123 count += ret; 124 es.close(); 125 } catch (IOException ioe) { 126 ioe.printStackTrace(); 127 } 128 129 if (count == 0) 130 throw new RuntimeException("Failed: ErrorStream returning 0 bytes"); 131 132 if (times >= 1 && count != (4096+10)) 133 throw new RuntimeException("Failed: ErrorStream returning " + count + 134 " bytes. Expecting " + (4096+10)); 135 136 System.out.println("Read " + count + " bytes from the errorStream"); 137 } 138 } 139 } 140 141 /** 142 * Http Server 143 */ 144 void startHttpServer() throws IOException { 145 httpServer = com.sun.net.httpserver.HttpServer.create(new InetSocketAddress(0), 0); 146 147 // create HttpServer context 148 httpServer.createContext("/test/first", new FirstHandler()); 149 httpServer.createContext("/test/second", new SecondHandler()); 150 151 httpServer.start(); 152 } 153 154 class FirstHandler implements HttpHandler { 155 public void handle(HttpExchange t) throws IOException { 156 InputStream is = t.getRequestBody(); 157 byte[] ba = new byte[1024]; 158 while (is.read(ba) != -1); 159 is.close(); 160 161 Headers resHeaders = t.getResponseHeaders(); 162 resHeaders.add("Connection", "close"); 163 t.sendResponseHeaders(404, 0); 164 OutputStream os = t.getResponseBody(); 165 166 // actual data doesn't matter. Just send 2K worth. 167 byte b = 'a'; 168 for (int i=0; i<2048; i++) 169 os.write(b); 170 171 os.close(); 172 t.close(); 173 } 174 } 175 176 static class SecondHandler implements HttpHandler { 177 /* count greater than 0, slow response */ 178 static int count = 0; 179 180 public void handle(HttpExchange t) throws IOException { 181 InputStream is = t.getRequestBody(); 182 byte[] ba = new byte[1024]; 183 while (is.read(ba) != -1); 184 is.close(); 185 186 if (count > 0) { 187 System.out.println("server sleeping..."); 188 try { Thread.sleep(1000); } catch(InterruptedException e) {} 189 } 190 count++; 191 192 t.sendResponseHeaders(404, 0); 193 OutputStream os = t.getResponseBody(); 194 195 // actual data doesn't matter. Just send more than 4K worth 196 byte b = 'a'; 197 for (int i=0; i<(4096+10); i++) 198 os.write(b); 199 200 os.close(); 201 t.close(); 202 } 203 } 204} 205