| /* |
| * ==================================================================== |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * ==================================================================== |
| * |
| * This software consists of voluntary contributions made by many |
| * individuals on behalf of the Apache Software Foundation. For more |
| * information on the Apache Software Foundation, please see |
| * <http://www.apache.org/>. |
| * |
| */ |
| |
| package org.apache.hc.core5.testing.nio; |
| |
| import java.net.InetSocketAddress; |
| import java.net.URI; |
| import java.net.URISyntaxException; |
| import java.net.URL; |
| import java.security.Provider; |
| import java.security.SecureRandom; |
| import java.security.Security; |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.concurrent.Future; |
| |
| import org.apache.hc.core5.http.HttpHeaders; |
| import org.apache.hc.core5.http.HttpResponse; |
| import org.apache.hc.core5.http.Message; |
| import org.apache.hc.core5.http.Method; |
| import org.apache.hc.core5.http.config.Http1Config; |
| import org.apache.hc.core5.http.nio.entity.StringAsyncEntityConsumer; |
| import org.apache.hc.core5.http.nio.support.AsyncRequestBuilder; |
| import org.apache.hc.core5.http.nio.support.BasicRequestProducer; |
| import org.apache.hc.core5.http.nio.support.BasicResponseConsumer; |
| import org.apache.hc.core5.http.protocol.DefaultHttpProcessor; |
| import org.apache.hc.core5.http.protocol.HttpProcessor; |
| import org.apache.hc.core5.http.protocol.RequestValidateHost; |
| import org.apache.hc.core5.reactor.IOReactorConfig; |
| import org.apache.hc.core5.ssl.SSLContextBuilder; |
| import org.apache.hc.core5.util.ReflectionUtils; |
| import org.apache.hc.core5.util.TimeValue; |
| import org.apache.hc.core5.util.Timeout; |
| import org.conscrypt.Conscrypt; |
| import org.junit.Assert; |
| import org.junit.Assume; |
| import org.junit.BeforeClass; |
| import org.junit.Rule; |
| import org.junit.Test; |
| import org.junit.rules.ExternalResource; |
| import org.junit.rules.RuleChain; |
| import org.junit.rules.TestRule; |
| import org.junit.runner.RunWith; |
| import org.junit.runners.Parameterized; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| @RunWith(Parameterized.class) |
| public class JSSEProviderIntegrationTest { |
| |
| private final Logger log = LoggerFactory.getLogger(getClass()); |
| |
| @Parameterized.Parameters(name = "{0} {1}") |
| public static Collection<Object[]> protocols() { |
| return Arrays.asList(new Object[][]{ |
| {"Oracle", null}, |
| {"Conscrypt", "TLSv1.2"}, |
| {"Conscrypt", "TLSv1.3"}, |
| }); |
| } |
| |
| private final String securityProviderName; |
| private final String protocolVersion; |
| |
| public JSSEProviderIntegrationTest(final String securityProviderName, final String protocolVersion) { |
| super(); |
| this.securityProviderName = securityProviderName; |
| this.protocolVersion = protocolVersion; |
| } |
| |
| private static final Timeout TIMEOUT = Timeout.ofSeconds(30); |
| private static final int REQ_NUM = 25; |
| |
| private Provider securityProvider; |
| private Http1TestServer server; |
| private Http1TestClient client; |
| |
| @BeforeClass |
| public static void determineJavaVersion() { |
| Assume.assumeTrue("Java version must be 8 or greater", ReflectionUtils.determineJRELevel() >= 8); |
| } |
| |
| @Rule |
| public TestRule resourceRules = RuleChain.outerRule(new ExternalResource() { |
| |
| @Override |
| protected void before() throws Throwable { |
| if ("Conscrypt".equalsIgnoreCase(securityProviderName)) { |
| try { |
| securityProvider = Conscrypt.newProviderBuilder().provideTrustManager(true).build(); |
| } catch (final UnsatisfiedLinkError e) { |
| Assume.assumeFalse("Conscrypt provider failed to be loaded: " + e.getMessage(), true); |
| } |
| } else { |
| securityProvider = null; |
| } |
| if (securityProvider != null) { |
| Security.insertProviderAt(securityProvider, 1); |
| } |
| } |
| |
| @Override |
| protected void after() { |
| if (securityProvider != null) { |
| Security.removeProvider(securityProvider.getName()); |
| securityProvider = null; |
| } |
| } |
| |
| }).around(new ExternalResource() { |
| |
| @Override |
| protected void before() throws Throwable { |
| log.debug("Starting up test server"); |
| |
| final URL keyStoreURL = getClass().getResource("/test-server.p12"); |
| final String storePassword = "nopassword"; |
| |
| server = new Http1TestServer( |
| IOReactorConfig.custom() |
| .setSoTimeout(TIMEOUT) |
| .build(), |
| SSLContextBuilder.create() |
| .setProvider(securityProvider) |
| .setKeyStoreType("pkcs12") |
| .loadTrustMaterial(keyStoreURL, storePassword.toCharArray()) |
| .loadKeyMaterial(keyStoreURL, storePassword.toCharArray(), storePassword.toCharArray()) |
| .setSecureRandom(new SecureRandom()) |
| .build(), |
| (endpoint, sslEngine) -> { |
| if (protocolVersion != null) { |
| sslEngine.setEnabledProtocols(new String[]{protocolVersion}); |
| } |
| }, |
| null); |
| } |
| |
| @Override |
| protected void after() { |
| log.debug("Shutting down test server"); |
| if (server != null) { |
| server.shutdown(TimeValue.ofSeconds(5)); |
| } |
| } |
| |
| }).around(new ExternalResource() { |
| |
| @Override |
| protected void before() throws Throwable { |
| log.debug("Starting up test client"); |
| |
| final URL keyStoreURL = getClass().getResource("/test-client.p12"); |
| final String storePassword = "nopassword"; |
| |
| client = new Http1TestClient( |
| IOReactorConfig.custom() |
| .setSoTimeout(TIMEOUT) |
| .build(), |
| SSLContextBuilder.create() |
| .setProvider(securityProvider) |
| .setKeyStoreType("pkcs12") |
| .loadTrustMaterial(keyStoreURL, storePassword.toCharArray()) |
| .setSecureRandom(new SecureRandom()) |
| .build(), |
| (endpoint, sslEngine) -> { |
| if (protocolVersion != null) { |
| sslEngine.setEnabledProtocols(new String[]{protocolVersion}); |
| } |
| }, |
| null); |
| } |
| |
| @Override |
| protected void after() { |
| log.debug("Shutting down test client"); |
| if (client != null) { |
| client.shutdown(TimeValue.ofSeconds(5)); |
| } |
| } |
| |
| }); |
| |
| private URI createRequestURI(final InetSocketAddress serverEndpoint, final String path) { |
| try { |
| return new URI("https", null, "localhost", serverEndpoint.getPort(), path, null, null); |
| } catch (final URISyntaxException e) { |
| throw new IllegalStateException(); |
| } |
| } |
| |
| @Test |
| public void testSimpleGet() throws Exception { |
| server.register("/hello", () -> new SingleLineResponseHandler("Hi there")); |
| final InetSocketAddress serverEndpoint = server.start(); |
| |
| client.start(); |
| final Future<ClientSessionEndpoint> connectFuture = client.connect( |
| "localhost", serverEndpoint.getPort(), TIMEOUT); |
| final ClientSessionEndpoint streamEndpoint = connectFuture.get(); |
| |
| for (int i = 0; i < REQ_NUM; i++) { |
| final Future<Message<HttpResponse, String>> future = streamEndpoint.execute( |
| new BasicRequestProducer(Method.GET, createRequestURI(serverEndpoint, "/hello")), |
| new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), null); |
| final Message<HttpResponse, String> result = future.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit()); |
| Assert.assertNotNull(result); |
| final HttpResponse response1 = result.getHead(); |
| final String entity1 = result.getBody(); |
| Assert.assertNotNull(response1); |
| Assert.assertEquals(200, response1.getCode()); |
| Assert.assertEquals("Hi there", entity1); |
| } |
| } |
| |
| @Test |
| public void testSimpleGetConnectionClose() throws Exception { |
| server.register("/hello", () -> new SingleLineResponseHandler("Hi there")); |
| final InetSocketAddress serverEndpoint = server.start(); |
| |
| client.start(); |
| final URI requestURI = createRequestURI(serverEndpoint, "/hello"); |
| for (int i = 0; i < REQ_NUM; i++) { |
| final Future<ClientSessionEndpoint> connectFuture = client.connect( |
| "localhost", serverEndpoint.getPort(), TIMEOUT); |
| try (final ClientSessionEndpoint streamEndpoint = connectFuture.get()) { |
| final Future<Message<HttpResponse, String>> future = streamEndpoint.execute( |
| AsyncRequestBuilder.get(requestURI) |
| .addHeader(HttpHeaders.CONNECTION, "close") |
| .build(), |
| new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), null); |
| final Message<HttpResponse, String> result = future.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit()); |
| Assert.assertNotNull(result); |
| final HttpResponse response1 = result.getHead(); |
| final String entity1 = result.getBody(); |
| Assert.assertNotNull(response1); |
| Assert.assertEquals(200, response1.getCode()); |
| Assert.assertEquals("Hi there", entity1); |
| } |
| } |
| } |
| |
| @Test |
| public void testSimpleGetIdentityTransfer() throws Exception { |
| server.register("/hello", () -> new SingleLineResponseHandler("Hi there")); |
| final HttpProcessor httpProcessor = new DefaultHttpProcessor(new RequestValidateHost()); |
| final InetSocketAddress serverEndpoint = server.start(httpProcessor, Http1Config.DEFAULT); |
| |
| client.start(); |
| |
| for (int i = 0; i < REQ_NUM; i++) { |
| final Future<ClientSessionEndpoint> connectFuture = client.connect( |
| "localhost", serverEndpoint.getPort(), TIMEOUT); |
| try (final ClientSessionEndpoint streamEndpoint = connectFuture.get()) { |
| final Future<Message<HttpResponse, String>> future = streamEndpoint.execute( |
| new BasicRequestProducer(Method.GET, createRequestURI(serverEndpoint, "/hello")), |
| new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), null); |
| final Message<HttpResponse, String> result = future.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit()); |
| Assert.assertNotNull(result); |
| final HttpResponse response = result.getHead(); |
| final String entity = result.getBody(); |
| Assert.assertNotNull(response); |
| Assert.assertEquals(200, response.getCode()); |
| Assert.assertEquals("Hi there", entity); |
| } |
| } |
| } |
| |
| } |