/* * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ import java.io.IOException; import java.lang.reflect.Method; import java.net.Authenticator; import java.net.CookieHandler; import java.net.CookieManager; import java.net.InetSocketAddress; import java.net.ProxySelector; import java.net.URI; import java.net.http.HttpHeaders; import java.net.http.HttpRequest; import java.net.http.HttpRequest.BodyPublishers; import java.net.http.HttpResponse; import java.net.http.HttpResponse.BodyHandler; import java.net.http.HttpResponse.BodyHandlers; import java.net.http.HttpResponse.PushPromiseHandler; import java.time.Duration; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.TreeMap; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLParameters; import java.net.http.HttpClient; import java.net.http.HttpClient.Redirect; import java.net.http.HttpClient.Version; import jdk.testlibrary.SimpleSSLContext; import org.testng.annotations.Test; import static java.time.Duration.*; import static org.testng.Assert.*; /* * @test * @summary HttpClient[.Builder] API and behaviour checks * @library /lib/testlibrary/ * @build jdk.testlibrary.SimpleSSLContext * @run testng HttpClientBuilderTest */ public class HttpClientBuilderTest { static final Class NPE = NullPointerException.class; static final Class IAE = IllegalArgumentException.class; @Test public void testDefaults() throws Exception { List clients = List.of(HttpClient.newHttpClient(), HttpClient.newBuilder().build()); for (HttpClient client : clients) { // Empty optionals and defaults assertFalse(client.authenticator().isPresent()); assertFalse(client.cookieHandler().isPresent()); assertFalse(client.connectTimeout().isPresent()); assertFalse(client.executor().isPresent()); assertFalse(client.proxy().isPresent()); assertTrue(client.sslParameters() != null); assertTrue(client.followRedirects().equals(HttpClient.Redirect.NEVER)); assertTrue(client.sslContext() == SSLContext.getDefault()); assertTrue(client.version().equals(HttpClient.Version.HTTP_2)); } } @Test public void testNull() throws Exception { HttpClient.Builder builder = HttpClient.newBuilder(); assertThrows(NPE, () -> builder.authenticator(null)); assertThrows(NPE, () -> builder.cookieHandler(null)); assertThrows(NPE, () -> builder.connectTimeout(null)); assertThrows(NPE, () -> builder.executor(null)); assertThrows(NPE, () -> builder.proxy(null)); assertThrows(NPE, () -> builder.sslParameters(null)); assertThrows(NPE, () -> builder.followRedirects(null)); assertThrows(NPE, () -> builder.sslContext(null)); assertThrows(NPE, () -> builder.version(null)); } static class TestAuthenticator extends Authenticator { } @Test public void testAuthenticator() { HttpClient.Builder builder = HttpClient.newBuilder(); Authenticator a = new TestAuthenticator(); builder.authenticator(a); assertTrue(builder.build().authenticator().get() == a); Authenticator b = new TestAuthenticator(); builder.authenticator(b); assertTrue(builder.build().authenticator().get() == b); assertThrows(NPE, () -> builder.authenticator(null)); Authenticator c = new TestAuthenticator(); builder.authenticator(c); assertTrue(builder.build().authenticator().get() == c); } @Test public void testCookieHandler() { HttpClient.Builder builder = HttpClient.newBuilder(); CookieHandler a = new CookieManager(); builder.cookieHandler(a); assertTrue(builder.build().cookieHandler().get() == a); CookieHandler b = new CookieManager(); builder.cookieHandler(b); assertTrue(builder.build().cookieHandler().get() == b); assertThrows(NPE, () -> builder.cookieHandler(null)); CookieManager c = new CookieManager(); builder.cookieHandler(c); assertTrue(builder.build().cookieHandler().get() == c); } @Test public void testConnectTimeout() { HttpClient.Builder builder = HttpClient.newBuilder(); Duration a = Duration.ofSeconds(5); builder.connectTimeout(a); assertTrue(builder.build().connectTimeout().get() == a); Duration b = Duration.ofMinutes(1); builder.connectTimeout(b); assertTrue(builder.build().connectTimeout().get() == b); assertThrows(NPE, () -> builder.cookieHandler(null)); Duration c = Duration.ofHours(100); builder.connectTimeout(c); assertTrue(builder.build().connectTimeout().get() == c); assertThrows(IAE, () -> builder.connectTimeout(ZERO)); assertThrows(IAE, () -> builder.connectTimeout(ofSeconds(0))); assertThrows(IAE, () -> builder.connectTimeout(ofSeconds(-1))); assertThrows(IAE, () -> builder.connectTimeout(ofNanos(-100))); } static class TestExecutor implements Executor { public void execute(Runnable r) { } } @Test public void testExecutor() { HttpClient.Builder builder = HttpClient.newBuilder(); TestExecutor a = new TestExecutor(); builder.executor(a); assertTrue(builder.build().executor().get() == a); TestExecutor b = new TestExecutor(); builder.executor(b); assertTrue(builder.build().executor().get() == b); assertThrows(NPE, () -> builder.executor(null)); TestExecutor c = new TestExecutor(); builder.executor(c); assertTrue(builder.build().executor().get() == c); } @Test public void testProxySelector() { HttpClient.Builder builder = HttpClient.newBuilder(); ProxySelector a = ProxySelector.of(null); builder.proxy(a); assertTrue(builder.build().proxy().get() == a); ProxySelector b = ProxySelector.of(InetSocketAddress.createUnresolved("foo", 80)); builder.proxy(b); assertTrue(builder.build().proxy().get() == b); assertThrows(NPE, () -> builder.proxy(null)); ProxySelector c = ProxySelector.of(InetSocketAddress.createUnresolved("bar", 80)); builder.proxy(c); assertTrue(builder.build().proxy().get() == c); } @Test public void testSSLParameters() { HttpClient.Builder builder = HttpClient.newBuilder(); SSLParameters a = new SSLParameters(); a.setCipherSuites(new String[] { "A" }); builder.sslParameters(a); a.setCipherSuites(new String[] { "Z" }); assertTrue(builder.build().sslParameters() != (a)); assertTrue(builder.build().sslParameters().getCipherSuites()[0].equals("A")); SSLParameters b = new SSLParameters(); b.setEnableRetransmissions(true); builder.sslParameters(b); assertTrue(builder.build().sslParameters() != b); assertTrue(builder.build().sslParameters().getEnableRetransmissions()); assertThrows(NPE, () -> builder.sslParameters(null)); SSLParameters c = new SSLParameters(); c.setProtocols(new String[] { "C" }); builder.sslParameters(c); c.setProtocols(new String[] { "D" }); assertTrue(builder.build().sslParameters().getProtocols()[0].equals("C")); } @Test public void testSSLContext() throws Exception { HttpClient.Builder builder = HttpClient.newBuilder(); SSLContext a = (new SimpleSSLContext()).get(); builder.sslContext(a); assertTrue(builder.build().sslContext() == a); SSLContext b = (new SimpleSSLContext()).get(); builder.sslContext(b); assertTrue(builder.build().sslContext() == b); assertThrows(NPE, () -> builder.sslContext(null)); SSLContext c = (new SimpleSSLContext()).get(); builder.sslContext(c); assertTrue(builder.build().sslContext() == c); } @Test public void testFollowRedirects() { HttpClient.Builder builder = HttpClient.newBuilder(); builder.followRedirects(Redirect.ALWAYS); assertTrue(builder.build().followRedirects() == Redirect.ALWAYS); builder.followRedirects(Redirect.NEVER); assertTrue(builder.build().followRedirects() == Redirect.NEVER); assertThrows(NPE, () -> builder.followRedirects(null)); builder.followRedirects(Redirect.NORMAL); assertTrue(builder.build().followRedirects() == Redirect.NORMAL); } @Test public void testVersion() { HttpClient.Builder builder = HttpClient.newBuilder(); builder.version(Version.HTTP_2); assertTrue(builder.build().version() == Version.HTTP_2); builder.version(Version.HTTP_1_1); assertTrue(builder.build().version() == Version.HTTP_1_1); assertThrows(NPE, () -> builder.version(null)); builder.version(Version.HTTP_2); assertTrue(builder.build().version() == Version.HTTP_2); builder.version(Version.HTTP_1_1); assertTrue(builder.build().version() == Version.HTTP_1_1); } @Test static void testPriority() throws Exception { HttpClient.Builder builder = HttpClient.newBuilder(); assertThrows(IAE, () -> builder.priority(-1)); assertThrows(IAE, () -> builder.priority(0)); assertThrows(IAE, () -> builder.priority(257)); assertThrows(IAE, () -> builder.priority(500)); builder.priority(1); builder.build(); builder.priority(256); builder.build(); } // --- static final URI uri = URI.create("http://foo.com/"); @Test static void testHttpClientSendArgs() throws Exception { HttpClient client = HttpClient.newHttpClient(); HttpRequest request = HttpRequest.newBuilder(uri).build(); assertThrows(NPE, () -> client.send(null, BodyHandlers.discarding())); assertThrows(NPE, () -> client.send(request, null)); assertThrows(NPE, () -> client.send(null, null)); assertThrows(NPE, () -> client.sendAsync(null, BodyHandlers.discarding())); assertThrows(NPE, () -> client.sendAsync(request, null)); assertThrows(NPE, () -> client.sendAsync(null, null)); assertThrows(NPE, () -> client.sendAsync(null, BodyHandlers.discarding(), null)); assertThrows(NPE, () -> client.sendAsync(request, null, null)); assertThrows(NPE, () -> client.sendAsync(null, null, null)); // CONNECT is disallowed in the implementation, since it is used for // tunneling, and is handled separately for security checks. HttpRequest connectRequest = new HttpConnectRequest(); assertThrows(IAE, () -> client.send(connectRequest, BodyHandlers.discarding())); assertThrows(IAE, () -> client.sendAsync(connectRequest, BodyHandlers.discarding())); assertThrows(IAE, () -> client.sendAsync(connectRequest, BodyHandlers.discarding(), null)); } static class HttpConnectRequest extends HttpRequest { @Override public Optional bodyPublisher() { return Optional.empty(); } @Override public String method() { return "CONNECT"; } @Override public Optional timeout() { return Optional.empty(); } @Override public boolean expectContinue() { return false; } @Override public URI uri() { return URI.create("http://foo.com/"); } @Override public Optional version() { return Optional.empty(); } @Override public HttpHeaders headers() { return HttpHeaders.of(Map.of(), (x, y) -> true); } } // --- static final Class UOE = UnsupportedOperationException.class; @Test static void testUnsupportedWebSocket() throws Exception { // @implSpec The default implementation of this method throws // {@code UnsupportedOperationException}. assertThrows(UOE, () -> (new MockHttpClient()).newWebSocketBuilder()); } static class MockHttpClient extends HttpClient { @Override public Optional cookieHandler() { return null; } @Override public Optional connectTimeout() { return null; } @Override public Redirect followRedirects() { return null; } @Override public Optional proxy() { return null; } @Override public SSLContext sslContext() { return null; } @Override public SSLParameters sslParameters() { return null; } @Override public Optional authenticator() { return null; } @Override public Version version() { return null; } @Override public Optional executor() { return null; } @Override public HttpResponse send(HttpRequest request, BodyHandler responseBodyHandler) throws IOException, InterruptedException { return null; } @Override public CompletableFuture> sendAsync(HttpRequest request, BodyHandler responseBodyHandler) { return null; } @Override public CompletableFuture> sendAsync(HttpRequest x, BodyHandler y, PushPromiseHandler z) { return null; } } /* ---- standalone entry point ---- */ public static void main(String[] args) throws Exception { HttpClientBuilderTest test = new HttpClientBuilderTest(); for (Method m : HttpClientBuilderTest.class.getDeclaredMethods()) { if (m.isAnnotationPresent(Test.class)) { try { m.invoke(test); System.out.printf("test %s: success%n", m.getName()); } catch (Throwable t ) { System.out.printf("test %s: failed%n", m.getName()); t.printStackTrace(); } } } } }