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
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
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
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();
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);
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) {}
|
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.internal.httpclient.debug=true -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.net.Proxy;
47 import java.net.SocketAddress;
48 import java.util.concurrent.atomic.AtomicInteger;
49 import java.net.InetSocketAddress;
50 import java.net.PasswordAuthentication;
51 import java.net.ProxySelector;
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.BodyPublisher.fromFile;
85 import static jdk.incubator.http.HttpRequest.BodyPublisher.fromInputStream;
86 import static jdk.incubator.http.HttpRequest.BodyPublisher.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
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 test1(httproot + "files/foo.txt", true);
176 test1(httproot + "files/foo.txt", false);
177 test1(httpsroot + "files/foo.txt", true);
178 test1(httpsroot + "files/foo.txt", false);
179
180 test2(httproot + "echo/foo", "This is a short test");
181 test2(httpsroot + "echo/foo", "This is a short test");
182
183 test2a(httproot + "echo/foo");
184 test2a(httpsroot + "echo/foo");
185
186 test3(httproot + "redirect/foo.txt");
187 test3(httpsroot + "redirect/foo.txt");
188
189 test4(httproot + "files/foo.txt");
190
191 test4(httpsroot + "files/foo.txt");
192
193 test5(httproot + "echo/foo", true);
194
237 }
238 }
239
240 // Basic test
241 static void test1(String target, boolean fixedLen) throws Exception {
242 System.out.print("test1: " + target);
243 URI uri = new URI(target);
244
245 HttpRequest.Builder builder = HttpRequest.newBuilder().uri(uri).GET();
246
247 if (fixedLen) {
248 builder.header("XFixed", "yes");
249 }
250
251 HttpRequest request = builder.build();
252
253 HttpResponse<String> response = client.send(request, asString());
254
255 String body = response.body();
256 if (!body.equals("This is foo.txt\r\n")) {
257 throw new RuntimeException("Did not get expected body: "
258 + "\n\t expected \"This is foo.txt\\r\\n\""
259 + "\n\t received \""
260 + body.replace("\r", "\\r").replace("\n","\\n") + "\"");
261 }
262
263 // repeat async
264 HttpResponse<String> response1 = client.sendAsync(request, asString())
265 .join();
266
267 String body1 = response1.body();
268 if (!body1.equals("This is foo.txt\r\n")) {
269 throw new RuntimeException();
270 }
271 System.out.println(" OK");
272 }
273
274 // POST use echo to check reply
275 static void test2(String s, String body) throws Exception {
276 System.out.print("test2: " + s);
277 URI uri = new URI(s);
278
279 HttpRequest request = HttpRequest.newBuilder(uri)
280 .POST(fromString(body))
281 .build();
282
283 HttpResponse<String> response = client.send(request, asString());
284
285 if (response.statusCode() != 200) {
286 throw new RuntimeException(
287 "Expected 200, got [ " + response.statusCode() + " ]");
288 }
289 String reply = response.body();
290 if (!reply.equals(body)) {
291 throw new RuntimeException(
292 "Body mismatch: expected [" + body + "], got [" + reply + "]");
293 }
294 System.out.println(" OK");
295 }
296
297 // POST use echo to check reply
298 static void test2a(String s) throws Exception {
299 System.out.print("test2a: " + s);
300 URI uri = new URI(s);
301 Path p = getTempFile(128 * 1024);
302
303 HttpRequest request = HttpRequest.newBuilder(uri)
304 .POST(fromFile(p))
305 .build();
306
307 Path resp = getTempFile(1); // will be overwritten
308
309 HttpResponse<Path> response =
310 client.send(request,
311 BodyHandler.asFile(resp,
312 StandardOpenOption.TRUNCATE_EXISTING,
313 StandardOpenOption.WRITE));
314
315 if (response.statusCode() != 200) {
316 throw new RuntimeException(
317 "Expected 200, got [ " + response.statusCode() + " ]");
318 }
319 // no redirection, etc, should be no previous response
320 if (response.previousResponse().isPresent()) {
321 throw new RuntimeException(
322 "Unexpected previous response: " + response.previousResponse().get());
323 }
324 Path reply = response.body();
325 //System.out.println("Reply stored in " + reply.toString());
326 cmpFileContent(reply, p);
327 System.out.println(" OK");
328 }
329
330 // Redirect
331 static void test3(String s) throws Exception {
332 System.out.print("test3: " + s);
333 URI uri = new URI(s);
334 RedirectHandler handler = uri.getScheme().equals("https")
335 ? redirectHandlerSecure : redirectHandler;
336
337 HttpRequest request = HttpRequest.newBuilder()
338 .uri(uri)
339 .GET()
340 .build();
341
342 HttpResponse<Path> response = client.send(request,
343 asFile(Paths.get("redir1.txt")));
344
345 if (response.statusCode() != 200) {
346 throw new RuntimeException(
347 "Expected 200, got [ " + response.statusCode() + " ]");
348 } else {
349 response.body();
350 }
351
352 Path downloaded = Paths.get("redir1.txt");
353 if (Files.size(downloaded) != Files.size(midSizedFile)) {
354 throw new RuntimeException("Size mismatch");
355 }
356 checkPreviousRedirectResponses(request, response);
357 System.out.printf(" (count: %d) ", handler.count());
358 // repeat with async api
359
360 handler.reset();
361
362 request = HttpRequest.newBuilder(uri).build();
363
364 response = client.sendAsync(request, asFile(Paths.get("redir2.txt"))).join();
365
366 if (response.statusCode() != 200) {
367 throw new RuntimeException(
368 "Expected 200, got [ " + response.statusCode() + " ]");
369 } else {
370 response.body();
371 }
372
373 downloaded = Paths.get("redir2.txt");
374 if (Files.size(downloaded) != Files.size(midSizedFile)) {
375 throw new RuntimeException("Size mismatch 2");
376 }
377
378 checkPreviousRedirectResponses(request, response);
379 System.out.printf(" (count: %d) ", handler.count());
380 System.out.println(" OK");
381 }
382
383 static void checkPreviousRedirectResponses(HttpRequest initialRequest,
384 HttpResponse<?> finalResponse) {
385 // there must be at least one previous response
386 finalResponse.previousResponse()
387 .orElseThrow(() -> new RuntimeException("no previous response"));
388
389 HttpResponse<?> response = finalResponse;
390 do {
391 URI uri = response.uri();
392 response = response.previousResponse().get();
393 check(300 <= response.statusCode() && response.statusCode() <= 309,
394 "Expected 300 <= code <= 309, got:" + response.statusCode());
395 check(response.body() == null, "Unexpected body: " + response.body());
396 String locationHeader = response.headers().firstValue("Location")
397 .orElseThrow(() -> new RuntimeException("no previous Location"));
398 check(uri.toString().endsWith(locationHeader),
399 "URI: " + uri + ", Location: " + locationHeader);
400 } while (response.previousResponse().isPresent());
401
402 // initial
403 check(initialRequest.equals(response.request()),
404 "Expected initial request [%s] to equal last prev req [%s]",
405 initialRequest, response.request());
406 }
407
408 static void check(boolean cond, Object... msg) {
409 if (cond)
410 return;
411 StringBuilder sb = new StringBuilder();
412 for (Object o : msg)
413 sb.append(o);
414 throw new RuntimeException(sb.toString());
415 }
416
417 /**
418 * A Proxy Selector that wraps a ProxySelector.of(), and counts the number
419 * of times its select method has been invoked. This can be used to ensure
420 * that the Proxy Selector is invoked only once per HttpClient.sendXXX
421 * invocation.
422 */
423 static class CountingProxySelector extends ProxySelector {
424 private final ProxySelector proxySelector;
425 private volatile int count; // 0
426 private CountingProxySelector(InetSocketAddress proxyAddress) {
427 proxySelector = ProxySelector.of(proxyAddress);
428 }
429
430 public static CountingProxySelector of(InetSocketAddress proxyAddress) {
431 return new CountingProxySelector(proxyAddress);
432 }
433
434 int count() { return count; }
435
436 @Override
437 public List<Proxy> select(URI uri) {
438 count++;
439 return proxySelector.select(uri);
440 }
441
442 @Override
443 public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
444 proxySelector.connectFailed(uri, sa, ioe);
445 }
446 }
447
448 // Proxies
449 static void test4(String s) throws Exception {
450 System.out.print("test4: " + s);
451 URI uri = new URI(s);
452 InetSocketAddress proxyAddr = new InetSocketAddress("127.0.0.1", proxyPort);
453 String filename = fileroot + uri.getPath();
454
455 ExecutorService e = Executors.newCachedThreadPool();
456
457 CountingProxySelector ps = CountingProxySelector.of(proxyAddr);
458 HttpClient cl = HttpClient.newBuilder()
459 .executor(e)
460 .proxy(ps)
461 .sslContext(ctx)
462 .sslParameters(sslparams)
463 .build();
464
465 HttpRequest request = HttpRequest.newBuilder(uri).GET().build();
466
467 CompletableFuture<String> fut = cl.sendAsync(request, asString())
468 .thenApply((response) -> response.body());
469
470 String body = fut.get(5, TimeUnit.HOURS);
471
472 String fc = getFileContent(filename);
473
474 if (!body.equals(fc)) {
475 throw new RuntimeException(
476 "Body mismatch: expected [" + body + "], got [" + fc + "]");
477 }
478 if (ps.count() != 1) {
479 throw new RuntimeException("CountingProxySelector. Expected 1, got " + ps.count());
480 }
481 e.shutdownNow();
482 System.out.println(" OK");
483 }
484
485 // 100 Continue: use echo target
486 static void test5(String target, boolean fixedLen) throws Exception {
487 System.out.print("test5: " + target);
488 URI uri = new URI(target);
489 String requestBody = generateString(12 * 1024 + 13);
490
491 HttpRequest.Builder builder = HttpRequest.newBuilder(uri)
492 .expectContinue(true)
493 .POST(fromString(requestBody));
494
495 if (fixedLen) {
496 builder.header("XFixed", "yes");
497 }
498
499 HttpRequest request = builder.build();
500
525
526 HttpResponse<String> response = client.send(request, asString());
527
528 if (response.statusCode() != 200) {
529 throw new RuntimeException(
530 "Expected 200, got [ " + response.statusCode() + " ]");
531 }
532
533 String responseBody = response.body();
534
535 if (responseBody.equals(requestBody)) {
536 throw new RuntimeException(
537 "Body mismatch: expected [" + requestBody + "], got [" + responseBody + "]");
538 }
539 System.out.println(" OK");
540 }
541
542 @SuppressWarnings("rawtypes")
543 static void test7(String target) throws Exception {
544 System.out.print("test7: " + target);
545 Path requestBody = getTempFile(128 * 1024);
546 // First test
547 URI uri = new URI(target);
548 HttpRequest request = HttpRequest.newBuilder().uri(uri).GET().build();
549
550 for (int i=0; i<4; i++) {
551 HttpResponse<String> r = client.send(request, asString());
552 String body = r.body();
553 if (!body.equals("OK")) {
554 throw new RuntimeException("Expected OK, got: " + body);
555 }
556 }
557
558 // Second test: 4 x parallel
559 request = HttpRequest.newBuilder().uri(uri).POST(fromFile(requestBody)).build();
560 List<CompletableFuture<String>> futures = new LinkedList<>();
561 for (int i=0; i<4; i++) {
562 futures.add(client.sendAsync(request, asString())
563 .thenApply((response) -> {
564 if (response.statusCode() == 200)
565 return response.body();
704 static char randomChar() {
705 return alphabet.charAt(random.nextInt(alphabet.length()));
706 }
707
708 static String generateString(int length) {
709 StringBuilder sb = new StringBuilder(length);
710 for (int i=0; i<length; i++) {
711 sb.append(randomChar());
712 }
713 return sb.toString();
714 }
715
716 static void initServer() throws Exception {
717
718 Logger logger = Logger.getLogger("com.sun.net.httpserver");
719 ConsoleHandler ch = new ConsoleHandler();
720 logger.setLevel(Level.SEVERE);
721 ch.setLevel(Level.SEVERE);
722 logger.addHandler(ch);
723
724 String root = System.getProperty ("test.src", ".")+ "/docs";
725 InetSocketAddress addr = new InetSocketAddress (0);
726 s1 = HttpServer.create (addr, 0);
727 if (s1 instanceof HttpsServer) {
728 throw new RuntimeException ("should not be httpsserver");
729 }
730 s2 = HttpsServer.create (addr, 0);
731 HttpHandler h = new FileServerHandler(root);
732
733 HttpContext c1 = s1.createContext("/files", h);
734 HttpContext c2 = s2.createContext("/files", h);
735 HttpContext c3 = s1.createContext("/echo", new EchoHandler());
736 redirectHandler = new RedirectHandler("/redirect");
737 redirectHandlerSecure = new RedirectHandler("/redirect");
738 HttpContext c4 = s1.createContext("/redirect", redirectHandler);
739 HttpContext c41 = s2.createContext("/redirect", redirectHandlerSecure);
740 HttpContext c5 = s2.createContext("/echo", new EchoHandler());
741 HttpContext c6 = s1.createContext("/keepalive", new KeepAliveHandler());
742 redirectErrorHandler = new RedirectErrorHandler("/redirecterror");
743 redirectErrorHandlerSecure = new RedirectErrorHandler("/redirecterror");
744 HttpContext c7 = s1.createContext("/redirecterror", redirectErrorHandler);
750 executor = Executors.newCachedThreadPool();
751 s1.setExecutor(executor);
752 s2.setExecutor(executor);
753 ctx = new SimpleSSLContext().get();
754 sslparams = ctx.getSupportedSSLParameters();
755 s2.setHttpsConfigurator(new Configurator(ctx));
756 s1.start();
757 s2.start();
758
759 port = s1.getAddress().getPort();
760 System.out.println("HTTP server port = " + port);
761 httpsport = s2.getAddress().getPort();
762 System.out.println("HTTPS server port = " + httpsport);
763 httproot = "http://127.0.0.1:" + port + "/";
764 httpsroot = "https://127.0.0.1:" + httpsport + "/";
765
766 proxy = new ProxyServer(0, false);
767 proxyPort = proxy.getPort();
768 System.out.println("Proxy port = " + proxyPort);
769 }
770
771 static class RedirectHandler implements HttpHandler {
772 private final String root;
773 private volatile int count = 0;
774
775 RedirectHandler(String root) {
776 this.root = root;
777 }
778
779 @Override
780 public synchronized void handle(HttpExchange t) throws IOException {
781 byte[] buf = new byte[2048];
782 try (InputStream is = t.getRequestBody()) {
783 while (is.read(buf) != -1) ;
784 }
785
786 Headers responseHeaders = t.getResponseHeaders();
787
788 if (count++ < 1) {
789 responseHeaders.add("Location", root + "/foo/" + count);
790 } else {
791 responseHeaders.add("Location", SmokeTest.midSizedFilename);
792 }
793 t.sendResponseHeaders(301, 64 * 1024);
794 byte[] bb = new byte[1024];
795 OutputStream os = t.getResponseBody();
796 for (int i=0; i<64; i++) {
797 os.write(bb);
798 }
799 os.close();
800 t.close();
801 }
802
803 int count() {
804 return count;
805 }
806
807 void reset() {
808 count = 0;
809 }
810 }
811
812 static class RedirectErrorHandler implements HttpHandler {
813 private final String root;
814 private volatile int count = 1;
815
816 RedirectErrorHandler(String root) {
817 this.root = root;
818 }
819
820 synchronized int count() {
821 return count;
822 }
823
824 synchronized void increment() {
825 count++;
826 }
827
828 @Override
829 public synchronized void handle(HttpExchange t) throws IOException {
830 try (InputStream is = t.getRequestBody()) {
831 is.readAllBytes();
832 }
833
834 Headers map = t.getResponseHeaders();
835 String redirect = root + "/foo/" + Integer.toString(count);
836 increment();
837 map.add("Location", redirect);
838 t.sendResponseHeaders(301, -1);
839 t.close();
840 }
841 }
842
843 static class DelayHandler implements HttpHandler {
844
845 CyclicBarrier bar1 = new CyclicBarrier(2);
846 CyclicBarrier bar2 = new CyclicBarrier(2);
847 CyclicBarrier bar3 = new CyclicBarrier(2);
848
849 CyclicBarrier barrier1() {
850 return bar1;
851 }
852
853 CyclicBarrier barrier2() {
854 return bar2;
855 }
856
857 @Override
858 public synchronized void handle(HttpExchange he) throws IOException {
859 he.getRequestBody().readAllBytes();
860 try {
861 bar1.await();
862 bar2.await();
863 } catch (Exception e) { }
864 he.sendResponseHeaders(200, -1); // will probably fail
865 he.close();
866 }
867 }
868
869 static class Configurator extends HttpsConfigurator {
870 public Configurator(SSLContext ctx) {
871 super(ctx);
872 }
873
874 public void configure (HttpsParameters params) {
875 params.setSSLParameters (getSSLContext().getSupportedSSLParameters());
876 }
877 }
878
879 static Path getTempFile(int size) throws IOException {
880 File f = File.createTempFile("test", "txt");
881 f.deleteOnExit();
882 byte[] buf = new byte[2048];
883 for (int i = 0; i < buf.length; i++)
884 buf[i] = (byte) i;
885
886 FileOutputStream fos = new FileOutputStream(f);
887 while (size > 0) {
888 int amount = Math.min(size, buf.length);
889 fos.write(buf, 0, amount);
890 size -= amount;
891 }
892 fos.close();
893 return f.toPath();
894 }
895 }
896
897 // check for simple hardcoded sequence and use remote address
898 // to check.
899 // First 4 requests executed in sequence (should use same connection/address)
900 // Next 4 requests parallel (should use different addresses)
901 // Then send 4 requests in parallel x 100 times (same four addresses used all time)
902
903 class KeepAliveHandler implements HttpHandler {
904 AtomicInteger counter = new AtomicInteger(0);
905 AtomicInteger nparallel = new AtomicInteger(0);
906
907 HashSet<Integer> portSet = new HashSet<>();
908
909 int[] ports = new int[8];
910
911 void sleep(int n) {
912 try {
913 Thread.sleep(n);
914 } catch (InterruptedException e) {}
|