--- old/test/jdk/java/net/httpclient/SmokeTest.java 2017-11-30 04:05:03.922729325 -0800 +++ new/test/jdk/java/net/httpclient/SmokeTest.java 2017-11-30 04:05:03.713711056 -0800 @@ -32,7 +32,7 @@ * @compile ../../../com/sun/net/httpserver/LogFilter.java * @compile ../../../com/sun/net/httpserver/EchoHandler.java * @compile ../../../com/sun/net/httpserver/FileServerHandler.java - * @run main/othervm -Djdk.httpclient.HttpClient.log=errors,trace SmokeTest + * @run main/othervm -Djdk.internal.httpclient.debug=true -Djdk.httpclient.HttpClient.log=errors,trace SmokeTest */ import com.sun.net.httpserver.Headers; @@ -43,12 +43,12 @@ import com.sun.net.httpserver.HttpsConfigurator; import com.sun.net.httpserver.HttpsParameters; import com.sun.net.httpserver.HttpsServer; +import java.net.Proxy; +import java.net.SocketAddress; import java.util.concurrent.atomic.AtomicInteger; import java.net.InetSocketAddress; import java.net.PasswordAuthentication; import java.net.ProxySelector; -import java.net.ServerSocket; -import java.net.Socket; import java.net.URI; import jdk.incubator.http.HttpClient; import jdk.incubator.http.HttpRequest; @@ -81,9 +81,9 @@ import java.util.List; import java.util.Random; import jdk.testlibrary.SimpleSSLContext; -import static jdk.incubator.http.HttpRequest.BodyProcessor.fromFile; -import static jdk.incubator.http.HttpRequest.BodyProcessor.fromInputStream; -import static jdk.incubator.http.HttpRequest.BodyProcessor.fromString; +import static jdk.incubator.http.HttpRequest.BodyPublisher.fromFile; +import static jdk.incubator.http.HttpRequest.BodyPublisher.fromInputStream; +import static jdk.incubator.http.HttpRequest.BodyPublisher.fromString; import static jdk.incubator.http.HttpResponse.*; import static jdk.incubator.http.HttpResponse.BodyHandler.asFile; import static jdk.incubator.http.HttpResponse.BodyHandler.asString; @@ -172,7 +172,6 @@ .build(); try { - test1(httproot + "files/foo.txt", true); test1(httproot + "files/foo.txt", false); test1(httpsroot + "files/foo.txt", true); @@ -255,7 +254,10 @@ String body = response.body(); if (!body.equals("This is foo.txt\r\n")) { - throw new RuntimeException(); + throw new RuntimeException("Did not get expected body: " + + "\n\t expected \"This is foo.txt\\r\\n\"" + + "\n\t received \"" + + body.replace("\r", "\\r").replace("\n","\\n") + "\""); } // repeat async @@ -296,14 +298,13 @@ static void test2a(String s) throws Exception { System.out.print("test2a: " + s); URI uri = new URI(s); - Path p = Util.getTempFile(128 * 1024); - //Path p = Util.getTempFile(1 * 1024); + Path p = getTempFile(128 * 1024); HttpRequest request = HttpRequest.newBuilder(uri) .POST(fromFile(p)) .build(); - Path resp = Util.getTempFile(1); // will be overwritten + Path resp = getTempFile(1); // will be overwritten HttpResponse response = client.send(request, @@ -315,6 +316,11 @@ throw new RuntimeException( "Expected 200, got [ " + response.statusCode() + " ]"); } + // no redirection, etc, should be no previous response + if (response.previousResponse().isPresent()) { + throw new RuntimeException( + "Unexpected previous response: " + response.previousResponse().get()); + } Path reply = response.body(); //System.out.println("Reply stored in " + reply.toString()); cmpFileContent(reply, p); @@ -347,7 +353,7 @@ if (Files.size(downloaded) != Files.size(midSizedFile)) { throw new RuntimeException("Size mismatch"); } - + checkPreviousRedirectResponses(request, response); System.out.printf(" (count: %d) ", handler.count()); // repeat with async api @@ -368,10 +374,77 @@ if (Files.size(downloaded) != Files.size(midSizedFile)) { throw new RuntimeException("Size mismatch 2"); } + + checkPreviousRedirectResponses(request, response); System.out.printf(" (count: %d) ", handler.count()); System.out.println(" OK"); } + static void checkPreviousRedirectResponses(HttpRequest initialRequest, + HttpResponse finalResponse) { + // there must be at least one previous response + finalResponse.previousResponse() + .orElseThrow(() -> new RuntimeException("no previous response")); + + HttpResponse response = finalResponse; + do { + URI uri = response.uri(); + response = response.previousResponse().get(); + check(300 <= response.statusCode() && response.statusCode() <= 309, + "Expected 300 <= code <= 309, got:" + response.statusCode()); + check(response.body() == null, "Unexpected body: " + response.body()); + String locationHeader = response.headers().firstValue("Location") + .orElseThrow(() -> new RuntimeException("no previous Location")); + check(uri.toString().endsWith(locationHeader), + "URI: " + uri + ", Location: " + locationHeader); + } while (response.previousResponse().isPresent()); + + // initial + check(initialRequest.equals(response.request()), + "Expected initial request [%s] to equal last prev req [%s]", + initialRequest, response.request()); + } + + static void check(boolean cond, Object... msg) { + if (cond) + return; + StringBuilder sb = new StringBuilder(); + for (Object o : msg) + sb.append(o); + throw new RuntimeException(sb.toString()); + } + + /** + * A Proxy Selector that wraps a ProxySelector.of(), and counts the number + * of times its select method has been invoked. This can be used to ensure + * that the Proxy Selector is invoked only once per HttpClient.sendXXX + * invocation. + */ + static class CountingProxySelector extends ProxySelector { + private final ProxySelector proxySelector; + private volatile int count; // 0 + private CountingProxySelector(InetSocketAddress proxyAddress) { + proxySelector = ProxySelector.of(proxyAddress); + } + + public static CountingProxySelector of(InetSocketAddress proxyAddress) { + return new CountingProxySelector(proxyAddress); + } + + int count() { return count; } + + @Override + public List select(URI uri) { + count++; + return proxySelector.select(uri); + } + + @Override + public void connectFailed(URI uri, SocketAddress sa, IOException ioe) { + proxySelector.connectFailed(uri, sa, ioe); + } + } + // Proxies static void test4(String s) throws Exception { System.out.print("test4: " + s); @@ -381,16 +454,17 @@ ExecutorService e = Executors.newCachedThreadPool(); + CountingProxySelector ps = CountingProxySelector.of(proxyAddr); HttpClient cl = HttpClient.newBuilder() .executor(e) - .proxy(ProxySelector.of(proxyAddr)) + .proxy(ps) .sslContext(ctx) .sslParameters(sslparams) .build(); HttpRequest request = HttpRequest.newBuilder(uri).GET().build(); - CompletableFuture fut = client.sendAsync(request, asString()) + CompletableFuture fut = cl.sendAsync(request, asString()) .thenApply((response) -> response.body()); String body = fut.get(5, TimeUnit.HOURS); @@ -401,6 +475,9 @@ throw new RuntimeException( "Body mismatch: expected [" + body + "], got [" + fc + "]"); } + if (ps.count() != 1) { + throw new RuntimeException("CountingProxySelector. Expected 1, got " + ps.count()); + } e.shutdownNow(); System.out.println(" OK"); } @@ -465,7 +542,7 @@ @SuppressWarnings("rawtypes") static void test7(String target) throws Exception { System.out.print("test7: " + target); - Path requestBody = Util.getTempFile(128 * 1024); + Path requestBody = getTempFile(128 * 1024); // First test URI uri = new URI(target); HttpRequest request = HttpRequest.newBuilder().uri(uri).GET().build(); @@ -644,7 +721,7 @@ ch.setLevel(Level.SEVERE); logger.addHandler(ch); - String root = System.getProperty ("test.src")+ "/docs"; + String root = System.getProperty ("test.src", ".")+ "/docs"; InetSocketAddress addr = new InetSocketAddress (0); s1 = HttpServer.create (addr, 0); if (s1 instanceof HttpsServer) { @@ -690,167 +767,112 @@ proxyPort = proxy.getPort(); System.out.println("Proxy port = " + proxyPort); } -} -class Configurator extends HttpsConfigurator { - public Configurator(SSLContext ctx) { - super(ctx); - } + static class RedirectHandler implements HttpHandler { + private final String root; + private volatile int count = 0; - public void configure (HttpsParameters params) { - params.setSSLParameters (getSSLContext().getSupportedSSLParameters()); - } -} + RedirectHandler(String root) { + this.root = root; + } -class UploadServer extends Thread { - int statusCode; - ServerSocket ss; - int port; - int size; - Object lock; - boolean failed = false; + @Override + public synchronized void handle(HttpExchange t) throws IOException { + byte[] buf = new byte[2048]; + try (InputStream is = t.getRequestBody()) { + while (is.read(buf) != -1) ; + } - UploadServer(int size) throws IOException { - this.statusCode = statusCode; - this.size = size; - ss = new ServerSocket(0); - port = ss.getLocalPort(); - lock = new Object(); - } + Headers responseHeaders = t.getResponseHeaders(); - int port() { - return port; - } + if (count++ < 1) { + responseHeaders.add("Location", root + "/foo/" + count); + } else { + responseHeaders.add("Location", SmokeTest.midSizedFilename); + } + t.sendResponseHeaders(301, 64 * 1024); + byte[] bb = new byte[1024]; + OutputStream os = t.getResponseBody(); + for (int i=0; i<64; i++) { + os.write(bb); + } + os.close(); + t.close(); + } - int size() { - return size; - } + int count() { + return count; + } - // wait a sec before calling this - boolean failed() { - synchronized(lock) { - return failed; + void reset() { + count = 0; } } - @Override - public void run () { - int nbytes = 0; - Socket s = null; + static class RedirectErrorHandler implements HttpHandler { + private final String root; + private volatile int count = 1; - synchronized(lock) { - try { - s = ss.accept(); - - InputStream is = s.getInputStream(); - OutputStream os = s.getOutputStream(); - os.write("HTTP/1.1 201 OK\r\nContent-length: 0\r\n\r\n".getBytes()); - int n; - byte[] buf = new byte[8000]; - while ((n=is.read(buf)) != -1) { - nbytes += n; - } - } catch (IOException e) { - System.out.println ("read " + nbytes); - System.out.println ("size " + size); - failed = nbytes >= size; - } finally { - try { - ss.close(); - if (s != null) - s.close(); - } catch (IOException e) {} - } + RedirectErrorHandler(String root) { + this.root = root; } - } -} -class RedirectHandler implements HttpHandler { - String root; - volatile int count = 0; - - RedirectHandler(String root) { - this.root = root; - } + synchronized int count() { + return count; + } - @Override - public synchronized void handle(HttpExchange t) - throws IOException - { - byte[] buf = new byte[2048]; - try (InputStream is = t.getRequestBody()) { - while (is.read(buf) != -1) ; + synchronized void increment() { + count++; } - Headers responseHeaders = t.getResponseHeaders(); + @Override + public synchronized void handle(HttpExchange t) throws IOException { + try (InputStream is = t.getRequestBody()) { + is.readAllBytes(); + } - if (count++ < 1) { - responseHeaders.add("Location", root + "/foo/" + count); - } else { - responseHeaders.add("Location", SmokeTest.midSizedFilename); + Headers map = t.getResponseHeaders(); + String redirect = root + "/foo/" + Integer.toString(count); + increment(); + map.add("Location", redirect); + t.sendResponseHeaders(301, -1); + t.close(); } - t.sendResponseHeaders(301, -1); - t.close(); } - int count() { - return count; - } - - void reset() { - count = 0; - } -} + static class DelayHandler implements HttpHandler { -class RedirectErrorHandler implements HttpHandler { - String root; - volatile int count = 1; + CyclicBarrier bar1 = new CyclicBarrier(2); + CyclicBarrier bar2 = new CyclicBarrier(2); + CyclicBarrier bar3 = new CyclicBarrier(2); - RedirectErrorHandler(String root) { - this.root = root; - } + CyclicBarrier barrier1() { + return bar1; + } - synchronized int count() { - return count; - } + CyclicBarrier barrier2() { + return bar2; + } - synchronized void increment() { - count++; + @Override + public synchronized void handle(HttpExchange he) throws IOException { + he.getRequestBody().readAllBytes(); + try { + bar1.await(); + bar2.await(); + } catch (Exception e) { } + he.sendResponseHeaders(200, -1); // will probably fail + he.close(); + } } - @Override - public synchronized void handle (HttpExchange t) - throws IOException - { - byte[] buf = new byte[2048]; - try (InputStream is = t.getRequestBody()) { - while (is.read(buf) != -1) ; + static class Configurator extends HttpsConfigurator { + public Configurator(SSLContext ctx) { + super(ctx); } - Headers map = t.getResponseHeaders(); - String redirect = root + "/foo/" + Integer.toString(count); - increment(); - map.add("Location", redirect); - t.sendResponseHeaders(301, -1); - t.close(); - } -} - -class Util { - static byte[] readAll(InputStream is) throws IOException { - byte[] buf = new byte[1024]; - byte[] result = new byte[0]; - - while (true) { - int n = is.read(buf); - if (n > 0) { - byte[] b1 = new byte[result.length + n]; - System.arraycopy(result, 0, b1, 0, result.length); - System.arraycopy(buf, 0, b1, result.length, n); - result = b1; - } else if (n == -1) { - return result; - } + public void configure (HttpsParameters params) { + params.setSSLParameters (getSSLContext().getSupportedSSLParameters()); } } @@ -858,8 +880,8 @@ File f = File.createTempFile("test", "txt"); f.deleteOnExit(); byte[] buf = new byte[2048]; - for (int i=0; i 0) { @@ -872,33 +894,6 @@ } } -class DelayHandler implements HttpHandler { - - CyclicBarrier bar1 = new CyclicBarrier(2); - CyclicBarrier bar2 = new CyclicBarrier(2); - CyclicBarrier bar3 = new CyclicBarrier(2); - - CyclicBarrier barrier1() { - return bar1; - } - - CyclicBarrier barrier2() { - return bar2; - } - - @Override - public synchronized void handle(HttpExchange he) throws IOException { - byte[] buf = Util.readAll(he.getRequestBody()); - try { - bar1.await(); - bar2.await(); - } catch (Exception e) {} - he.sendResponseHeaders(200, -1); // will probably fail - he.close(); - } - -} - // check for simple hardcoded sequence and use remote address // to check. // First 4 requests executed in sequence (should use same connection/address)