|
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 8178699 |
|
27 * @modules jdk.incubator.httpclient |
|
28 * java.logging |
|
29 * jdk.httpserver |
|
30 * @library /lib/testlibrary/ / |
|
31 * @build jdk.testlibrary.SimpleSSLContext ProxyServer |
|
32 * @compile ../../../com/sun/net/httpserver/LogFilter.java |
|
33 * @compile ../../../com/sun/net/httpserver/EchoHandler.java |
|
34 * @compile ../../../com/sun/net/httpserver/FileServerHandler.java |
|
35 * @run main/othervm -Djdk.httpclient.HttpClient.log=errors,trace SmokeTest |
|
36 */ |
|
37 |
|
38 import com.sun.net.httpserver.Headers; |
|
39 import com.sun.net.httpserver.HttpContext; |
|
40 import com.sun.net.httpserver.HttpExchange; |
|
41 import com.sun.net.httpserver.HttpHandler; |
|
42 import com.sun.net.httpserver.HttpServer; |
|
43 import com.sun.net.httpserver.HttpsConfigurator; |
|
44 import com.sun.net.httpserver.HttpsParameters; |
|
45 import com.sun.net.httpserver.HttpsServer; |
|
46 import java.util.concurrent.atomic.AtomicInteger; |
|
47 import java.net.InetSocketAddress; |
|
48 import java.net.PasswordAuthentication; |
|
49 import java.net.ProxySelector; |
|
50 import java.net.ServerSocket; |
|
51 import java.net.Socket; |
|
52 import java.net.URI; |
|
53 import jdk.incubator.http.HttpClient; |
|
54 import jdk.incubator.http.HttpRequest; |
|
55 import jdk.incubator.http.HttpResponse; |
|
56 import java.nio.file.StandardOpenOption; |
|
57 import java.io.File; |
|
58 import java.io.FileInputStream; |
|
59 import java.io.FileOutputStream; |
|
60 import java.io.FileNotFoundException; |
|
61 import java.io.IOException; |
|
62 import java.io.BufferedInputStream; |
|
63 import java.io.InputStream; |
|
64 import java.io.OutputStream; |
|
65 import java.io.UncheckedIOException; |
|
66 import java.util.concurrent.BlockingQueue; |
|
67 import java.util.concurrent.CompletableFuture; |
|
68 import java.util.concurrent.CompletionException; |
|
69 import java.util.concurrent.CyclicBarrier; |
|
70 import java.util.concurrent.Executors; |
|
71 import java.util.concurrent.ExecutorService; |
|
72 import java.util.concurrent.LinkedBlockingQueue; |
|
73 import java.util.concurrent.TimeUnit; |
|
74 import javax.net.ssl.SSLContext; |
|
75 import javax.net.ssl.SSLParameters; |
|
76 import java.nio.file.Files; |
|
77 import java.nio.file.Path; |
|
78 import java.nio.file.Paths; |
|
79 import java.util.HashSet; |
|
80 import java.util.LinkedList; |
|
81 import java.util.List; |
|
82 import java.util.Random; |
|
83 import jdk.testlibrary.SimpleSSLContext; |
|
84 import static jdk.incubator.http.HttpRequest.BodyProcessor.fromFile; |
|
85 import static jdk.incubator.http.HttpRequest.BodyProcessor.fromInputStream; |
|
86 import static jdk.incubator.http.HttpRequest.BodyProcessor.fromString; |
|
87 import static jdk.incubator.http.HttpResponse.*; |
|
88 import static jdk.incubator.http.HttpResponse.BodyHandler.asFile; |
|
89 import static jdk.incubator.http.HttpResponse.BodyHandler.asString; |
|
90 import java.util.concurrent.CountDownLatch; |
|
91 import java.util.logging.ConsoleHandler; |
|
92 import java.util.logging.Level; |
|
93 import java.util.logging.Logger; |
|
94 |
|
95 /** |
|
96 * * Basic smoke test for Http/1.1 client |
|
97 * - basic request response |
|
98 * - request body POST |
|
99 * - response body GET |
|
100 * - redirect |
|
101 * - chunked request/response |
|
102 * - SSL |
|
103 * - proxies |
|
104 * - 100 continue |
|
105 * - check keep alive appears to be working |
|
106 * - cancel of long request |
|
107 * |
|
108 * Uses a FileServerHandler serving a couple of known files |
|
109 * in docs directory. |
|
110 */ |
|
111 public class SmokeTest { |
|
112 static SSLContext ctx; |
|
113 static SSLParameters sslparams; |
|
114 static HttpServer s1 ; |
|
115 static HttpsServer s2; |
|
116 static ExecutorService executor; |
|
117 static int port; |
|
118 static int httpsport; |
|
119 static String httproot; |
|
120 static String httpsroot; |
|
121 static HttpClient client; |
|
122 static ProxyServer proxy; |
|
123 static int proxyPort; |
|
124 static RedirectErrorHandler redirectErrorHandler, redirectErrorHandlerSecure; |
|
125 static RedirectHandler redirectHandler, redirectHandlerSecure; |
|
126 static DelayHandler delayHandler; |
|
127 final static String midSizedFilename = "/files/notsobigfile.txt"; |
|
128 final static String smallFilename = "/files/smallfile.txt"; |
|
129 static Path midSizedFile; |
|
130 static Path smallFile; |
|
131 static String fileroot; |
|
132 |
|
133 static String getFileContent(String path) throws IOException { |
|
134 FileInputStream fis = new FileInputStream(path); |
|
135 byte[] buf = new byte[2000]; |
|
136 StringBuilder sb = new StringBuilder(); |
|
137 int n; |
|
138 while ((n=fis.read(buf)) != -1) { |
|
139 sb.append(new String(buf, 0, n, "US-ASCII")); |
|
140 } |
|
141 fis.close(); |
|
142 return sb.toString(); |
|
143 } |
|
144 |
|
145 static void cmpFileContent(Path path1, Path path2) throws IOException { |
|
146 InputStream fis1 = new BufferedInputStream(new FileInputStream(path1.toFile())); |
|
147 InputStream fis2 = new BufferedInputStream(new FileInputStream(path2.toFile())); |
|
148 |
|
149 int n1, n2; |
|
150 while ((n1=fis1.read()) != -1) { |
|
151 n2 = fis2.read(); |
|
152 if (n1 != n2) |
|
153 throw new IOException("Content not the same"); |
|
154 } |
|
155 fis1.close(); |
|
156 fis2.close(); |
|
157 } |
|
158 |
|
159 public static void main(String[] args) throws Exception { |
|
160 initServer(); |
|
161 fileroot = System.getProperty ("test.src", ".")+ "/docs"; |
|
162 midSizedFile = Paths.get(fileroot + midSizedFilename); |
|
163 smallFile = Paths.get(fileroot + smallFilename); |
|
164 ExecutorService e = Executors.newCachedThreadPool(); |
|
165 System.out.println(e); |
|
166 client = HttpClient.newBuilder() |
|
167 .sslContext(ctx) |
|
168 .executor(e) |
|
169 .version(HttpClient.Version.HTTP_1_1) |
|
170 .sslParameters(sslparams) |
|
171 .followRedirects(HttpClient.Redirect.ALWAYS) |
|
172 .build(); |
|
173 |
|
174 try { |
|
175 |
|
176 test1(httproot + "files/foo.txt", true); |
|
177 test1(httproot + "files/foo.txt", false); |
|
178 test1(httpsroot + "files/foo.txt", true); |
|
179 test1(httpsroot + "files/foo.txt", false); |
|
180 |
|
181 test2(httproot + "echo/foo", "This is a short test"); |
|
182 test2(httpsroot + "echo/foo", "This is a short test"); |
|
183 |
|
184 test2a(httproot + "echo/foo"); |
|
185 test2a(httpsroot + "echo/foo"); |
|
186 |
|
187 test3(httproot + "redirect/foo.txt"); |
|
188 test3(httpsroot + "redirect/foo.txt"); |
|
189 |
|
190 test4(httproot + "files/foo.txt"); |
|
191 |
|
192 test4(httpsroot + "files/foo.txt"); |
|
193 |
|
194 test5(httproot + "echo/foo", true); |
|
195 |
|
196 test5(httpsroot + "echo/foo", true); |
|
197 test5(httproot + "echo/foo", false); |
|
198 |
|
199 test5(httpsroot + "echo/foo", false); |
|
200 |
|
201 test6(httproot + "echo/foo", true); |
|
202 test6(httpsroot + "echo/foo", true); |
|
203 test6(httproot + "echo/foo", false); |
|
204 test6(httpsroot + "echo/foo", false); |
|
205 |
|
206 test7(httproot + "keepalive/foo"); |
|
207 /* |
|
208 test10(httproot + "redirecterror/foo.txt"); |
|
209 |
|
210 test10(httpsroot + "redirecterror/foo.txt"); |
|
211 |
|
212 test11(httproot + "echo/foo"); |
|
213 test11(httpsroot + "echo/foo"); |
|
214 */ |
|
215 //test12(httproot + "delay/foo", delayHandler); |
|
216 |
|
217 } finally { |
|
218 s1.stop(0); |
|
219 s2.stop(0); |
|
220 proxy.close(); |
|
221 e.shutdownNow(); |
|
222 executor.shutdownNow(); |
|
223 } |
|
224 } |
|
225 |
|
226 static class Auth extends java.net.Authenticator { |
|
227 volatile int count = 0; |
|
228 @Override |
|
229 protected PasswordAuthentication getPasswordAuthentication() { |
|
230 if (count++ == 0) { |
|
231 return new PasswordAuthentication("user", "passwd".toCharArray()); |
|
232 } else { |
|
233 return new PasswordAuthentication("user", "goober".toCharArray()); |
|
234 } |
|
235 } |
|
236 int count() { |
|
237 return count; |
|
238 } |
|
239 } |
|
240 |
|
241 // Basic test |
|
242 static void test1(String target, boolean fixedLen) throws Exception { |
|
243 System.out.print("test1: " + target); |
|
244 URI uri = new URI(target); |
|
245 |
|
246 HttpRequest.Builder builder = HttpRequest.newBuilder().uri(uri).GET(); |
|
247 |
|
248 if (fixedLen) { |
|
249 builder.header("XFixed", "yes"); |
|
250 } |
|
251 |
|
252 HttpRequest request = builder.build(); |
|
253 |
|
254 HttpResponse<String> response = client.send(request, asString()); |
|
255 |
|
256 String body = response.body(); |
|
257 if (!body.equals("This is foo.txt\r\n")) { |
|
258 throw new RuntimeException(); |
|
259 } |
|
260 |
|
261 // repeat async |
|
262 HttpResponse<String> response1 = client.sendAsync(request, asString()) |
|
263 .join(); |
|
264 |
|
265 String body1 = response1.body(); |
|
266 if (!body1.equals("This is foo.txt\r\n")) { |
|
267 throw new RuntimeException(); |
|
268 } |
|
269 System.out.println(" OK"); |
|
270 } |
|
271 |
|
272 // POST use echo to check reply |
|
273 static void test2(String s, String body) throws Exception { |
|
274 System.out.print("test2: " + s); |
|
275 URI uri = new URI(s); |
|
276 |
|
277 HttpRequest request = HttpRequest.newBuilder(uri) |
|
278 .POST(fromString(body)) |
|
279 .build(); |
|
280 |
|
281 HttpResponse<String> response = client.send(request, asString()); |
|
282 |
|
283 if (response.statusCode() != 200) { |
|
284 throw new RuntimeException( |
|
285 "Expected 200, got [ " + response.statusCode() + " ]"); |
|
286 } |
|
287 String reply = response.body(); |
|
288 if (!reply.equals(body)) { |
|
289 throw new RuntimeException( |
|
290 "Body mismatch: expected [" + body + "], got [" + reply + "]"); |
|
291 } |
|
292 System.out.println(" OK"); |
|
293 } |
|
294 |
|
295 // POST use echo to check reply |
|
296 static void test2a(String s) throws Exception { |
|
297 System.out.print("test2a: " + s); |
|
298 URI uri = new URI(s); |
|
299 Path p = Util.getTempFile(128 * 1024); |
|
300 //Path p = Util.getTempFile(1 * 1024); |
|
301 |
|
302 HttpRequest request = HttpRequest.newBuilder(uri) |
|
303 .POST(fromFile(p)) |
|
304 .build(); |
|
305 |
|
306 Path resp = Util.getTempFile(1); // will be overwritten |
|
307 |
|
308 HttpResponse<Path> response = |
|
309 client.send(request, |
|
310 BodyHandler.asFile(resp, |
|
311 StandardOpenOption.TRUNCATE_EXISTING, |
|
312 StandardOpenOption.WRITE)); |
|
313 |
|
314 if (response.statusCode() != 200) { |
|
315 throw new RuntimeException( |
|
316 "Expected 200, got [ " + response.statusCode() + " ]"); |
|
317 } |
|
318 Path reply = response.body(); |
|
319 //System.out.println("Reply stored in " + reply.toString()); |
|
320 cmpFileContent(reply, p); |
|
321 System.out.println(" OK"); |
|
322 } |
|
323 |
|
324 // Redirect |
|
325 static void test3(String s) throws Exception { |
|
326 System.out.print("test3: " + s); |
|
327 URI uri = new URI(s); |
|
328 RedirectHandler handler = uri.getScheme().equals("https") |
|
329 ? redirectHandlerSecure : redirectHandler; |
|
330 |
|
331 HttpRequest request = HttpRequest.newBuilder() |
|
332 .uri(uri) |
|
333 .GET() |
|
334 .build(); |
|
335 |
|
336 HttpResponse<Path> response = client.send(request, |
|
337 asFile(Paths.get("redir1.txt"))); |
|
338 |
|
339 if (response.statusCode() != 200) { |
|
340 throw new RuntimeException( |
|
341 "Expected 200, got [ " + response.statusCode() + " ]"); |
|
342 } else { |
|
343 response.body(); |
|
344 } |
|
345 |
|
346 Path downloaded = Paths.get("redir1.txt"); |
|
347 if (Files.size(downloaded) != Files.size(midSizedFile)) { |
|
348 throw new RuntimeException("Size mismatch"); |
|
349 } |
|
350 |
|
351 System.out.printf(" (count: %d) ", handler.count()); |
|
352 // repeat with async api |
|
353 |
|
354 handler.reset(); |
|
355 |
|
356 request = HttpRequest.newBuilder(uri).build(); |
|
357 |
|
358 response = client.sendAsync(request, asFile(Paths.get("redir2.txt"))).join(); |
|
359 |
|
360 if (response.statusCode() != 200) { |
|
361 throw new RuntimeException( |
|
362 "Expected 200, got [ " + response.statusCode() + " ]"); |
|
363 } else { |
|
364 response.body(); |
|
365 } |
|
366 |
|
367 downloaded = Paths.get("redir2.txt"); |
|
368 if (Files.size(downloaded) != Files.size(midSizedFile)) { |
|
369 throw new RuntimeException("Size mismatch 2"); |
|
370 } |
|
371 System.out.printf(" (count: %d) ", handler.count()); |
|
372 System.out.println(" OK"); |
|
373 } |
|
374 |
|
375 // Proxies |
|
376 static void test4(String s) throws Exception { |
|
377 System.out.print("test4: " + s); |
|
378 URI uri = new URI(s); |
|
379 InetSocketAddress proxyAddr = new InetSocketAddress("127.0.0.1", proxyPort); |
|
380 String filename = fileroot + uri.getPath(); |
|
381 |
|
382 ExecutorService e = Executors.newCachedThreadPool(); |
|
383 |
|
384 HttpClient cl = HttpClient.newBuilder() |
|
385 .executor(e) |
|
386 .proxy(ProxySelector.of(proxyAddr)) |
|
387 .sslContext(ctx) |
|
388 .sslParameters(sslparams) |
|
389 .build(); |
|
390 |
|
391 HttpRequest request = HttpRequest.newBuilder(uri).GET().build(); |
|
392 |
|
393 CompletableFuture<String> fut = client.sendAsync(request, asString()) |
|
394 .thenApply((response) -> response.body()); |
|
395 |
|
396 String body = fut.get(5, TimeUnit.HOURS); |
|
397 |
|
398 String fc = getFileContent(filename); |
|
399 |
|
400 if (!body.equals(fc)) { |
|
401 throw new RuntimeException( |
|
402 "Body mismatch: expected [" + body + "], got [" + fc + "]"); |
|
403 } |
|
404 e.shutdownNow(); |
|
405 System.out.println(" OK"); |
|
406 } |
|
407 |
|
408 // 100 Continue: use echo target |
|
409 static void test5(String target, boolean fixedLen) throws Exception { |
|
410 System.out.print("test5: " + target); |
|
411 URI uri = new URI(target); |
|
412 String requestBody = generateString(12 * 1024 + 13); |
|
413 |
|
414 HttpRequest.Builder builder = HttpRequest.newBuilder(uri) |
|
415 .expectContinue(true) |
|
416 .POST(fromString(requestBody)); |
|
417 |
|
418 if (fixedLen) { |
|
419 builder.header("XFixed", "yes"); |
|
420 } |
|
421 |
|
422 HttpRequest request = builder.build(); |
|
423 |
|
424 HttpResponse<String> response = client.send(request, asString()); |
|
425 |
|
426 String body = response.body(); |
|
427 |
|
428 if (!body.equals(requestBody)) { |
|
429 throw new RuntimeException( |
|
430 "Body mismatch: expected [" + body + "], got [" + body + "]"); |
|
431 } |
|
432 System.out.println(" OK"); |
|
433 } |
|
434 |
|
435 // use echo |
|
436 static void test6(String target, boolean fixedLen) throws Exception { |
|
437 System.out.print("test6: " + target); |
|
438 URI uri = new URI(target); |
|
439 String requestBody = generateString(12 * 1024 + 3); |
|
440 |
|
441 HttpRequest.Builder builder = HttpRequest.newBuilder(uri).GET(); |
|
442 |
|
443 if (fixedLen) { |
|
444 builder.header("XFixed", "yes"); |
|
445 } |
|
446 |
|
447 HttpRequest request = builder.build(); |
|
448 |
|
449 HttpResponse<String> response = client.send(request, asString()); |
|
450 |
|
451 if (response.statusCode() != 200) { |
|
452 throw new RuntimeException( |
|
453 "Expected 200, got [ " + response.statusCode() + " ]"); |
|
454 } |
|
455 |
|
456 String responseBody = response.body(); |
|
457 |
|
458 if (responseBody.equals(requestBody)) { |
|
459 throw new RuntimeException( |
|
460 "Body mismatch: expected [" + requestBody + "], got [" + responseBody + "]"); |
|
461 } |
|
462 System.out.println(" OK"); |
|
463 } |
|
464 |
|
465 @SuppressWarnings("rawtypes") |
|
466 static void test7(String target) throws Exception { |
|
467 System.out.print("test7: " + target); |
|
468 Path requestBody = Util.getTempFile(128 * 1024); |
|
469 // First test |
|
470 URI uri = new URI(target); |
|
471 HttpRequest request = HttpRequest.newBuilder().uri(uri).GET().build(); |
|
472 |
|
473 for (int i=0; i<4; i++) { |
|
474 HttpResponse<String> r = client.send(request, asString()); |
|
475 String body = r.body(); |
|
476 if (!body.equals("OK")) { |
|
477 throw new RuntimeException("Expected OK, got: " + body); |
|
478 } |
|
479 } |
|
480 |
|
481 // Second test: 4 x parallel |
|
482 request = HttpRequest.newBuilder().uri(uri).POST(fromFile(requestBody)).build(); |
|
483 List<CompletableFuture<String>> futures = new LinkedList<>(); |
|
484 for (int i=0; i<4; i++) { |
|
485 futures.add(client.sendAsync(request, asString()) |
|
486 .thenApply((response) -> { |
|
487 if (response.statusCode() == 200) |
|
488 return response.body(); |
|
489 else |
|
490 return "ERROR"; |
|
491 })); |
|
492 } |
|
493 // all sent? |
|
494 CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])) |
|
495 .join(); |
|
496 |
|
497 for (CompletableFuture<String> future : futures) { |
|
498 String body = future.get(); |
|
499 if (!body.equals("OK")) { |
|
500 throw new RuntimeException("Expected OK, got: " + body); |
|
501 } |
|
502 } |
|
503 |
|
504 // Third test: Multiple of 4 parallel requests |
|
505 request = HttpRequest.newBuilder(uri).GET().build(); |
|
506 BlockingQueue<String> q = new LinkedBlockingQueue<>(); |
|
507 for (int i=0; i<4; i++) { |
|
508 client.sendAsync(request, asString()) |
|
509 .thenApply((HttpResponse<String> resp) -> { |
|
510 String body = resp.body(); |
|
511 putQ(q, body); |
|
512 return body; |
|
513 }); |
|
514 } |
|
515 // we've sent four requests. Now, just send another request |
|
516 // as each response is received. The idea is to ensure that |
|
517 // only four sockets ever get used. |
|
518 |
|
519 for (int i=0; i<100; i++) { |
|
520 // block until response received |
|
521 String body = takeQ(q); |
|
522 if (!body.equals("OK")) { |
|
523 throw new RuntimeException(body); |
|
524 } |
|
525 client.sendAsync(request, asString()) |
|
526 .thenApply((resp) -> { |
|
527 if (resp.statusCode() == 200) |
|
528 putQ(q, resp.body()); |
|
529 else |
|
530 putQ(q, "ERROR"); |
|
531 return null; |
|
532 }); |
|
533 } |
|
534 // should be four left |
|
535 for (int i=0; i<4; i++) { |
|
536 takeQ(q); |
|
537 } |
|
538 System.out.println(" OK"); |
|
539 } |
|
540 |
|
541 static String takeQ(BlockingQueue<String> q) { |
|
542 String r = null; |
|
543 try { |
|
544 r = q.take(); |
|
545 } catch (InterruptedException e) {} |
|
546 |
|
547 return r; |
|
548 } |
|
549 |
|
550 static void putQ(BlockingQueue<String> q, String o) { |
|
551 try { |
|
552 q.put(o); |
|
553 } catch (InterruptedException e) { |
|
554 // can't happen |
|
555 } |
|
556 } |
|
557 |
|
558 static FileInputStream newStream() { |
|
559 try { |
|
560 return new FileInputStream(smallFile.toFile()); |
|
561 } catch (FileNotFoundException e) { |
|
562 throw new UncheckedIOException(e); |
|
563 } |
|
564 } |
|
565 // Chunked output stream |
|
566 static void test11(String target) throws Exception { |
|
567 System.out.print("test11: " + target); |
|
568 URI uri = new URI(target); |
|
569 |
|
570 HttpRequest request = HttpRequest.newBuilder(uri) |
|
571 .POST(fromInputStream(SmokeTest::newStream)) |
|
572 .build(); |
|
573 |
|
574 Path download = Paths.get("test11.txt"); |
|
575 |
|
576 HttpResponse<Path> response = client.send(request, asFile(download)); |
|
577 |
|
578 if (response.statusCode() != 200) { |
|
579 throw new RuntimeException("Wrong response code"); |
|
580 } |
|
581 |
|
582 download.toFile().delete(); |
|
583 response.body(); |
|
584 |
|
585 if (Files.size(download) != Files.size(smallFile)) { |
|
586 System.out.println("Original size: " + Files.size(smallFile)); |
|
587 System.out.println("Downloaded size: " + Files.size(download)); |
|
588 throw new RuntimeException("Size mismatch"); |
|
589 } |
|
590 System.out.println(" OK"); |
|
591 } |
|
592 |
|
593 static void delay(int seconds) { |
|
594 try { |
|
595 Thread.sleep(seconds * 1000); |
|
596 } catch (InterruptedException e) { |
|
597 } |
|
598 } |
|
599 |
|
600 // Redirect loop: return an error after a certain number of redirects |
|
601 static void test10(String s) throws Exception { |
|
602 System.out.print("test10: " + s); |
|
603 URI uri = new URI(s); |
|
604 RedirectErrorHandler handler = uri.getScheme().equals("https") |
|
605 ? redirectErrorHandlerSecure : redirectErrorHandler; |
|
606 |
|
607 HttpRequest request = HttpRequest.newBuilder(uri).GET().build(); |
|
608 CompletableFuture<HttpResponse<String>> cf = |
|
609 client.sendAsync(request, asString()); |
|
610 |
|
611 try { |
|
612 HttpResponse<String> response = cf.join(); |
|
613 throw new RuntimeException("Exepected Completion Exception"); |
|
614 } catch (CompletionException e) { |
|
615 //System.out.println(e); |
|
616 } |
|
617 |
|
618 System.out.printf(" (Calls %d) ", handler.count()); |
|
619 System.out.println(" OK"); |
|
620 } |
|
621 |
|
622 static final int NUM = 50; |
|
623 |
|
624 static Random random = new Random(); |
|
625 static final String alphabet = "ABCDEFGHIJKLMNOPQRST"; |
|
626 |
|
627 static char randomChar() { |
|
628 return alphabet.charAt(random.nextInt(alphabet.length())); |
|
629 } |
|
630 |
|
631 static String generateString(int length) { |
|
632 StringBuilder sb = new StringBuilder(length); |
|
633 for (int i=0; i<length; i++) { |
|
634 sb.append(randomChar()); |
|
635 } |
|
636 return sb.toString(); |
|
637 } |
|
638 |
|
639 static void initServer() throws Exception { |
|
640 |
|
641 Logger logger = Logger.getLogger("com.sun.net.httpserver"); |
|
642 ConsoleHandler ch = new ConsoleHandler(); |
|
643 logger.setLevel(Level.SEVERE); |
|
644 ch.setLevel(Level.SEVERE); |
|
645 logger.addHandler(ch); |
|
646 |
|
647 String root = System.getProperty ("test.src")+ "/docs"; |
|
648 InetSocketAddress addr = new InetSocketAddress (0); |
|
649 s1 = HttpServer.create (addr, 0); |
|
650 if (s1 instanceof HttpsServer) { |
|
651 throw new RuntimeException ("should not be httpsserver"); |
|
652 } |
|
653 s2 = HttpsServer.create (addr, 0); |
|
654 HttpHandler h = new FileServerHandler(root); |
|
655 |
|
656 HttpContext c1 = s1.createContext("/files", h); |
|
657 HttpContext c2 = s2.createContext("/files", h); |
|
658 HttpContext c3 = s1.createContext("/echo", new EchoHandler()); |
|
659 redirectHandler = new RedirectHandler("/redirect"); |
|
660 redirectHandlerSecure = new RedirectHandler("/redirect"); |
|
661 HttpContext c4 = s1.createContext("/redirect", redirectHandler); |
|
662 HttpContext c41 = s2.createContext("/redirect", redirectHandlerSecure); |
|
663 HttpContext c5 = s2.createContext("/echo", new EchoHandler()); |
|
664 HttpContext c6 = s1.createContext("/keepalive", new KeepAliveHandler()); |
|
665 redirectErrorHandler = new RedirectErrorHandler("/redirecterror"); |
|
666 redirectErrorHandlerSecure = new RedirectErrorHandler("/redirecterror"); |
|
667 HttpContext c7 = s1.createContext("/redirecterror", redirectErrorHandler); |
|
668 HttpContext c71 = s2.createContext("/redirecterror", redirectErrorHandlerSecure); |
|
669 delayHandler = new DelayHandler(); |
|
670 HttpContext c8 = s1.createContext("/delay", delayHandler); |
|
671 HttpContext c81 = s2.createContext("/delay", delayHandler); |
|
672 |
|
673 executor = Executors.newCachedThreadPool(); |
|
674 s1.setExecutor(executor); |
|
675 s2.setExecutor(executor); |
|
676 ctx = new SimpleSSLContext().get(); |
|
677 sslparams = ctx.getSupportedSSLParameters(); |
|
678 s2.setHttpsConfigurator(new Configurator(ctx)); |
|
679 s1.start(); |
|
680 s2.start(); |
|
681 |
|
682 port = s1.getAddress().getPort(); |
|
683 System.out.println("HTTP server port = " + port); |
|
684 httpsport = s2.getAddress().getPort(); |
|
685 System.out.println("HTTPS server port = " + httpsport); |
|
686 httproot = "http://127.0.0.1:" + port + "/"; |
|
687 httpsroot = "https://127.0.0.1:" + httpsport + "/"; |
|
688 |
|
689 proxy = new ProxyServer(0, false); |
|
690 proxyPort = proxy.getPort(); |
|
691 System.out.println("Proxy port = " + proxyPort); |
|
692 } |
|
693 } |
|
694 |
|
695 class Configurator extends HttpsConfigurator { |
|
696 public Configurator(SSLContext ctx) { |
|
697 super(ctx); |
|
698 } |
|
699 |
|
700 public void configure (HttpsParameters params) { |
|
701 params.setSSLParameters (getSSLContext().getSupportedSSLParameters()); |
|
702 } |
|
703 } |
|
704 |
|
705 class UploadServer extends Thread { |
|
706 int statusCode; |
|
707 ServerSocket ss; |
|
708 int port; |
|
709 int size; |
|
710 Object lock; |
|
711 boolean failed = false; |
|
712 |
|
713 UploadServer(int size) throws IOException { |
|
714 this.statusCode = statusCode; |
|
715 this.size = size; |
|
716 ss = new ServerSocket(0); |
|
717 port = ss.getLocalPort(); |
|
718 lock = new Object(); |
|
719 } |
|
720 |
|
721 int port() { |
|
722 return port; |
|
723 } |
|
724 |
|
725 int size() { |
|
726 return size; |
|
727 } |
|
728 |
|
729 // wait a sec before calling this |
|
730 boolean failed() { |
|
731 synchronized(lock) { |
|
732 return failed; |
|
733 } |
|
734 } |
|
735 |
|
736 @Override |
|
737 public void run () { |
|
738 int nbytes = 0; |
|
739 Socket s = null; |
|
740 |
|
741 synchronized(lock) { |
|
742 try { |
|
743 s = ss.accept(); |
|
744 |
|
745 InputStream is = s.getInputStream(); |
|
746 OutputStream os = s.getOutputStream(); |
|
747 os.write("HTTP/1.1 201 OK\r\nContent-length: 0\r\n\r\n".getBytes()); |
|
748 int n; |
|
749 byte[] buf = new byte[8000]; |
|
750 while ((n=is.read(buf)) != -1) { |
|
751 nbytes += n; |
|
752 } |
|
753 } catch (IOException e) { |
|
754 System.out.println ("read " + nbytes); |
|
755 System.out.println ("size " + size); |
|
756 failed = nbytes >= size; |
|
757 } finally { |
|
758 try { |
|
759 ss.close(); |
|
760 if (s != null) |
|
761 s.close(); |
|
762 } catch (IOException e) {} |
|
763 } |
|
764 } |
|
765 } |
|
766 } |
|
767 |
|
768 class RedirectHandler implements HttpHandler { |
|
769 String root; |
|
770 volatile int count = 0; |
|
771 |
|
772 RedirectHandler(String root) { |
|
773 this.root = root; |
|
774 } |
|
775 |
|
776 @Override |
|
777 public synchronized void handle(HttpExchange t) |
|
778 throws IOException |
|
779 { |
|
780 byte[] buf = new byte[2048]; |
|
781 try (InputStream is = t.getRequestBody()) { |
|
782 while (is.read(buf) != -1) ; |
|
783 } |
|
784 |
|
785 Headers responseHeaders = t.getResponseHeaders(); |
|
786 |
|
787 if (count++ < 1) { |
|
788 responseHeaders.add("Location", root + "/foo/" + count); |
|
789 } else { |
|
790 responseHeaders.add("Location", SmokeTest.midSizedFilename); |
|
791 } |
|
792 t.sendResponseHeaders(301, -1); |
|
793 t.close(); |
|
794 } |
|
795 |
|
796 int count() { |
|
797 return count; |
|
798 } |
|
799 |
|
800 void reset() { |
|
801 count = 0; |
|
802 } |
|
803 } |
|
804 |
|
805 class RedirectErrorHandler implements HttpHandler { |
|
806 String root; |
|
807 volatile int count = 1; |
|
808 |
|
809 RedirectErrorHandler(String root) { |
|
810 this.root = root; |
|
811 } |
|
812 |
|
813 synchronized int count() { |
|
814 return count; |
|
815 } |
|
816 |
|
817 synchronized void increment() { |
|
818 count++; |
|
819 } |
|
820 |
|
821 @Override |
|
822 public synchronized void handle (HttpExchange t) |
|
823 throws IOException |
|
824 { |
|
825 byte[] buf = new byte[2048]; |
|
826 try (InputStream is = t.getRequestBody()) { |
|
827 while (is.read(buf) != -1) ; |
|
828 } |
|
829 |
|
830 Headers map = t.getResponseHeaders(); |
|
831 String redirect = root + "/foo/" + Integer.toString(count); |
|
832 increment(); |
|
833 map.add("Location", redirect); |
|
834 t.sendResponseHeaders(301, -1); |
|
835 t.close(); |
|
836 } |
|
837 } |
|
838 |
|
839 class Util { |
|
840 static byte[] readAll(InputStream is) throws IOException { |
|
841 byte[] buf = new byte[1024]; |
|
842 byte[] result = new byte[0]; |
|
843 |
|
844 while (true) { |
|
845 int n = is.read(buf); |
|
846 if (n > 0) { |
|
847 byte[] b1 = new byte[result.length + n]; |
|
848 System.arraycopy(result, 0, b1, 0, result.length); |
|
849 System.arraycopy(buf, 0, b1, result.length, n); |
|
850 result = b1; |
|
851 } else if (n == -1) { |
|
852 return result; |
|
853 } |
|
854 } |
|
855 } |
|
856 |
|
857 static Path getTempFile(int size) throws IOException { |
|
858 File f = File.createTempFile("test", "txt"); |
|
859 f.deleteOnExit(); |
|
860 byte[] buf = new byte[2048]; |
|
861 for (int i=0; i<buf.length; i++) |
|
862 buf[i] = (byte)i; |
|
863 |
|
864 FileOutputStream fos = new FileOutputStream(f); |
|
865 while (size > 0) { |
|
866 int amount = Math.min(size, buf.length); |
|
867 fos.write(buf, 0, amount); |
|
868 size -= amount; |
|
869 } |
|
870 fos.close(); |
|
871 return f.toPath(); |
|
872 } |
|
873 } |
|
874 |
|
875 class DelayHandler implements HttpHandler { |
|
876 |
|
877 CyclicBarrier bar1 = new CyclicBarrier(2); |
|
878 CyclicBarrier bar2 = new CyclicBarrier(2); |
|
879 CyclicBarrier bar3 = new CyclicBarrier(2); |
|
880 |
|
881 CyclicBarrier barrier1() { |
|
882 return bar1; |
|
883 } |
|
884 |
|
885 CyclicBarrier barrier2() { |
|
886 return bar2; |
|
887 } |
|
888 |
|
889 @Override |
|
890 public synchronized void handle(HttpExchange he) throws IOException { |
|
891 byte[] buf = Util.readAll(he.getRequestBody()); |
|
892 try { |
|
893 bar1.await(); |
|
894 bar2.await(); |
|
895 } catch (Exception e) {} |
|
896 he.sendResponseHeaders(200, -1); // will probably fail |
|
897 he.close(); |
|
898 } |
|
899 |
|
900 } |
|
901 |
|
902 // check for simple hardcoded sequence and use remote address |
|
903 // to check. |
|
904 // First 4 requests executed in sequence (should use same connection/address) |
|
905 // Next 4 requests parallel (should use different addresses) |
|
906 // Then send 4 requests in parallel x 100 times (same four addresses used all time) |
|
907 |
|
908 class KeepAliveHandler implements HttpHandler { |
|
909 AtomicInteger counter = new AtomicInteger(0); |
|
910 AtomicInteger nparallel = new AtomicInteger(0); |
|
911 |
|
912 HashSet<Integer> portSet = new HashSet<>(); |
|
913 |
|
914 int[] ports = new int[8]; |
|
915 |
|
916 void sleep(int n) { |
|
917 try { |
|
918 Thread.sleep(n); |
|
919 } catch (InterruptedException e) {} |
|
920 } |
|
921 |
|
922 synchronized void setPort(int index, int value) { |
|
923 ports[index] = value; |
|
924 } |
|
925 |
|
926 synchronized int getPort(int index) { |
|
927 return ports[index]; |
|
928 } |
|
929 |
|
930 synchronized void getPorts(int[] dest, int from) { |
|
931 dest[0] = ports[from+0]; |
|
932 dest[1] = ports[from+1]; |
|
933 dest[2] = ports[from+2]; |
|
934 dest[3] = ports[from+3]; |
|
935 } |
|
936 |
|
937 static CountDownLatch latch = new CountDownLatch(4); |
|
938 |
|
939 @Override |
|
940 public void handle (HttpExchange t) |
|
941 throws IOException |
|
942 { |
|
943 int np = nparallel.incrementAndGet(); |
|
944 int remotePort = t.getRemoteAddress().getPort(); |
|
945 String result = "OK"; |
|
946 int[] lports = new int[4]; |
|
947 |
|
948 int n = counter.getAndIncrement(); |
|
949 |
|
950 /// First test |
|
951 if (n < 4) { |
|
952 setPort(n, remotePort); |
|
953 } |
|
954 if (n == 3) { |
|
955 getPorts(lports, 0); |
|
956 // check all values in ports[] are the same |
|
957 if (lports[0] != lports[1] || lports[2] != lports[3] |
|
958 || lports[0] != lports[2]) { |
|
959 result = "Error " + Integer.toString(n); |
|
960 System.out.println(result); |
|
961 } |
|
962 } |
|
963 // Second test |
|
964 if (n >=4 && n < 8) { |
|
965 // delay so that this connection doesn't get reused |
|
966 // before all 4 requests sent |
|
967 setPort(n, remotePort); |
|
968 latch.countDown(); |
|
969 try {latch.await();} catch (InterruptedException e) {} |
|
970 } |
|
971 if (n == 7) { |
|
972 getPorts(lports, 4); |
|
973 // should be all different |
|
974 if (lports[0] == lports[1] || lports[2] == lports[3] |
|
975 || lports[0] == lports[2]) { |
|
976 result = "Error " + Integer.toString(n); |
|
977 System.out.println(result); |
|
978 } |
|
979 // setup for third test |
|
980 for (int i=0; i<4; i++) { |
|
981 portSet.add(lports[i]); |
|
982 } |
|
983 System.out.printf("Ports: %d, %d, %d, %d\n", lports[0], lports[1], lports[2], lports[3]); |
|
984 } |
|
985 // Third test |
|
986 if (n > 7) { |
|
987 if (np > 4) { |
|
988 System.err.println("XXX np = " + np); |
|
989 } |
|
990 // just check that port is one of the ones in portSet |
|
991 if (!portSet.contains(remotePort)) { |
|
992 System.out.println ("UNEXPECTED REMOTE PORT " + remotePort); |
|
993 result = "Error " + Integer.toString(n); |
|
994 System.out.println(result); |
|
995 } |
|
996 } |
|
997 byte[] buf = new byte[2048]; |
|
998 |
|
999 try (InputStream is = t.getRequestBody()) { |
|
1000 while (is.read(buf) != -1) ; |
|
1001 } |
|
1002 t.sendResponseHeaders(200, result.length()); |
|
1003 OutputStream o = t.getResponseBody(); |
|
1004 o.write(result.getBytes("US-ASCII")); |
|
1005 t.close(); |
|
1006 nparallel.getAndDecrement(); |
|
1007 } |
|
1008 } |