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 /* 25 * @test 26 * @bug 8087112 27 * @library /lib/testlibrary server 28 * @build jdk.testlibrary.SimpleSSLContext 29 * @modules java.base/sun.net.www.http 30 * jdk.incubator.httpclient/jdk.incubator.http.internal.common 31 * jdk.incubator.httpclient/jdk.incubator.http.internal.frame 32 * jdk.incubator.httpclient/jdk.incubator.http.internal.hpack 33 * @run testng/othervm -Djdk.httpclient.HttpClient.log=ssl,requests,responses,errors BasicTest 34 */ 35 36 import java.io.IOException; 37 import java.net.*; 38 import jdk.incubator.http.*; 39 import static jdk.incubator.http.HttpClient.Version.HTTP_2; 40 import javax.net.ssl.*; 41 import java.nio.file.*; 42 import java.util.concurrent.*; 43 import java.util.concurrent.atomic.AtomicReference; 44 import java.util.Collections; 45 import java.util.LinkedList; 46 import java.util.List; 47 import jdk.testlibrary.SimpleSSLContext; 48 import static jdk.incubator.http.HttpRequest.BodyPublisher.fromFile; 49 import static jdk.incubator.http.HttpRequest.BodyPublisher.fromString; 50 import static jdk.incubator.http.HttpResponse.BodyHandler.asFile; 51 import static jdk.incubator.http.HttpResponse.BodyHandler.asString; 52 53 import org.testng.annotations.Test; 54 55 @Test 56 public class BasicTest { 57 static int httpPort, httpsPort; 58 static Http2TestServer httpServer, httpsServer; 59 static HttpClient client = null; 60 static ExecutorService clientExec; 61 static ExecutorService serverExec; 62 static SSLContext sslContext; 63 64 static String pingURIString, httpURIString, httpsURIString; 65 66 static void initialize() throws Exception { 67 try { 68 SimpleSSLContext sslct = new SimpleSSLContext(); 69 sslContext = sslct.get(); 70 client = getClient(); 71 httpServer = new Http2TestServer(false, 0, serverExec, sslContext); 72 httpServer.addHandler(new Http2EchoHandler(), "/"); 73 httpServer.addHandler(new EchoWithPingHandler(), "/ping"); 74 httpPort = httpServer.getAddress().getPort(); 75 76 httpsServer = new Http2TestServer(true, 0, serverExec, sslContext); 77 httpsServer.addHandler(new Http2EchoHandler(), "/"); 78 79 httpsPort = httpsServer.getAddress().getPort(); 80 httpURIString = "http://127.0.0.1:" + httpPort + "/foo/"; 81 pingURIString = "http://127.0.0.1:" + httpPort + "/ping/"; 82 httpsURIString = "https://127.0.0.1:" + httpsPort + "/bar/"; 83 84 httpServer.start(); 85 httpsServer.start(); 86 } catch (Throwable e) { 87 System.err.println("Throwing now"); 88 e.printStackTrace(); 89 throw e; 90 } 91 } 92 93 static List<CompletableFuture<Long>> cfs = Collections 94 .synchronizedList( new LinkedList<>()); 95 96 static CompletableFuture<Long> currentCF; 97 98 static class EchoWithPingHandler extends Http2EchoHandler { 99 private final Object lock = new Object(); 100 101 @Override 102 public void handle(Http2TestExchange exchange) throws IOException { 103 // for now only one ping active at a time. don't want to saturate 104 synchronized(lock) { 105 CompletableFuture<Long> cf = currentCF; 106 if (cf == null || cf.isDone()) { 107 cf = exchange.sendPing(); 108 assert cf != null; 109 cfs.add(cf); 110 currentCF = cf; 111 } 112 } 113 super.handle(exchange); 114 } 115 } 116 117 @Test 118 public static void test() throws Exception { 119 try { 120 initialize(); 121 simpleTest(false, false); 122 simpleTest(false, true); 123 simpleTest(true, false); 124 streamTest(false); 125 streamTest(true); 126 paramsTest(); 127 CompletableFuture.allOf(cfs.toArray(new CompletableFuture[0])).join(); 128 synchronized (cfs) { 129 for (CompletableFuture<Long> cf : cfs) { 130 System.out.printf("Ping ack received in %d millisec\n", cf.get()); 131 } 132 } 133 } catch (Throwable tt) { 134 System.err.println("tt caught"); 135 tt.printStackTrace(); 136 throw tt; 137 } finally { 138 httpServer.stop(); 139 httpsServer.stop(); 140 //clientExec.shutdown(); 141 } 142 } 143 144 static HttpClient getClient() { 145 if (client == null) { 146 serverExec = Executors.newCachedThreadPool(); 147 clientExec = Executors.newCachedThreadPool(); 148 client = HttpClient.newBuilder() 149 .executor(clientExec) 150 .sslContext(sslContext) 151 .version(HTTP_2) 152 .build(); 153 } 154 return client; 155 } 156 157 static URI getURI(boolean secure) { 158 return getURI(secure, false); 159 } 160 161 static URI getURI(boolean secure, boolean ping) { 162 if (secure) 163 return URI.create(httpsURIString); 164 else 165 return URI.create(ping ? pingURIString: httpURIString); 166 } 167 168 static void checkStatus(int expected, int found) throws Exception { 169 if (expected != found) { 170 System.err.printf ("Test failed: wrong status code %d/%d\n", 171 expected, found); 172 throw new RuntimeException("Test failed"); 173 } 174 } 175 176 static void checkStrings(String expected, String found) throws Exception { 177 if (!expected.equals(found)) { 178 System.err.printf ("Test failed: wrong string %s/%s\n", 179 expected, found); 180 throw new RuntimeException("Test failed"); 181 } 182 } 183 184 static Void compareFiles(Path path1, Path path2) { 185 return TestUtil.compareFiles(path1, path2); 186 } 187 188 static Path tempFile() { 189 return TestUtil.tempFile(); 190 } 191 192 static final String SIMPLE_STRING = "Hello world Goodbye world"; 193 194 static final int LOOPS = 13; 195 static final int FILESIZE = 64 * 1024 + 200; 196 197 static void streamTest(boolean secure) throws Exception { 198 URI uri = getURI(secure); 199 System.err.printf("streamTest %b to %s\n" , secure, uri); 200 201 HttpClient client = getClient(); 202 Path src = TestUtil.getAFile(FILESIZE * 4); 203 HttpRequest req = HttpRequest.newBuilder(uri) 204 .POST(fromFile(src)) 205 .build(); 206 207 Path dest = Paths.get("streamtest.txt"); 208 dest.toFile().delete(); 209 CompletableFuture<Path> response = client.sendAsync(req, asFile(dest)) 210 .thenApply(resp -> { 211 if (resp.statusCode() != 200) 212 throw new RuntimeException(); 213 return resp.body(); 214 }); 215 response.join(); 216 compareFiles(src, dest); 217 System.err.println("streamTest: DONE"); 218 } 219 220 static void paramsTest() throws Exception { 221 Http2TestServer server = new Http2TestServer(true, 0, serverExec, sslContext); 222 server.addHandler((t -> { 223 SSLSession s = t.getSSLSession(); 224 String prot = s.getProtocol(); 225 if (prot.equals("TLSv1.2")) { 226 t.sendResponseHeaders(200, -1); 227 } else { 228 System.err.printf("Protocols =%s\n", prot); 229 t.sendResponseHeaders(500, -1); 230 } 231 }), "/"); 232 server.start(); 233 int port = server.getAddress().getPort(); 234 URI u = new URI("https://127.0.0.1:"+port+"/foo"); 235 HttpClient client = getClient(); 236 HttpRequest req = HttpRequest.newBuilder(u).build(); 237 HttpResponse<String> resp = client.send(req, asString()); 238 int stat = resp.statusCode(); 239 if (stat != 200) { 240 throw new RuntimeException("paramsTest failed " 241 + Integer.toString(stat)); 242 } 243 System.err.println("paramsTest: DONE"); 244 } 245 246 static void simpleTest(boolean secure, boolean ping) throws Exception { 247 URI uri = getURI(secure, ping); 248 System.err.println("Request to " + uri); 249 250 // Do a simple warmup request 251 252 HttpClient client = getClient(); 253 HttpRequest req = HttpRequest.newBuilder(uri) 254 .POST(fromString(SIMPLE_STRING)) 255 .build(); 256 HttpResponse<String> response = client.send(req, asString()); 257 HttpHeaders h = response.headers(); 258 259 checkStatus(200, response.statusCode()); 260 261 String responseBody = response.body(); 262 checkStrings(SIMPLE_STRING, responseBody); 263 264 checkStrings(h.firstValue("x-hello").get(), "world"); 265 checkStrings(h.firstValue("x-bye").get(), "universe"); 266 267 // Do loops asynchronously 268 269 CompletableFuture[] responses = new CompletableFuture[LOOPS]; 270 final Path source = TestUtil.getAFile(FILESIZE); 271 HttpRequest request = HttpRequest.newBuilder(uri) 272 .POST(fromFile(source)) 273 .build(); 274 for (int i = 0; i < LOOPS; i++) { 275 responses[i] = client.sendAsync(request, asFile(tempFile())) 276 //.thenApply(resp -> compareFiles(resp.body(), source)); 277 .thenApply(resp -> { 278 System.out.printf("Resp status %d body size %d\n", 279 resp.statusCode(), resp.body().toFile().length()); 280 return compareFiles(resp.body(), source); 281 }); 282 Thread.sleep(100); 283 } 284 CompletableFuture.allOf(responses).join(); 285 System.err.println("simpleTest: DONE"); 286 } 287 }