1 /* 2 * Copyright (c) 2015, 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 import java.io.IOException; 26 import jdk.incubator.http.HttpClient; 27 import jdk.incubator.http.HttpRequest; 28 import jdk.incubator.http.HttpResponse; 29 import java.net.URI; 30 import java.util.concurrent.CompletableFuture; 31 import java.util.concurrent.Executor; 32 import java.util.concurrent.ExecutorService; 33 import static jdk.incubator.http.HttpResponse.BodyHandler.asString; 34 35 /** 36 * @test 37 * @bug 8087112 38 * @key intermittent 39 * @build Server 40 * @run main/othervm -Djava.net.HttpClient.log=all SplitResponse 41 */ 42 43 /** 44 * Similar test to QuickResponses except that each byte of the response 45 * is sent in a separate packet, which tests the stability of the implementation 46 * for receiving unusual packet sizes. 47 */ 48 public class SplitResponse { 49 50 static Server server; 51 52 static String response(String body) { 53 return "HTTP/1.1 200 OK\r\nConnection: Close\r\nContent-length: " 54 + Integer.toString(body.length()) 55 + "\r\n\r\n" + body; 56 } 57 58 static final String responses[] = { 59 "Lorem ipsum", 60 "dolor sit amet", 61 "consectetur adipiscing elit, sed do eiusmod tempor", 62 "quis nostrud exercitation ullamco", 63 "laboris nisi", 64 "ut", 65 "aliquip ex ea commodo consequat." + 66 "Duis aute irure dolor in reprehenderit in voluptate velit esse" + 67 "cillum dolore eu fugiat nulla pariatur.", 68 "Excepteur sint occaecat cupidatat non proident." 69 }; 70 71 public static void main(String[] args) throws Exception { 72 server = new Server(0); 73 URI uri = new URI(server.getURL()); 74 server.start(); 75 76 HttpClient client = HttpClient.newHttpClient(); 77 HttpRequest request = HttpRequest.newBuilder(uri).build(); 78 HttpResponse<String> r; 79 CompletableFuture<HttpResponse<String>> cf1; 80 81 try { 82 for (int i=0; i<responses.length; i++) { 83 cf1 = client.sendAsync(request, asString()); 84 String body = responses[i]; 85 86 Server.Connection c = server.activity(); 87 sendSplitResponse(response(body), c); 88 r = cf1.get(); 89 if (r.statusCode()!= 200) 90 throw new RuntimeException("Failed"); 91 92 String rxbody = r.body(); 93 System.out.println("received " + rxbody); 94 if (!rxbody.equals(body)) 95 throw new RuntimeException("Failed"); 96 c.close(); 97 } 98 } finally { 99 Executor def = client.executor(); 100 if (def instanceof ExecutorService) { 101 ((ExecutorService)def).shutdownNow(); 102 } 103 } 104 System.out.println("OK"); 105 } 106 107 // send the response one byte at a time with a small delay between bytes 108 // to ensure that each byte is read in a separate read 109 static void sendSplitResponse(String s, Server.Connection conn) { 110 System.out.println("Sending: "); 111 Thread t = new Thread(() -> { 112 try { 113 int len = s.length(); 114 for (int i = 0; i < len; i++) { 115 String onechar = s.substring(i, i + 1); 116 conn.send(onechar); 117 Thread.sleep(30); 118 } 119 System.out.println("sent"); 120 } catch (IOException | InterruptedException e) { 121 } 122 }); 123 t.setDaemon(true); 124 t.start(); 125 } 126 } | 1 /* 2 * Copyright (c) 2015, 2017, 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 import java.io.IOException; 25 import java.net.URI; 26 import java.util.concurrent.CompletableFuture; 27 import javax.net.ssl.SSLContext; 28 import javax.net.ServerSocketFactory; 29 import javax.net.ssl.SSLServerSocketFactory; 30 import jdk.incubator.http.HttpClient; 31 import jdk.incubator.http.HttpClient.Version; 32 import jdk.incubator.http.HttpRequest; 33 import jdk.incubator.http.HttpResponse; 34 import jdk.testlibrary.SimpleSSLContext; 35 import static java.lang.System.out; 36 import static java.lang.String.format; 37 import static jdk.incubator.http.HttpResponse.BodyHandler.asString; 38 39 /** 40 * @test 41 * @bug 8087112 42 * @library /lib/testlibrary 43 * @build jdk.testlibrary.SimpleSSLContext 44 * @build MockServer 45 * @run main/othervm -Djdk.internal.httpclient.debug=true -Djdk.httpclient.HttpClient.log=all SplitResponse 46 */ 47 48 /** 49 * Similar test to QuickResponses except that each byte of the response 50 * is sent in a separate packet, which tests the stability of the implementation 51 * for receiving unusual packet sizes. Additionally, tests scenarios there 52 * connections that are retrieved from the connection pool may reach EOF before 53 * being reused. 54 */ 55 public class SplitResponse { 56 57 static String response(String body, boolean serverKeepalive) { 58 StringBuilder sb = new StringBuilder(); 59 sb.append("HTTP/1.1 200 OK\r\n"); 60 if (!serverKeepalive) 61 sb.append("Connection: Close\r\n"); 62 63 sb.append("Content-length: ").append(body.length()).append("\r\n"); 64 sb.append("\r\n"); 65 sb.append(body); 66 return sb.toString(); 67 } 68 69 static final String responses[] = { 70 "Lorem ipsum", 71 "dolor sit amet", 72 "consectetur adipiscing elit, sed do eiusmod tempor", 73 "quis nostrud exercitation ullamco", 74 "laboris nisi", 75 "ut", 76 "aliquip ex ea commodo consequat." + 77 "Duis aute irure dolor in reprehenderit in voluptate velit esse" + 78 "cillum dolore eu fugiat nulla pariatur.", 79 "Excepteur sint occaecat cupidatat non proident." 80 }; 81 82 final ServerSocketFactory factory; 83 final SSLContext context; 84 final boolean useSSL; 85 SplitResponse(boolean useSSL) throws IOException { 86 this.useSSL = useSSL; 87 context = new SimpleSSLContext().get(); 88 SSLContext.setDefault(context); 89 factory = useSSL ? SSLServerSocketFactory.getDefault() 90 : ServerSocketFactory.getDefault(); 91 } 92 93 public HttpClient newHttpClient() { 94 HttpClient client; 95 if (useSSL) { 96 client = HttpClient.newBuilder() 97 .sslContext(context) 98 .build(); 99 } else { 100 client = HttpClient.newHttpClient(); 101 } 102 return client; 103 } 104 105 public static void main(String[] args) throws Exception { 106 boolean useSSL = false; 107 if (args != null && args.length == 1) { 108 useSSL = "SSL".equals(args[0]); 109 } 110 SplitResponse sp = new SplitResponse(useSSL); 111 112 for (Version version : Version.values()) { 113 for (boolean serverKeepalive : new boolean[]{ true, false }) { 114 // Note: the mock server doesn't support Keep-Alive, but 115 // pretending that it might exercises code paths in and out of 116 // the connection pool, and retry logic 117 for (boolean async : new boolean[]{ true, false }) { 118 sp.test(version, serverKeepalive, async); 119 } 120 } 121 } 122 } 123 124 // @Test 125 void test(Version version, boolean serverKeepalive, boolean async) 126 throws Exception 127 { 128 out.println(format("*** version %s, serverKeepAlive: %s, async: %s ***", 129 version, serverKeepalive, async)); 130 MockServer server = new MockServer(0, factory); 131 URI uri = new URI(server.getURL()); 132 out.println("server is: " + uri); 133 server.start(); 134 135 HttpClient client = newHttpClient(); 136 HttpRequest request = HttpRequest.newBuilder(uri).version(version).build(); 137 HttpResponse<String> r; 138 CompletableFuture<HttpResponse<String>> cf1; 139 140 try { 141 for (int i=0; i<responses.length; i++) { 142 out.println("----- iteration " + i + " -----"); 143 String body = responses[i]; 144 Thread t = sendSplitResponse(response(body, serverKeepalive), server); 145 146 if (async) { 147 out.println("send async: " + request); 148 cf1 = client.sendAsync(request, asString()); 149 r = cf1.get(); 150 } else { // sync 151 out.println("send sync: " + request); 152 r = client.send(request, asString()); 153 } 154 155 if (r.statusCode() != 200) 156 throw new RuntimeException("Failed"); 157 158 String rxbody = r.body(); 159 out.println("received " + rxbody); 160 if (!rxbody.equals(body)) 161 throw new RuntimeException(format("Expected:%s, got:%s", body, rxbody)); 162 163 t.join(); 164 conn.close(); 165 } 166 } finally { 167 server.close(); 168 } 169 System.out.println("OK"); 170 } 171 172 // required for cleanup 173 volatile MockServer.Connection conn; 174 175 // Sends the response, mostly, one byte at a time with a small delay 176 // between bytes, to encourage that each byte is read in a separate read 177 Thread sendSplitResponse(String s, MockServer server) { 178 System.out.println("Sending: "); 179 Thread t = new Thread(() -> { 180 System.out.println("Waiting for server to receive headers"); 181 conn = server.activity(); 182 System.out.println("Start sending response"); 183 184 try { 185 int len = s.length(); 186 out.println("sending " + s); 187 for (int i = 0; i < len; i++) { 188 String onechar = s.substring(i, i + 1); 189 conn.send(onechar); 190 Thread.sleep(10); 191 } 192 out.println("sent " + s); 193 } catch (IOException | InterruptedException e) { 194 throw new RuntimeException(e); 195 } 196 }); 197 t.setDaemon(true); 198 t.start(); 199 return t; 200 } 201 } |