You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by ol...@apache.org on 2024/10/20 13:31:31 UTC
(httpcomponents-core) 02/02: Redesign of compatibility integration tests for greater flexibility and extensibility; added classic i/o and TLS compatibility tests
This is an automated email from the ASF dual-hosted git repository.
olegk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/httpcomponents-core.git
commit 1ed6e17937b80b26607af0ec8620c55c8e9285df
Author: Oleg Kalnichevski <ol...@apache.org>
AuthorDate: Tue Oct 15 16:34:17 2024 +0200
Redesign of compatibility integration tests for greater flexibility and extensibility; added classic i/o and TLS compatibility tests
---
.gitignore | 3 +
.../testing/compatibility/ApacheHttpDCompatIT.java | 128 ++++++++
.../testing/compatibility/ContainerImages.java | 109 +++++--
...acheHttpDCompatIT.java => HttpBinCompatIT.java} | 43 ++-
.../core5/testing/compatibility/NginxCompatIT.java | 128 ++++++++
.../NginxCompatIT.java => TLSTestContexts.java} | 55 ++--
.../classic/ClassicHttpCompatTest.java | 154 +++++++++
.../classic/HttpBinClassicCompatTest.java | 121 +++++++
.../compatibility/nio/AsyncHttp1CompatTest.java | 70 ++++
.../AsyncHttp2CompatTest.java} | 115 ++-----
.../AsyncHttpCompatTest.java} | 121 ++-----
.../HttpBinAsyncCompatTest.java} | 71 ++--
.../src/test/resources/docker/BUILDING.txt | 43 +++
.../{httpd-vhosts.conf => httpd-default.conf} | 20 +-
.../{ngnix/default.conf => httpd/httpd-h2c.conf} | 32 +-
.../src/test/resources/docker/httpd/httpd-ssl.conf | 53 +++
.../resources/docker/{ngnix => nginx}/default.conf | 8 +-
.../docker/{ngnix/default.conf => nginx/h2c.conf} | 2 +-
.../docker/{ngnix/default.conf => nginx/ssl.conf} | 6 +-
.../src/test/resources/docker/server-cert.pem | 83 +++++
.../src/test/resources/docker/server-key.pem | 28 ++
httpcore5-testing/src/test/resources/test-ca.jks | Bin 0 -> 1037 bytes
test-CA/ca-cert.pem | 23 ++
test-CA/ca-key.pem | 30 ++
test-CA/openssl.cnf | 357 +++++++++++++++++++++
25 files changed, 1450 insertions(+), 353 deletions(-)
diff --git a/.gitignore b/.gitignore
index cde3cfff4..e6786cd55 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,3 +9,6 @@ maven-eclipse.xml
*.iml
**/log4j2-debug.xml
**/.checkstyle
+/test-CA/newcerts/
+/test-CA/serial.txt*
+/test-CA/index.txt*
diff --git a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/compatibility/ApacheHttpDCompatIT.java b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/compatibility/ApacheHttpDCompatIT.java
new file mode 100644
index 000000000..78cbd98f7
--- /dev/null
+++ b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/compatibility/ApacheHttpDCompatIT.java
@@ -0,0 +1,128 @@
+/*
+ * ====================================================================
+ * 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.compatibility;
+
+import org.apache.hc.core5.http.HttpHost;
+import org.apache.hc.core5.http.URIScheme;
+import org.apache.hc.core5.http2.HttpVersionPolicy;
+import org.apache.hc.core5.testing.compatibility.classic.ClassicHttpCompatTest;
+import org.apache.hc.core5.testing.compatibility.nio.AsyncHttp1CompatTest;
+import org.apache.hc.core5.testing.compatibility.nio.AsyncHttp2CompatTest;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+import org.testcontainers.containers.GenericContainer;
+import org.testcontainers.containers.Network;
+import org.testcontainers.junit.jupiter.Container;
+import org.testcontainers.junit.jupiter.Testcontainers;
+
+@Testcontainers(disabledWithoutDocker = true)
+class ApacheHttpDCompatIT {
+
+ private static Network NETWORK = Network.newNetwork();
+ @Container
+ static final GenericContainer<?> HTTPD_CONTAINER = ContainerImages.apacheHttpD(NETWORK);
+
+ @AfterAll
+ static void cleanup() {
+ HTTPD_CONTAINER.close();
+ }
+
+ static HttpHost targetContainerHost() {
+ return new HttpHost(URIScheme.HTTP.id, HTTPD_CONTAINER.getHost(), HTTPD_CONTAINER.getMappedPort(ContainerImages.HTTP_PORT));
+ }
+
+ static HttpHost targetContainerH2CHost() {
+ return new HttpHost(URIScheme.HTTP.id, HTTPD_CONTAINER.getHost(), HTTPD_CONTAINER.getMappedPort(ContainerImages.H2C_PORT));
+ }
+
+ static HttpHost targetContainerTLSHost() {
+ return new HttpHost(URIScheme.HTTPS.id, HTTPD_CONTAINER.getHost(), HTTPD_CONTAINER.getMappedPort(ContainerImages.HTTPS_PORT));
+ }
+
+ @Nested
+ @DisplayName("Classic, HTTP/1, plain")
+ class ClassicHttp1 extends ClassicHttpCompatTest {
+
+ public ClassicHttp1() throws Exception {
+ super(targetContainerHost());
+ }
+
+ }
+
+ @Nested
+ @DisplayName("Classic, HTTP/1, TLS")
+ class ClassicHttp1Tls extends ClassicHttpCompatTest {
+
+ public ClassicHttp1Tls() throws Exception {
+ super(targetContainerTLSHost());
+ }
+
+ }
+
+ @Nested
+ @DisplayName("Async, HTTP/1, plain")
+ class AsyncHttp1 extends AsyncHttp1CompatTest {
+
+ public AsyncHttp1() throws Exception {
+ super(targetContainerHost());
+ }
+
+ }
+
+ @Nested
+ @DisplayName("Async, HTTP/2, plain")
+ class AsyncHttp2 extends AsyncHttp2CompatTest {
+
+ public AsyncHttp2() throws Exception {
+ super(targetContainerH2CHost(), HttpVersionPolicy.FORCE_HTTP_2);
+ }
+
+ }
+
+ @Nested
+ @DisplayName("Async, HTTP/1, TLS")
+ class AsyncHttp1Tls extends AsyncHttp1CompatTest {
+
+ public AsyncHttp1Tls() throws Exception {
+ super(targetContainerTLSHost());
+ }
+
+ }
+
+ @Nested
+ @DisplayName("Async, protocol HTTP/2, TLS")
+ class AsyncHttp2Tls extends AsyncHttp2CompatTest {
+
+ public AsyncHttp2Tls() throws Exception {
+ super(targetContainerTLSHost(), HttpVersionPolicy.FORCE_HTTP_2);
+ }
+
+ }
+
+}
diff --git a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/compatibility/ContainerImages.java b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/compatibility/ContainerImages.java
index 89d467844..ac7849a78 100644
--- a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/compatibility/ContainerImages.java
+++ b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/compatibility/ContainerImages.java
@@ -26,69 +26,110 @@
*/
package org.apache.hc.core5.testing.compatibility;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.testcontainers.containers.GenericContainer;
+import org.testcontainers.containers.Network;
+import org.testcontainers.containers.output.Slf4jLogConsumer;
import org.testcontainers.images.builder.ImageFromDockerfile;
import org.testcontainers.utility.DockerImageName;
public final class ContainerImages {
+ private static final Logger LOG = LoggerFactory.getLogger(ContainerImages.class);
+
public static final String AAA = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
public static final String BBB = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
public static final String CCC = "ccccccccccccccccccccccccccccccccccccccccccccccccc";
public static final String PUSHY = "I am being very pushy";
+ public static final String APACHE_HTTPD = "test-apache";
+ public static final String NGINX = "test-nginx";
+ public static final String HTTPBIN = "test-httpbin";
+
public static int HTTP_PORT = 80;
+ public static int H2C_PORT = 81;
+ public static int HTTPS_PORT = 443;
- public static GenericContainer<?> httpBin() {
+ public static GenericContainer<?> httpBin(final Network network) {
return new GenericContainer<>(DockerImageName.parse("kennethreitz/httpbin:latest"))
+ .withNetwork(network)
+ .withNetworkAliases(HTTPBIN)
+ .withLogConsumer(new Slf4jLogConsumer(LOG))
.withExposedPorts(HTTP_PORT);
}
- public static GenericContainer<?> apacheHttpD() {
+ public static GenericContainer<?> apacheHttpD(final Network network) {
return new GenericContainer<>(new ImageFromDockerfile()
- .withFileFromClasspath("httpd-vhosts.conf", "docker/httpd/httpd-vhosts.conf")
+ .withFileFromClasspath("httpd-default.conf", "docker/httpd/httpd-default.conf")
+ .withFileFromClasspath("httpd-h2c.conf", "docker/httpd/httpd-h2c.conf")
+ .withFileFromClasspath("httpd-ssl.conf", "docker/httpd/httpd-ssl.conf")
+ .withFileFromClasspath("server-cert.pem", "docker/server-cert.pem")
+ .withFileFromClasspath("server-key.pem", "docker/server-key.pem")
.withFileFromString("pushy", PUSHY)
.withFileFromString("aaa", AAA)
.withFileFromString("bbb", BBB)
.withFileFromString("ccc", CCC)
- .withDockerfileFromBuilder(builder ->
- builder
- .from("httpd:2.4")
- .env("var_dir", "/var/httpd")
- .env("www_dir", "${var_dir}/www")
- .run("mkdir -p ${var_dir}")
- .run("sed -i -E 's/^\\s*#\\s*(LoadModule\\s+http2_module\\s+modules\\/mod_http2.so)/\\1/' conf/httpd.conf")
- .run("sed -i -E 's/^\\s*ServerAdmin.*$/ServerAdmin dev@hc.apache.org/' conf/httpd.conf")
- .run("sed -i -E 's/^\\s*#\\s*(Include\\s+conf\\/extra\\/httpd-vhosts.conf)/\\1/' conf/httpd.conf")
- .copy("httpd-vhosts.conf", "/usr/local/apache2/conf/extra/httpd-vhosts.conf")
- .copy("pushy", "${www_dir}/")
- .copy("aaa", "${www_dir}/")
- .copy("bbb", "${www_dir}/")
- .copy("ccc", "${www_dir}/")
- .build()))
- .withExposedPorts(HTTP_PORT);
+ .withDockerfileFromBuilder(builder -> builder
+ .from("httpd:2.4")
+ .env("var_dir", "/var/httpd")
+ .env("www_dir", "${var_dir}/www")
+ .run("mkdir -p ${var_dir}")
+ .run("mkdir -p ${www_dir}")
+ .run("echo '\\n" +
+ "LoadModule http2_module modules/mod_http2.so\\n" +
+ "LoadModule ssl_module modules/mod_ssl.so\\n" +
+ "Include conf/extra/httpd-default.conf\\n" +
+ "Include conf/extra/httpd-h2c.conf\\n" +
+ "Include conf/extra/httpd-ssl.conf\\n" +
+ "'" +
+ " >> /usr/local/apache2/conf/httpd.conf")
+ .copy("httpd-default.conf", "/usr/local/apache2/conf/extra/httpd-default.conf")
+ .copy("httpd-h2c.conf", "/usr/local/apache2/conf/extra/httpd-h2c.conf")
+ .copy("httpd-ssl.conf", "/usr/local/apache2/conf/extra/httpd-ssl.conf")
+ .copy("server-cert.pem", "/usr/local/apache2/conf/server-cert.pem")
+ .copy("server-key.pem", "/usr/local/apache2/conf/server-key.pem")
+ .copy("pushy", "${www_dir}/")
+ .copy("aaa", "${www_dir}/")
+ .copy("bbb", "${www_dir}/")
+ .copy("ccc", "${www_dir}/")
+ .build()))
+ .withNetwork(network)
+ .withNetworkAliases(APACHE_HTTPD)
+ .withLogConsumer(new Slf4jLogConsumer(LOG))
+ .withExposedPorts(HTTP_PORT, H2C_PORT, HTTPS_PORT);
}
- public static GenericContainer<?> ngnix() {
+ public static GenericContainer<?> nginx(final Network network) {
return new GenericContainer<>(new ImageFromDockerfile()
- .withFileFromClasspath("default.conf", "docker/ngnix/default.conf")
+ .withFileFromClasspath("default.conf", "docker/nginx/default.conf")
+ .withFileFromClasspath("h2c.conf", "docker/nginx/h2c.conf")
+ .withFileFromClasspath("ssl.conf", "docker/nginx/ssl.conf")
+ .withFileFromClasspath("server-cert.pem", "docker/server-cert.pem")
+ .withFileFromClasspath("server-key.pem", "docker/server-key.pem")
.withFileFromString("pushy", PUSHY)
.withFileFromString("aaa", AAA)
.withFileFromString("bbb", BBB)
.withFileFromString("ccc", CCC)
- .withDockerfileFromBuilder(builder ->
- builder
- .from("nginx:1.22")
- .env("var_dir", "/var/nginx")
- .env("www_dir", "${var_dir}/www")
- .run("mkdir -p ${var_dir}")
- .copy("default.conf", "/etc/nginx/conf.d/default.conf")
- .copy("pushy", "${www_dir}/")
- .copy("aaa", "${www_dir}/")
- .copy("bbb", "${www_dir}/")
- .copy("ccc", "${www_dir}/")
- .build()))
- .withExposedPorts(HTTP_PORT);
+ .withDockerfileFromBuilder(builder -> builder
+ .from("nginx:1.22")
+ .env("var_dir", "/var/nginx")
+ .env("www_dir", "${var_dir}/www")
+ .run("mkdir -p ${var_dir}")
+ .copy("default.conf", "/etc/nginx/conf.d/default.conf")
+ .copy("h2c.conf", "/etc/nginx/conf.d/h2c.conf")
+ .copy("ssl.conf", "/etc/nginx/conf.d/ssl.conf")
+ .copy("server-cert.pem", "/etc/nginx/server-cert.pem")
+ .copy("server-key.pem", "/etc/nginx/server-key.pem")
+ .copy("pushy", "${www_dir}/")
+ .copy("aaa", "${www_dir}/")
+ .copy("bbb", "${www_dir}/")
+ .copy("ccc", "${www_dir}/")
+ .build()))
+ .withNetwork(network)
+ .withNetworkAliases(NGINX)
+ .withLogConsumer(new Slf4jLogConsumer(LOG))
+ .withExposedPorts(HTTP_PORT, H2C_PORT, HTTPS_PORT);
}
}
diff --git a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/compatibility/http2/ApacheHttpDCompatIT.java b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/compatibility/HttpBinCompatIT.java
similarity index 57%
rename from httpcore5-testing/src/test/java/org/apache/hc/core5/testing/compatibility/http2/ApacheHttpDCompatIT.java
rename to httpcore5-testing/src/test/java/org/apache/hc/core5/testing/compatibility/HttpBinCompatIT.java
index 0277dba0a..6157acf12 100644
--- a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/compatibility/http2/ApacheHttpDCompatIT.java
+++ b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/compatibility/HttpBinCompatIT.java
@@ -25,35 +25,48 @@
*
*/
-package org.apache.hc.core5.testing.compatibility.http2;
+package org.apache.hc.core5.testing.compatibility;
import org.apache.hc.core5.http.HttpHost;
-import org.apache.hc.core5.http2.impl.nio.bootstrap.H2RequesterBootstrap;
-import org.apache.hc.core5.testing.compatibility.ContainerImages;
-import org.junit.jupiter.api.AfterAll;
+import org.apache.hc.core5.http.URIScheme;
+import org.apache.hc.core5.testing.compatibility.classic.HttpBinClassicCompatTest;
+import org.apache.hc.core5.testing.compatibility.nio.HttpBinAsyncCompatTest;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
import org.testcontainers.containers.GenericContainer;
+import org.testcontainers.containers.Network;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
@Testcontainers(disabledWithoutDocker = true)
-class ApacheHttpDCompatIT extends AbstractHttp2CompatIT {
+class HttpBinCompatIT {
+ private static Network NETWORK = Network.newNetwork();
@Container
- static final GenericContainer<?> CONTAINER = ContainerImages.apacheHttpD();
+ static final GenericContainer<?> HTTP_BIN_CONTAINER = ContainerImages.httpBin(NETWORK);
- @Override
- void configure(final H2RequesterBootstrap bootstrap) {
+ static HttpHost targetContainerHost() {
+ return new HttpHost(URIScheme.HTTP.id, HTTP_BIN_CONTAINER.getHost(), HTTP_BIN_CONTAINER.getMappedPort(ContainerImages.HTTP_PORT));
}
- HttpHost targetHost() {
- return new HttpHost("http",
- CONTAINER.getHost(),
- CONTAINER.getMappedPort(ContainerImages.HTTP_PORT));
+ @Nested
+ @DisplayName("Classic")
+ class Classic extends HttpBinClassicCompatTest {
+
+ public Classic() throws Exception {
+ super(targetContainerHost());
+ }
+
}
- @AfterAll
- static void cleanup() {
- CONTAINER.close();
+ @Nested
+ @DisplayName("Async")
+ class Async extends HttpBinAsyncCompatTest {
+
+ public Async() throws Exception {
+ super(targetContainerHost());
+ }
+
}
}
diff --git a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/compatibility/NginxCompatIT.java b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/compatibility/NginxCompatIT.java
new file mode 100644
index 000000000..3a8a632b1
--- /dev/null
+++ b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/compatibility/NginxCompatIT.java
@@ -0,0 +1,128 @@
+/*
+ * ====================================================================
+ * 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.compatibility;
+
+import org.apache.hc.core5.http.HttpHost;
+import org.apache.hc.core5.http.URIScheme;
+import org.apache.hc.core5.http2.HttpVersionPolicy;
+import org.apache.hc.core5.testing.compatibility.classic.ClassicHttpCompatTest;
+import org.apache.hc.core5.testing.compatibility.nio.AsyncHttp1CompatTest;
+import org.apache.hc.core5.testing.compatibility.nio.AsyncHttp2CompatTest;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+import org.testcontainers.containers.GenericContainer;
+import org.testcontainers.containers.Network;
+import org.testcontainers.junit.jupiter.Container;
+import org.testcontainers.junit.jupiter.Testcontainers;
+
+@Testcontainers(disabledWithoutDocker = true)
+class NginxCompatIT {
+
+ private static Network NETWORK = Network.newNetwork();
+ @Container
+ static final GenericContainer<?> NGINX_CONTAINER = ContainerImages.nginx(NETWORK);
+
+ @AfterAll
+ static void cleanup() {
+ NGINX_CONTAINER.close();
+ }
+
+ static HttpHost targetContainerHost() {
+ return new HttpHost(URIScheme.HTTP.id, NGINX_CONTAINER.getHost(), NGINX_CONTAINER.getMappedPort(ContainerImages.HTTP_PORT));
+ }
+
+ static HttpHost targetContainerH2CHost() {
+ return new HttpHost(URIScheme.HTTP.id, NGINX_CONTAINER.getHost(), NGINX_CONTAINER.getMappedPort(ContainerImages.H2C_PORT));
+ }
+
+ static HttpHost targetContainerTLSHost() {
+ return new HttpHost(URIScheme.HTTPS.id, NGINX_CONTAINER.getHost(), NGINX_CONTAINER.getMappedPort(ContainerImages.HTTPS_PORT));
+ }
+
+ @Nested
+ @DisplayName("Classic, HTTP/1, plain")
+ class ClassicHttp1 extends ClassicHttpCompatTest {
+
+ public ClassicHttp1() throws Exception {
+ super(targetContainerHost());
+ }
+
+ }
+
+ @Nested
+ @DisplayName("Classic, HTTP/1, TLS")
+ class ClassicHttp1Tls extends ClassicHttpCompatTest {
+
+ public ClassicHttp1Tls() throws Exception {
+ super(targetContainerTLSHost());
+ }
+
+ }
+
+ @Nested
+ @DisplayName("Async, HTTP/1, plain")
+ class AsyncHttp1 extends AsyncHttp1CompatTest {
+
+ public AsyncHttp1() throws Exception {
+ super(targetContainerHost());
+ }
+
+ }
+
+ @Nested
+ @DisplayName("Async, HTTP/2, plain")
+ class AsyncHttp2 extends AsyncHttp2CompatTest {
+
+ public AsyncHttp2() throws Exception {
+ super(targetContainerH2CHost(), HttpVersionPolicy.FORCE_HTTP_2);
+ }
+
+ }
+
+ @Nested
+ @DisplayName("Async, HTTP/1, TLS")
+ class AsyncHttp1Tls extends AsyncHttp1CompatTest {
+
+ public AsyncHttp1Tls() throws Exception {
+ super(targetContainerTLSHost());
+ }
+
+ }
+
+ @Nested
+ @DisplayName("Async, HTTP/2, TLS")
+ class AsyncHttp2Tls extends AsyncHttp2CompatTest {
+
+ public AsyncHttp2Tls() throws Exception {
+ super(targetContainerTLSHost(), HttpVersionPolicy.FORCE_HTTP_2);
+ }
+
+ }
+
+}
diff --git a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/compatibility/http2/NginxCompatIT.java b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/compatibility/TLSTestContexts.java
similarity index 55%
rename from httpcore5-testing/src/test/java/org/apache/hc/core5/testing/compatibility/http2/NginxCompatIT.java
rename to httpcore5-testing/src/test/java/org/apache/hc/core5/testing/compatibility/TLSTestContexts.java
index 06ef115bc..527f90aa7 100644
--- a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/compatibility/http2/NginxCompatIT.java
+++ b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/compatibility/TLSTestContexts.java
@@ -25,35 +25,32 @@
*
*/
-package org.apache.hc.core5.testing.compatibility.http2;
-
-import org.apache.hc.core5.http.HttpHost;
-import org.apache.hc.core5.http2.impl.nio.bootstrap.H2RequesterBootstrap;
-import org.apache.hc.core5.testing.compatibility.ContainerImages;
-import org.junit.jupiter.api.AfterAll;
-import org.testcontainers.containers.GenericContainer;
-import org.testcontainers.junit.jupiter.Container;
-import org.testcontainers.junit.jupiter.Testcontainers;
-
-@Testcontainers(disabledWithoutDocker = true)
-class NginxCompatIT extends AbstractHttp2CompatIT {
-
- @Container
- static final GenericContainer<?> CONTAINER = ContainerImages.ngnix();
-
- @Override
- void configure(final H2RequesterBootstrap bootstrap) {
- }
-
- HttpHost targetHost() {
- return new HttpHost("http",
- CONTAINER.getHost(),
- CONTAINER.getMappedPort(ContainerImages.HTTP_PORT));
- }
-
- @AfterAll
- static void cleanup() {
- CONTAINER.close();
+package org.apache.hc.core5.testing.compatibility;
+
+import java.io.IOException;
+import java.net.URL;
+import java.security.KeyManagementException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+
+import javax.net.ssl.SSLContext;
+
+import org.apache.hc.core5.ssl.SSLContextBuilder;
+
+public final class TLSTestContexts {
+
+ public static SSLContext createClientSSLContext() {
+ final URL keyStoreURL = TLSTestContexts.class.getResource("/test-ca.jks");
+ final String storePassword = "nopassword";
+ try {
+ return SSLContextBuilder.create()
+ .loadTrustMaterial(keyStoreURL, storePassword.toCharArray())
+ .build();
+ } catch (final NoSuchAlgorithmException | KeyManagementException | KeyStoreException | CertificateException |
+ IOException ex) {
+ throw new IllegalStateException(ex);
+ }
}
}
diff --git a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/compatibility/classic/ClassicHttpCompatTest.java b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/compatibility/classic/ClassicHttpCompatTest.java
new file mode 100644
index 000000000..3b8cd1bbc
--- /dev/null
+++ b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/compatibility/classic/ClassicHttpCompatTest.java
@@ -0,0 +1,154 @@
+/*
+ * ====================================================================
+ * 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.compatibility.classic;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import java.util.Queue;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Consumer;
+
+import org.apache.hc.core5.http.ClassicHttpRequest;
+import org.apache.hc.core5.http.HttpHost;
+import org.apache.hc.core5.http.HttpStatus;
+import org.apache.hc.core5.http.impl.bootstrap.HttpRequester;
+import org.apache.hc.core5.http.impl.bootstrap.RequesterBootstrap;
+import org.apache.hc.core5.http.io.SocketConfig;
+import org.apache.hc.core5.http.io.entity.EntityUtils;
+import org.apache.hc.core5.http.io.support.ClassicRequestBuilder;
+import org.apache.hc.core5.http.protocol.HttpCoreContext;
+import org.apache.hc.core5.testing.compatibility.ContainerImages;
+import org.apache.hc.core5.testing.compatibility.Result;
+import org.apache.hc.core5.testing.compatibility.TLSTestContexts;
+import org.apache.hc.core5.testing.extension.classic.HttpRequesterResource;
+import org.apache.hc.core5.util.Timeout;
+import org.hamcrest.CoreMatchers;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+public abstract class ClassicHttpCompatTest {
+
+ static final Timeout TIMEOUT = Timeout.ofSeconds(5);
+
+ private final HttpHost target;
+ @RegisterExtension
+ private final HttpRequesterResource clientResource;
+
+ public ClassicHttpCompatTest(final HttpHost target) {
+ this.target = target;
+ this.clientResource = new HttpRequesterResource();
+ this.clientResource.configure(bootstrap -> bootstrap
+ .setSocketConfig(SocketConfig.custom()
+ .setSoTimeout(TIMEOUT)
+ .build())
+ .setSslContext(TLSTestContexts.createClientSSLContext())
+ );
+ }
+
+ void configure(final Consumer<RequesterBootstrap> customizer) {
+ clientResource.configure(customizer);
+ }
+
+ HttpRequester client() {
+ return clientResource.start();
+ }
+
+ @Test
+ void test_sequential_requests() throws Exception {
+ final HttpRequester requester = client();
+
+ final int n = 20;
+ for (int i = 0; i < n; i++) {
+ final HttpCoreContext context = HttpCoreContext.create();
+ final ClassicHttpRequest request = ClassicRequestBuilder.get("/aaa")
+ .setHttpHost(target)
+ .build();
+ requester.execute(target, request, TIMEOUT, context, response -> {
+ assertThat(response.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
+ final String body1 = EntityUtils.toString(response.getEntity());
+ assertThat(body1, CoreMatchers.equalTo(ContainerImages.AAA));
+ return null;
+ });
+ }
+ }
+
+ @Test
+ void test_multi_threaded_requests() throws Exception {
+ final HttpRequester requester = client();
+
+ final int c = 10;
+ final AtomicInteger n = new AtomicInteger(20 * c);
+ final CountDownLatch countDownLatch = new CountDownLatch(c);
+ final Queue<Result<String>> resultQueue = new ConcurrentLinkedQueue<>();
+ final ExecutorService executorService = Executors.newFixedThreadPool(c);
+ try {
+ for (int i = 0; i < c; i++) {
+ executorService.execute(() -> {
+ try {
+ while (n.decrementAndGet() > 0) {
+ final HttpCoreContext context = HttpCoreContext.create();
+ final ClassicHttpRequest request = ClassicRequestBuilder.get("/aaa")
+ .setHttpHost(target)
+ .build();
+ try {
+ requester.execute(target, request, TIMEOUT, context, response -> {
+ resultQueue.add(new Result<>(
+ request,
+ response,
+ EntityUtils.toString(response.getEntity())));
+ return null;
+ });
+ } catch (final Exception ex) {
+ resultQueue.add(new Result<>(request, ex));
+ }
+ }
+ } finally {
+ countDownLatch.countDown();
+ }
+ });
+ }
+ Assertions.assertTrue(countDownLatch.await(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit()), "Request executions have not completed in time");
+ for (final Result<String> result : resultQueue) {
+ if (result.isOK()) {
+ Assertions.assertNotNull(result.response);
+ Assertions.assertEquals(HttpStatus.SC_OK, result.response.getCode(), "Response message returned non 200 status");
+ } else {
+ Assertions.fail(result.exception);
+ }
+ }
+ } finally {
+ executorService.shutdownNow();
+ }
+ }
+
+}
diff --git a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/compatibility/classic/HttpBinClassicCompatTest.java b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/compatibility/classic/HttpBinClassicCompatTest.java
new file mode 100644
index 000000000..bf447fd0e
--- /dev/null
+++ b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/compatibility/classic/HttpBinClassicCompatTest.java
@@ -0,0 +1,121 @@
+/*
+ * ====================================================================
+ * 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.compatibility.classic;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.function.Consumer;
+
+import org.apache.hc.core5.http.ClassicHttpRequest;
+import org.apache.hc.core5.http.ContentType;
+import org.apache.hc.core5.http.HttpHost;
+import org.apache.hc.core5.http.HttpStatus;
+import org.apache.hc.core5.http.impl.bootstrap.HttpRequester;
+import org.apache.hc.core5.http.impl.bootstrap.RequesterBootstrap;
+import org.apache.hc.core5.http.io.SocketConfig;
+import org.apache.hc.core5.http.io.entity.StringEntity;
+import org.apache.hc.core5.http.io.support.ClassicRequestBuilder;
+import org.apache.hc.core5.http.protocol.HttpCoreContext;
+import org.apache.hc.core5.testing.extension.classic.HttpRequesterResource;
+import org.apache.hc.core5.util.Timeout;
+import org.hamcrest.CoreMatchers;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+public abstract class HttpBinClassicCompatTest {
+
+ static final Timeout TIMEOUT = Timeout.ofSeconds(5);
+
+ private final HttpHost target;
+ @RegisterExtension
+ private final HttpRequesterResource clientResource;
+
+ public HttpBinClassicCompatTest(final HttpHost target) {
+ this.target = target;
+ this.clientResource = new HttpRequesterResource();
+ this.clientResource.configure(bootstrap -> bootstrap
+ .setSocketConfig(SocketConfig.custom()
+ .setSoTimeout(TIMEOUT)
+ .build())
+ );
+ }
+
+ void configure(final Consumer<RequesterBootstrap> customizer) {
+ clientResource.configure(customizer);
+ }
+
+ HttpRequester client() {
+ return clientResource.start();
+ }
+
+ @Test
+ void test_sequential_request_execution() throws Exception {
+ final HttpRequester client = client();
+ final List<ClassicHttpRequest> requestMessages = Arrays.asList(
+ ClassicRequestBuilder.get("/headers")
+ .setHttpHost(target)
+ .build(),
+ ClassicRequestBuilder.post("/anything")
+ .setHttpHost(target)
+ .setEntity(new StringEntity("some important message", ContentType.TEXT_PLAIN))
+ .build(),
+ ClassicRequestBuilder.put("/anything")
+ .setHttpHost(target)
+ .setEntity(new StringEntity("some important message", ContentType.TEXT_PLAIN))
+ .build(),
+ ClassicRequestBuilder.get("/drip")
+ .setHttpHost(target)
+ .build(),
+ ClassicRequestBuilder.get("/bytes/20000")
+ .setHttpHost(target)
+ .build(),
+ ClassicRequestBuilder.get("/delay/2")
+ .setHttpHost(target)
+ .build(),
+ ClassicRequestBuilder.post("/delay/2")
+ .setHttpHost(target)
+ .setEntity(new StringEntity("some important message", ContentType.TEXT_PLAIN))
+ .build(),
+ ClassicRequestBuilder.put("/delay/2")
+ .setHttpHost(target)
+ .setEntity(new StringEntity("some important message", ContentType.TEXT_PLAIN))
+ .build()
+ );
+
+ for (final ClassicHttpRequest request : requestMessages) {
+ final HttpCoreContext context = HttpCoreContext.create();
+ client.execute(target, request, TIMEOUT, context, response -> {
+ assertThat(response.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
+ return null;
+ });
+ }
+ }
+
+}
diff --git a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/compatibility/nio/AsyncHttp1CompatTest.java b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/compatibility/nio/AsyncHttp1CompatTest.java
new file mode 100644
index 000000000..2ddd89ec4
--- /dev/null
+++ b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/compatibility/nio/AsyncHttp1CompatTest.java
@@ -0,0 +1,70 @@
+/*
+ * ====================================================================
+ * 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.compatibility.nio;
+
+import java.util.function.Consumer;
+
+import org.apache.hc.core5.http.HttpHost;
+import org.apache.hc.core5.http.nio.ssl.BasicClientTlsStrategy;
+import org.apache.hc.core5.http2.HttpVersionPolicy;
+import org.apache.hc.core5.http2.impl.nio.bootstrap.H2AsyncRequester;
+import org.apache.hc.core5.http2.impl.nio.bootstrap.H2RequesterBootstrap;
+import org.apache.hc.core5.reactor.IOReactorConfig;
+import org.apache.hc.core5.testing.compatibility.TLSTestContexts;
+import org.apache.hc.core5.testing.extension.nio.H2AsyncRequesterResource;
+import org.apache.hc.core5.util.Timeout;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+public abstract class AsyncHttp1CompatTest extends AsyncHttpCompatTest<H2AsyncRequester> {
+
+ static final Timeout TIMEOUT = Timeout.ofSeconds(5);
+
+ @RegisterExtension
+ private final H2AsyncRequesterResource clientResource;
+
+ public AsyncHttp1CompatTest(final HttpHost target) {
+ super(target);
+ this.clientResource = new H2AsyncRequesterResource();
+ this.clientResource.configure(bootstrap -> bootstrap
+ .setIOReactorConfig(IOReactorConfig.custom()
+ .setSoTimeout(TIMEOUT)
+ .build())
+ .setTlsStrategy(new BasicClientTlsStrategy(TLSTestContexts.createClientSSLContext()))
+ .setVersionPolicy(HttpVersionPolicy.FORCE_HTTP_1));
+ }
+
+ void configure(final Consumer<H2RequesterBootstrap> customizer) {
+ clientResource.configure(customizer);
+ }
+
+ @Override
+ H2AsyncRequester client() {
+ return clientResource.start();
+ }
+
+}
diff --git a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/compatibility/http2/AbstractHttp2CompatIT.java b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/compatibility/nio/AsyncHttp2CompatTest.java
similarity index 57%
copy from httpcore5-testing/src/test/java/org/apache/hc/core5/testing/compatibility/http2/AbstractHttp2CompatIT.java
copy to httpcore5-testing/src/test/java/org/apache/hc/core5/testing/compatibility/nio/AsyncHttp2CompatTest.java
index a2c80620f..e1f2fa577 100644
--- a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/compatibility/http2/AbstractHttp2CompatIT.java
+++ b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/compatibility/nio/AsyncHttp2CompatTest.java
@@ -25,12 +25,13 @@
*
*/
-package org.apache.hc.core5.testing.compatibility.http2;
+package org.apache.hc.core5.testing.compatibility.nio;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Future;
+import java.util.function.Consumer;
import org.apache.hc.core5.concurrent.FutureCallback;
import org.apache.hc.core5.http.HttpHost;
@@ -40,7 +41,6 @@ import org.apache.hc.core5.http.HttpStatus;
import org.apache.hc.core5.http.Message;
import org.apache.hc.core5.http.Method;
import org.apache.hc.core5.http.RequestNotExecutedException;
-import org.apache.hc.core5.http.impl.bootstrap.HttpAsyncRequester;
import org.apache.hc.core5.http.message.BasicHttpRequest;
import org.apache.hc.core5.http.nio.AsyncClientEndpoint;
import org.apache.hc.core5.http.nio.entity.StringAsyncEntityConsumer;
@@ -49,119 +49,54 @@ import org.apache.hc.core5.http.nio.support.BasicRequestProducer;
import org.apache.hc.core5.http.nio.support.BasicResponseConsumer;
import org.apache.hc.core5.http2.HttpVersionPolicy;
import org.apache.hc.core5.http2.config.H2Config;
+import org.apache.hc.core5.http2.impl.nio.bootstrap.H2AsyncRequester;
import org.apache.hc.core5.http2.impl.nio.bootstrap.H2RequesterBootstrap;
-import org.apache.hc.core5.io.CloseMode;
+import org.apache.hc.core5.http2.ssl.H2ClientTlsStrategy;
import org.apache.hc.core5.reactor.IOReactorConfig;
-import org.apache.hc.core5.testing.classic.LoggingConnPoolListener;
-import org.apache.hc.core5.testing.compatibility.ContainerImages;
import org.apache.hc.core5.testing.compatibility.Result;
-import org.apache.hc.core5.testing.nio.LoggingExceptionCallback;
-import org.apache.hc.core5.testing.nio.LoggingH2StreamListener;
-import org.apache.hc.core5.testing.nio.LoggingHttp1StreamListener;
-import org.apache.hc.core5.testing.nio.LoggingIOSessionDecorator;
-import org.apache.hc.core5.testing.nio.LoggingIOSessionListener;
-import org.apache.hc.core5.testing.nio.LoggingReactorMetricsListener;
+import org.apache.hc.core5.testing.compatibility.TLSTestContexts;
+import org.apache.hc.core5.testing.extension.nio.H2AsyncRequesterResource;
import org.apache.hc.core5.util.Timeout;
-import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
-abstract class AbstractHttp2CompatIT {
+public abstract class AsyncHttp2CompatTest extends AsyncHttpCompatTest<H2AsyncRequester> {
static final Timeout TIMEOUT = Timeout.ofSeconds(5);
- abstract HttpHost targetHost();
+ private final HttpHost target;
+ @RegisterExtension
+ private final H2AsyncRequesterResource clientResource;
- HttpAsyncRequester client;
-
- abstract void configure(H2RequesterBootstrap bootstrap);
-
- @BeforeEach
- void start() throws Exception {
- final H2RequesterBootstrap bootstrap = H2RequesterBootstrap.bootstrap()
+ public AsyncHttp2CompatTest(final HttpHost target, final HttpVersionPolicy versionPolicy) {
+ super(target);
+ this.target = target;
+ this.clientResource = new H2AsyncRequesterResource();
+ this.clientResource.configure(bootstrap -> bootstrap
.setIOReactorConfig(IOReactorConfig.custom()
.setSoTimeout(TIMEOUT)
.build())
.setH2Config(H2Config.custom()
.setPushEnabled(true)
.build())
- .setStreamListener(LoggingHttp1StreamListener.INSTANCE_CLIENT)
- .setStreamListener(LoggingH2StreamListener.INSTANCE)
- .setConnPoolListener(LoggingConnPoolListener.INSTANCE)
- .setIOSessionDecorator(LoggingIOSessionDecorator.INSTANCE)
- .setExceptionCallback(LoggingExceptionCallback.INSTANCE)
- .setIOSessionListener(LoggingIOSessionListener.INSTANCE)
- .setIOReactorMetricsListener(LoggingReactorMetricsListener.INSTANCE);
- configure(bootstrap);
- client = bootstrap.create();
- client.start();
+ .setTlsStrategy(new H2ClientTlsStrategy(TLSTestContexts.createClientSSLContext()))
+ .setVersionPolicy(versionPolicy));
}
- @AfterEach
- void shutdown() throws Exception {
- if (client != null) {
- client.close(CloseMode.GRACEFUL);
- }
+ void configure(final Consumer<H2RequesterBootstrap> customizer) {
+ clientResource.configure(customizer);
}
- @Test
- void test_multiple_request_execution() throws Exception {
- final HttpHost target = targetHost();
- final Future<AsyncClientEndpoint> connectFuture = client.connect(target, TIMEOUT, HttpVersionPolicy.FORCE_HTTP_2, null);
- final AsyncClientEndpoint endpoint = connectFuture.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
- try {
- final int n = 20;
- final CountDownLatch countDownLatch = new CountDownLatch(n);
- final Queue<Result<String>> resultQueue = new ConcurrentLinkedQueue<>();
- for (int i = 0; i < n; i++) {
- final HttpRequest httpget = new BasicHttpRequest(Method.GET, target, "/aaa");
- endpoint.execute(
- new BasicRequestProducer(httpget, null),
- new BasicResponseConsumer<>(new StringAsyncEntityConsumer()),
- new FutureCallback<Message<HttpResponse, String>>() {
-
- @Override
- public void completed(final Message<HttpResponse, String> responseMessage) {
- resultQueue.add(new Result<>(
- httpget,
- responseMessage.getHead(),
- responseMessage.getBody()));
- countDownLatch.countDown();
- }
-
- @Override
- public void failed(final Exception ex) {
- resultQueue.add(new Result<>(httpget, ex));
- countDownLatch.countDown();
- }
-
- @Override
- public void cancelled() {
- failed(new RequestNotExecutedException());
- }
-
- });
- }
- Assertions.assertTrue(countDownLatch.await(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit()), "Request executions have not completed in time");
- for (final Result<String> result : resultQueue) {
- if (result.isOK()) {
- Assertions.assertNotNull(result.response);
- Assertions.assertEquals(HttpStatus.SC_OK, result.response.getCode(), "Response message returned non 200 status");
- Assertions.assertEquals(ContainerImages.AAA, result.content);
- } else {
- Assertions.fail(result.exception);
- }
- }
- } finally {
- endpoint.releaseAndDiscard();
- }
+ @Override
+ H2AsyncRequester client() {
+ return clientResource.start();
}
@Test
void test_request_execution_with_push() throws Exception {
- final HttpHost target = targetHost();
- final Future<AsyncClientEndpoint> connectFuture = client.connect(target, TIMEOUT, HttpVersionPolicy.FORCE_HTTP_2, null);
+ final H2AsyncRequester client = client();
+ final Future<AsyncClientEndpoint> connectFuture = client.connect(target, TIMEOUT, null, null);
final AsyncClientEndpoint endpoint = connectFuture.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
try {
final CountDownLatch countDownLatch = new CountDownLatch(4);
diff --git a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/compatibility/http2/AbstractHttp2CompatIT.java b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/compatibility/nio/AsyncHttpCompatTest.java
similarity index 56%
rename from httpcore5-testing/src/test/java/org/apache/hc/core5/testing/compatibility/http2/AbstractHttp2CompatIT.java
rename to httpcore5-testing/src/test/java/org/apache/hc/core5/testing/compatibility/nio/AsyncHttpCompatTest.java
index a2c80620f..3107316c8 100644
--- a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/compatibility/http2/AbstractHttp2CompatIT.java
+++ b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/compatibility/nio/AsyncHttpCompatTest.java
@@ -25,7 +25,7 @@
*
*/
-package org.apache.hc.core5.testing.compatibility.http2;
+package org.apache.hc.core5.testing.compatibility.nio;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
@@ -44,71 +44,30 @@ import org.apache.hc.core5.http.impl.bootstrap.HttpAsyncRequester;
import org.apache.hc.core5.http.message.BasicHttpRequest;
import org.apache.hc.core5.http.nio.AsyncClientEndpoint;
import org.apache.hc.core5.http.nio.entity.StringAsyncEntityConsumer;
-import org.apache.hc.core5.http.nio.support.AbstractAsyncPushHandler;
import org.apache.hc.core5.http.nio.support.BasicRequestProducer;
import org.apache.hc.core5.http.nio.support.BasicResponseConsumer;
-import org.apache.hc.core5.http2.HttpVersionPolicy;
-import org.apache.hc.core5.http2.config.H2Config;
-import org.apache.hc.core5.http2.impl.nio.bootstrap.H2RequesterBootstrap;
-import org.apache.hc.core5.io.CloseMode;
-import org.apache.hc.core5.reactor.IOReactorConfig;
-import org.apache.hc.core5.testing.classic.LoggingConnPoolListener;
import org.apache.hc.core5.testing.compatibility.ContainerImages;
import org.apache.hc.core5.testing.compatibility.Result;
-import org.apache.hc.core5.testing.nio.LoggingExceptionCallback;
-import org.apache.hc.core5.testing.nio.LoggingH2StreamListener;
-import org.apache.hc.core5.testing.nio.LoggingHttp1StreamListener;
-import org.apache.hc.core5.testing.nio.LoggingIOSessionDecorator;
-import org.apache.hc.core5.testing.nio.LoggingIOSessionListener;
-import org.apache.hc.core5.testing.nio.LoggingReactorMetricsListener;
import org.apache.hc.core5.util.Timeout;
-import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
-abstract class AbstractHttp2CompatIT {
+public abstract class AsyncHttpCompatTest<T extends HttpAsyncRequester> {
static final Timeout TIMEOUT = Timeout.ofSeconds(5);
- abstract HttpHost targetHost();
-
- HttpAsyncRequester client;
-
- abstract void configure(H2RequesterBootstrap bootstrap);
-
- @BeforeEach
- void start() throws Exception {
- final H2RequesterBootstrap bootstrap = H2RequesterBootstrap.bootstrap()
- .setIOReactorConfig(IOReactorConfig.custom()
- .setSoTimeout(TIMEOUT)
- .build())
- .setH2Config(H2Config.custom()
- .setPushEnabled(true)
- .build())
- .setStreamListener(LoggingHttp1StreamListener.INSTANCE_CLIENT)
- .setStreamListener(LoggingH2StreamListener.INSTANCE)
- .setConnPoolListener(LoggingConnPoolListener.INSTANCE)
- .setIOSessionDecorator(LoggingIOSessionDecorator.INSTANCE)
- .setExceptionCallback(LoggingExceptionCallback.INSTANCE)
- .setIOSessionListener(LoggingIOSessionListener.INSTANCE)
- .setIOReactorMetricsListener(LoggingReactorMetricsListener.INSTANCE);
- configure(bootstrap);
- client = bootstrap.create();
- client.start();
- }
+ private final HttpHost target;
- @AfterEach
- void shutdown() throws Exception {
- if (client != null) {
- client.close(CloseMode.GRACEFUL);
- }
+ public AsyncHttpCompatTest(final HttpHost target) {
+ this.target = target;
}
+ abstract T client();
+
@Test
- void test_multiple_request_execution() throws Exception {
- final HttpHost target = targetHost();
- final Future<AsyncClientEndpoint> connectFuture = client.connect(target, TIMEOUT, HttpVersionPolicy.FORCE_HTTP_2, null);
+ void test_multiple_request_execution_over_same_connection() throws Exception {
+ final HttpAsyncRequester client = client();
+ final Future<AsyncClientEndpoint> connectFuture = client.connect(target, TIMEOUT, null, null);
final AsyncClientEndpoint endpoint = connectFuture.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
try {
final int n = 20;
@@ -159,37 +118,20 @@ abstract class AbstractHttp2CompatIT {
}
@Test
- void test_request_execution_with_push() throws Exception {
- final HttpHost target = targetHost();
- final Future<AsyncClientEndpoint> connectFuture = client.connect(target, TIMEOUT, HttpVersionPolicy.FORCE_HTTP_2, null);
- final AsyncClientEndpoint endpoint = connectFuture.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
- try {
- final CountDownLatch countDownLatch = new CountDownLatch(4);
- final Queue<Result<String>> resultQueue = new ConcurrentLinkedQueue<>();
- final HttpRequest httpget = new BasicHttpRequest(Method.GET, target, "/pushy");
- endpoint.execute(
+ void test_multiple_request_execution_over_multiple_connections() throws Exception {
+ final HttpAsyncRequester client = client();
+ final int c = 10;
+ client.setDefaultMaxPerRoute(10);
+ final int n = 20 * c;
+ final CountDownLatch countDownLatch = new CountDownLatch(n);
+ final Queue<Result<String>> resultQueue = new ConcurrentLinkedQueue<>();
+ for (int i = 0; i < n; i++) {
+ final HttpRequest httpget = new BasicHttpRequest(Method.GET, target, "/aaa");
+ client.execute(
+ target,
new BasicRequestProducer(httpget, null),
new BasicResponseConsumer<>(new StringAsyncEntityConsumer()),
- (request, context) ->
- new AbstractAsyncPushHandler<Message<HttpResponse, String>>(new BasicResponseConsumer<>(new StringAsyncEntityConsumer())) {
-
- @Override
- protected void handleResponse(final HttpRequest promise, final Message<HttpResponse, String> responseMessage) {
- resultQueue.add(new Result<>(
- httpget,
- responseMessage.getHead(),
- responseMessage.getBody()));
- countDownLatch.countDown();
- }
-
- @Override
- protected void handleError(final HttpRequest promise, final Exception cause) {
- resultQueue.add(new Result<>(httpget, cause));
- countDownLatch.countDown();
- }
-
- },
- null,
+ TIMEOUT,
new FutureCallback<Message<HttpResponse, String>>() {
@Override
@@ -213,17 +155,16 @@ abstract class AbstractHttp2CompatIT {
}
});
- Assertions.assertTrue(countDownLatch.await(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit()), "Request executions have not completed in time");
- for (final Result<String> result : resultQueue) {
- if (result.isOK()) {
- Assertions.assertNotNull(result.response);
- Assertions.assertEquals(HttpStatus.SC_OK, result.response.getCode(), "Response message returned non 200 status");
- } else {
- Assertions.fail(result.exception);
- }
+ }
+ Assertions.assertTrue(countDownLatch.await(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit()), "Request executions have not completed in time");
+ for (final Result<String> result : resultQueue) {
+ if (result.isOK()) {
+ Assertions.assertNotNull(result.response);
+ Assertions.assertEquals(HttpStatus.SC_OK, result.response.getCode(), "Response message returned non 200 status");
+ Assertions.assertEquals(ContainerImages.AAA, result.content);
+ } else {
+ Assertions.fail(result.exception);
}
- } finally {
- endpoint.releaseAndDiscard();
}
}
diff --git a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/compatibility/http1/HttpBinCompatIT.java b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/compatibility/nio/HttpBinAsyncCompatTest.java
similarity index 78%
rename from httpcore5-testing/src/test/java/org/apache/hc/core5/testing/compatibility/http1/HttpBinCompatIT.java
rename to httpcore5-testing/src/test/java/org/apache/hc/core5/testing/compatibility/nio/HttpBinAsyncCompatTest.java
index 38b063d88..f0dd5f5aa 100644
--- a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/compatibility/http1/HttpBinCompatIT.java
+++ b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/compatibility/nio/HttpBinAsyncCompatTest.java
@@ -25,7 +25,7 @@
*
*/
-package org.apache.hc.core5.testing.compatibility.http1;
+package org.apache.hc.core5.testing.compatibility.nio;
import java.nio.charset.CodingErrorAction;
import java.nio.charset.StandardCharsets;
@@ -54,76 +54,41 @@ import org.apache.hc.core5.http.nio.entity.StringAsyncEntityConsumer;
import org.apache.hc.core5.http.nio.entity.StringAsyncEntityProducer;
import org.apache.hc.core5.http.nio.support.BasicRequestProducer;
import org.apache.hc.core5.http.nio.support.BasicResponseConsumer;
-import org.apache.hc.core5.http2.impl.nio.bootstrap.H2RequesterBootstrap;
-import org.apache.hc.core5.io.CloseMode;
+import org.apache.hc.core5.http2.HttpVersionPolicy;
+import org.apache.hc.core5.http2.impl.nio.bootstrap.H2AsyncRequester;
import org.apache.hc.core5.reactor.IOReactorConfig;
-import org.apache.hc.core5.testing.classic.LoggingConnPoolListener;
-import org.apache.hc.core5.testing.compatibility.ContainerImages;
import org.apache.hc.core5.testing.compatibility.Result;
-import org.apache.hc.core5.testing.nio.LoggingExceptionCallback;
-import org.apache.hc.core5.testing.nio.LoggingH2StreamListener;
-import org.apache.hc.core5.testing.nio.LoggingHttp1StreamListener;
-import org.apache.hc.core5.testing.nio.LoggingIOSessionDecorator;
-import org.apache.hc.core5.testing.nio.LoggingIOSessionListener;
-import org.apache.hc.core5.testing.nio.LoggingReactorMetricsListener;
+import org.apache.hc.core5.testing.extension.nio.H2AsyncRequesterResource;
import org.apache.hc.core5.util.Timeout;
-import org.junit.jupiter.api.AfterAll;
-import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
-import org.testcontainers.containers.GenericContainer;
-import org.testcontainers.junit.jupiter.Container;
-import org.testcontainers.junit.jupiter.Testcontainers;
+import org.junit.jupiter.api.extension.RegisterExtension;
-@Testcontainers(disabledWithoutDocker = true)
-class HttpBinCompatIT {
+public abstract class HttpBinAsyncCompatTest {
static final Timeout TIMEOUT = Timeout.ofSeconds(5);
- @Container
- static final GenericContainer<?> CONTAINER = ContainerImages.httpBin();
+ private final HttpHost target;
+ @RegisterExtension
+ private final H2AsyncRequesterResource clientResource;
- static HttpHost targetHost() {
- return new HttpHost("http",
- CONTAINER.getHost(),
- CONTAINER.getMappedPort(ContainerImages.HTTP_PORT));
- }
-
- HttpAsyncRequester client;
-
- @BeforeEach
- void start() throws Exception {
- client = H2RequesterBootstrap.bootstrap()
+ public HttpBinAsyncCompatTest(final HttpHost target) {
+ this.target = target;
+ this.clientResource = new H2AsyncRequesterResource();
+ this.clientResource.configure(bootstrap -> bootstrap
.setIOReactorConfig(IOReactorConfig.custom()
.setSoTimeout(TIMEOUT)
.build())
- .setStreamListener(LoggingHttp1StreamListener.INSTANCE_CLIENT)
- .setStreamListener(LoggingH2StreamListener.INSTANCE)
- .setConnPoolListener(LoggingConnPoolListener.INSTANCE)
- .setIOSessionDecorator(LoggingIOSessionDecorator.INSTANCE)
- .setExceptionCallback(LoggingExceptionCallback.INSTANCE)
- .setIOSessionListener(LoggingIOSessionListener.INSTANCE)
- .setIOReactorMetricsListener(LoggingReactorMetricsListener.INSTANCE)
- .create();
- client.start();
- }
-
- @AfterEach
- void shutdown() throws Exception {
- if (client != null) {
- client.close(CloseMode.GRACEFUL);
- }
+ .setVersionPolicy(HttpVersionPolicy.FORCE_HTTP_1));
}
- @AfterAll
- static void cleanup() {
- CONTAINER.close();
+ H2AsyncRequester client() {
+ return clientResource.start();
}
@Test
void test_sequential_request_execution() throws Exception {
- final HttpHost target = targetHost();
+ final HttpAsyncRequester client = client();
final List<Message<HttpRequest, AsyncEntityProducer>> requestMessages = Arrays.asList(
new Message<>(new BasicHttpRequest(Method.GET, target, "/headers")),
new Message<>(
@@ -162,7 +127,7 @@ class HttpBinCompatIT {
@Test
void test_pipelined_request_execution() throws Exception {
- final HttpHost target = targetHost();
+ final HttpAsyncRequester client = client();
final Future<AsyncClientEndpoint> connectFuture = client.connect(target, TIMEOUT);
final AsyncClientEndpoint streamEndpoint = connectFuture.get();
try {
diff --git a/httpcore5-testing/src/test/resources/docker/BUILDING.txt b/httpcore5-testing/src/test/resources/docker/BUILDING.txt
new file mode 100644
index 000000000..8896f184f
--- /dev/null
+++ b/httpcore5-testing/src/test/resources/docker/BUILDING.txt
@@ -0,0 +1,43 @@
+= SSL key / cert material
+
+Execute in the project root
+
+# Issue a certificate request
+---
+openssl req -config test-CA/openssl.cnf -new -nodes -sha256 -days 36500 \
+ -subj '/O=Apache Software Foundation/OU=HttpComponents Project/CN=localhost/emailAddress=dev@hc.apache.org/' \
+ -addext 'subjectAltName = DNS:localhost' \
+ -keyout httpcore5-testing/src/test/resources/docker/server-key.pem \
+ -out httpcore5-testing/src/test/resources/docker/server-certreq.pem
+---
+# Verify the request
+---
+openssl req -in httpcore5-testing/src/test/resources/docker/server-certreq.pem -text -noout
+---
+# Sign new certificate with the test CA key
+---
+openssl ca -config test-CA/openssl.cnf -days 36500 \
+ -out httpcore5-testing/src/test/resources/docker/server-cert.pem \
+ -in httpcore5-testing/src/test/resources/docker/server-certreq.pem \
+ && rm httpcore5-testing/src/test/resources/docker/server-certreq.pem
+---
+
+# Create JKS store with the Test CA cert
+keytool -import -trustcacerts -alias test-ca -file test-CA/ca-cert.pem -keystore httpcore5-testing/src/test/resources/test-ca.jks -storepass nopassword
+
+= Running a local version of HttpBin
+
+# Create container
+---
+docker container create -it --name test-httpbin -p 8080:80 kennethreitz/httpbin:latest
+docker start test-httpbin
+docker logs test-httpbin
+---
+# Trouble-shoot container
+---
+docker exec -it test-httpbin bash
+---
+# Delete container
+---
+docker rm --force test-httpbin
+---
\ No newline at end of file
diff --git a/httpcore5-testing/src/test/resources/docker/httpd/httpd-vhosts.conf b/httpcore5-testing/src/test/resources/docker/httpd/httpd-default.conf
similarity index 79%
rename from httpcore5-testing/src/test/resources/docker/httpd/httpd-vhosts.conf
rename to httpcore5-testing/src/test/resources/docker/httpd/httpd-default.conf
index fa29ea9c4..8465bdf60 100644
--- a/httpcore5-testing/src/test/resources/docker/httpd/httpd-vhosts.conf
+++ b/httpcore5-testing/src/test/resources/docker/httpd/httpd-default.conf
@@ -13,10 +13,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-ServerName localhost:80
-
-Protocols h2c http/1.1
-
<Directory />
AllowOverride none
Require all denied
@@ -29,15 +25,7 @@ DocumentRoot "/var/httpd/www"
Require all granted
</Directory>
-<IfModule http2_module>
- LogLevel http2:info
- H2Push on
- H2EarlyHints on
-
- <Location /pushy>
- H2PushResource /aaa
- H2PushResource /bbb
- H2PushResource /ccc
- </Location>
-
-</IfModule>
+<VirtualHost _default_:80>
+ ServerName localhost:80
+ Protocols http/1.1
+</VirtualHost>
diff --git a/httpcore5-testing/src/test/resources/docker/ngnix/default.conf b/httpcore5-testing/src/test/resources/docker/httpd/httpd-h2c.conf
similarity index 67%
copy from httpcore5-testing/src/test/resources/docker/ngnix/default.conf
copy to httpcore5-testing/src/test/resources/docker/httpd/httpd-h2c.conf
index c48cd4248..9091a37dd 100644
--- a/httpcore5-testing/src/test/resources/docker/ngnix/default.conf
+++ b/httpcore5-testing/src/test/resources/docker/httpd/httpd-h2c.conf
@@ -13,24 +13,22 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-server {
- listen 80 http2;
- server_name localhost;
+Listen 81
- location / {
- root /var/nginx/www;
+<VirtualHost _default_:81>
+ ServerName localhost:81
+ Protocols h2c
- location = /pushy {
- http2_push "/aaa";
- http2_push "/bbb";
- http2_push "/ccc";
- }
- }
+ <IfModule http2_module>
+ LogLevel http2:info
+ H2Push on
+ H2EarlyHints on
- error_page 500 502 503 504 /50x.html;
- location = /50x.html {
- root /usr/share/nginx/html;
- }
-
-}
+ <Location /pushy>
+ H2PushResource /aaa
+ H2PushResource /bbb
+ H2PushResource /ccc
+ </Location>
+ </IfModule>
+</VirtualHost>
diff --git a/httpcore5-testing/src/test/resources/docker/httpd/httpd-ssl.conf b/httpcore5-testing/src/test/resources/docker/httpd/httpd-ssl.conf
new file mode 100644
index 000000000..d9722d24c
--- /dev/null
+++ b/httpcore5-testing/src/test/resources/docker/httpd/httpd-ssl.conf
@@ -0,0 +1,53 @@
+# 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.
+#
+
+Listen 443
+
+SSLCipherSuite HIGH:MEDIUM:!MD5:!RC4:!3DES
+SSLProxyCipherSuite HIGH:MEDIUM:!MD5:!RC4:!3DES
+
+SSLHonorCipherOrder on
+
+SSLProtocol all -SSLv3
+SSLProxyProtocol all -SSLv3
+
+SSLPassPhraseDialog builtin
+
+SSLSessionCacheTimeout 300
+
+<VirtualHost _default_:443>
+ ServerName localhost:443
+ Protocols h2 http/1.1
+
+ SSLEngine on
+ SSLCertificateFile "/usr/local/apache2/conf/server-cert.pem"
+ SSLCertificateKeyFile "/usr/local/apache2/conf/server-key.pem"
+ CustomLog /proc/self/fd/1 \
+ "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"
+
+ <IfModule http2_module>
+ LogLevel http2:info
+ H2Push on
+ H2EarlyHints on
+
+ <Location /pushy>
+ H2PushResource /aaa
+ H2PushResource /bbb
+ H2PushResource /ccc
+ </Location>
+ </IfModule>
+
+</VirtualHost>
diff --git a/httpcore5-testing/src/test/resources/docker/ngnix/default.conf b/httpcore5-testing/src/test/resources/docker/nginx/default.conf
similarity index 85%
copy from httpcore5-testing/src/test/resources/docker/ngnix/default.conf
copy to httpcore5-testing/src/test/resources/docker/nginx/default.conf
index c48cd4248..99b2ba4b7 100644
--- a/httpcore5-testing/src/test/resources/docker/ngnix/default.conf
+++ b/httpcore5-testing/src/test/resources/docker/nginx/default.conf
@@ -14,17 +14,11 @@
# limitations under the License.
server {
- listen 80 http2;
+ listen 80;
server_name localhost;
location / {
root /var/nginx/www;
-
- location = /pushy {
- http2_push "/aaa";
- http2_push "/bbb";
- http2_push "/ccc";
- }
}
error_page 500 502 503 504 /50x.html;
diff --git a/httpcore5-testing/src/test/resources/docker/ngnix/default.conf b/httpcore5-testing/src/test/resources/docker/nginx/h2c.conf
similarity index 97%
copy from httpcore5-testing/src/test/resources/docker/ngnix/default.conf
copy to httpcore5-testing/src/test/resources/docker/nginx/h2c.conf
index c48cd4248..f994f2f47 100644
--- a/httpcore5-testing/src/test/resources/docker/ngnix/default.conf
+++ b/httpcore5-testing/src/test/resources/docker/nginx/h2c.conf
@@ -14,7 +14,7 @@
# limitations under the License.
server {
- listen 80 http2;
+ listen 81 http2;
server_name localhost;
location / {
diff --git a/httpcore5-testing/src/test/resources/docker/ngnix/default.conf b/httpcore5-testing/src/test/resources/docker/nginx/ssl.conf
similarity index 83%
rename from httpcore5-testing/src/test/resources/docker/ngnix/default.conf
rename to httpcore5-testing/src/test/resources/docker/nginx/ssl.conf
index c48cd4248..e0d83e10a 100644
--- a/httpcore5-testing/src/test/resources/docker/ngnix/default.conf
+++ b/httpcore5-testing/src/test/resources/docker/nginx/ssl.conf
@@ -14,8 +14,12 @@
# limitations under the License.
server {
- listen 80 http2;
+ listen 443 ssl http2;
server_name localhost;
+ ssl_certificate /etc/nginx/server-cert.pem;
+ ssl_certificate_key /etc/nginx/server-key.pem;
+ ssl_protocols TLSv1.2 TLSv1.3;
+ ssl_ciphers HIGH:!aNULL:!MD5;
location / {
root /var/nginx/www;
diff --git a/httpcore5-testing/src/test/resources/docker/server-cert.pem b/httpcore5-testing/src/test/resources/docker/server-cert.pem
new file mode 100644
index 000000000..ce3990fdd
--- /dev/null
+++ b/httpcore5-testing/src/test/resources/docker/server-cert.pem
@@ -0,0 +1,83 @@
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 0 (0x0)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: O=Apache Software Foundation, OU=HttpComponents Project, CN=Test CA/emailAddress=dev@hc.apache.org
+ Validity
+ Not Before: Oct 20 11:31:00 2024 GMT
+ Not After : Sep 26 11:31:00 2124 GMT
+ Subject: O=Apache Software Foundation, OU=HttpComponents Project, CN=localhost/emailAddress=dev@hc.apache.org
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:9a:cf:ff:49:86:9e:3a:0b:0c:2f:4f:89:10:86:
+ 11:30:da:81:8c:9e:26:f7:72:9f:c7:d0:8e:16:67:
+ be:0a:46:ee:d2:9f:67:89:37:b8:38:84:16:d8:66:
+ c1:c8:9a:9f:64:c6:06:8c:57:fe:0d:83:58:4d:3d:
+ f3:d5:35:a7:89:e3:5e:1b:c8:48:b5:66:34:38:ec:
+ 9f:ac:1a:05:81:66:0f:d4:9f:af:a9:0c:bf:20:51:
+ e5:1c:21:63:a5:95:39:86:b0:d6:eb:9d:9a:29:be:
+ 83:df:ef:6b:08:e4:e3:2e:a3:1e:49:4c:b1:2a:f7:
+ 89:49:45:4c:57:c0:47:63:49:5f:85:86:72:d7:06:
+ d1:e6:10:16:ab:60:a3:09:7d:9b:39:e4:13:4b:68:
+ 8e:c3:33:a0:50:ce:45:41:50:f6:38:d8:3e:89:e8:
+ cf:cd:15:24:3f:ea:37:a5:72:37:f8:7b:60:ce:d9:
+ 6b:e1:ef:bc:92:13:48:7a:97:c8:48:87:62:4b:7c:
+ 0e:6f:bf:a5:b7:47:78:2a:5d:74:92:5c:3a:40:8a:
+ f2:e2:d8:35:54:b2:13:1f:d7:c8:0b:c8:d9:89:56:
+ bd:72:d0:84:14:c8:b6:79:b8:22:b7:d0:20:9a:ef:
+ 59:0d:ca:0c:99:ad:27:da:3f:c8:f5:02:3b:e2:5f:
+ 98:6d
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints:
+ CA:FALSE
+ Netscape Comment:
+ OpenSSL Generated Certificate
+ X509v3 Subject Key Identifier:
+ F5:D3:EA:60:F9:5C:9E:DD:82:9D:DF:E4:71:43:A6:35:84:4D:07:46
+ X509v3 Authority Key Identifier:
+ 03:E4:E7:DA:0F:64:DB:13:1E:BD:85:AB:76:BC:29:CA:2F:A7:C7:4B
+ Signature Algorithm: sha256WithRSAEncryption
+ Signature Value:
+ 97:67:38:35:c2:da:ab:2b:22:5f:29:0a:cc:b3:a0:3c:a0:a5:
+ 5c:a3:75:ef:48:65:b5:45:3f:14:11:7b:95:09:78:e4:9a:b1:
+ db:10:23:33:7f:c8:37:89:1f:e4:be:51:48:8c:d4:1d:6b:25:
+ fd:ed:30:24:eb:20:f7:84:c4:49:d1:81:6d:f4:f5:54:71:ac:
+ a0:40:b1:c1:05:3a:fb:cb:79:5a:ee:ce:00:20:7c:31:f1:9a:
+ 16:1a:11:19:79:dd:49:8a:1b:91:e9:30:4f:33:72:2e:ee:71:
+ 5e:53:4a:59:9f:80:4b:cf:6a:da:c8:98:20:55:a1:45:c2:cc:
+ 86:05:45:49:df:72:48:54:88:02:91:aa:1b:e3:ed:b6:29:30:
+ a7:d3:46:d6:ab:58:c2:e5:1e:e6:8d:67:c0:2b:54:46:75:97:
+ f0:5a:f8:c2:04:8f:ce:31:50:28:de:37:dc:c6:8d:6b:24:f8:
+ fa:6c:ae:d9:bd:fc:87:22:dd:cc:c9:a0:c2:20:5f:13:ca:f8:
+ 32:96:66:14:1d:81:b7:36:4a:36:09:46:83:3d:80:07:9f:8b:
+ 64:e4:5c:42:93:55:c1:ea:f9:65:6d:10:b5:33:ee:90:27:11:
+ 3a:30:14:bf:a8:c8:ca:f0:fe:22:1b:b1:f0:76:b0:a4:32:3c:
+ 4a:52:af:1c
+-----BEGIN CERTIFICATE-----
+MIID7jCCAtagAwIBAgIBADANBgkqhkiG9w0BAQsFADB6MSMwIQYDVQQKDBpBcGFj
+aGUgU29mdHdhcmUgRm91bmRhdGlvbjEfMB0GA1UECwwWSHR0cENvbXBvbmVudHMg
+UHJvamVjdDEQMA4GA1UEAwwHVGVzdCBDQTEgMB4GCSqGSIb3DQEJARYRZGV2QGhj
+LmFwYWNoZS5vcmcwIBcNMjQxMDIwMTEzMTAwWhgPMjEyNDA5MjYxMTMxMDBaMHwx
+IzAhBgNVBAoMGkFwYWNoZSBTb2Z0d2FyZSBGb3VuZGF0aW9uMR8wHQYDVQQLDBZI
+dHRwQ29tcG9uZW50cyBQcm9qZWN0MRIwEAYDVQQDDAlsb2NhbGhvc3QxIDAeBgkq
+hkiG9w0BCQEWEWRldkBoYy5hcGFjaGUub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEAms//SYaeOgsML0+JEIYRMNqBjJ4m93Kfx9COFme+Ckbu0p9n
+iTe4OIQW2GbByJqfZMYGjFf+DYNYTT3z1TWnieNeG8hItWY0OOyfrBoFgWYP1J+v
+qQy/IFHlHCFjpZU5hrDW652aKb6D3+9rCOTjLqMeSUyxKveJSUVMV8BHY0lfhYZy
+1wbR5hAWq2CjCX2bOeQTS2iOwzOgUM5FQVD2ONg+iejPzRUkP+o3pXI3+Htgztlr
+4e+8khNIepfISIdiS3wOb7+lt0d4Kl10klw6QIry4tg1VLITH9fIC8jZiVa9ctCE
+FMi2ebgit9Agmu9ZDcoMma0n2j/I9QI74l+YbQIDAQABo3sweTAJBgNVHRMEAjAA
+MCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAd
+BgNVHQ4EFgQU9dPqYPlcnt2Cnd/kcUOmNYRNB0YwHwYDVR0jBBgwFoAUA+Tn2g9k
+2xMevYWrdrwpyi+nx0swDQYJKoZIhvcNAQELBQADggEBAJdnODXC2qsrIl8pCsyz
+oDygpVyjde9IZbVFPxQRe5UJeOSasdsQIzN/yDeJH+S+UUiM1B1rJf3tMCTrIPeE
+xEnRgW309VRxrKBAscEFOvvLeVruzgAgfDHxmhYaERl53UmKG5HpME8zci7ucV5T
+SlmfgEvPatrImCBVoUXCzIYFRUnfckhUiAKRqhvj7bYpMKfTRtarWMLlHuaNZ8Ar
+VEZ1l/Ba+MIEj84xUCjeN9zGjWsk+Ppsrtm9/Ici3czJoMIgXxPK+DKWZhQdgbc2
+SjYJRoM9gAefi2TkXEKTVcHq+WVtELUz7pAnETowFL+oyMrw/iIbsfB2sKQyPEpS
+rxw=
+-----END CERTIFICATE-----
diff --git a/httpcore5-testing/src/test/resources/docker/server-key.pem b/httpcore5-testing/src/test/resources/docker/server-key.pem
new file mode 100644
index 000000000..5871ecc91
--- /dev/null
+++ b/httpcore5-testing/src/test/resources/docker/server-key.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCaz/9Jhp46Cwwv
+T4kQhhEw2oGMnib3cp/H0I4WZ74KRu7Sn2eJN7g4hBbYZsHImp9kxgaMV/4Ng1hN
+PfPVNaeJ414byEi1ZjQ47J+sGgWBZg/Un6+pDL8gUeUcIWOllTmGsNbrnZopvoPf
+72sI5OMuox5JTLEq94lJRUxXwEdjSV+FhnLXBtHmEBarYKMJfZs55BNLaI7DM6BQ
+zkVBUPY42D6J6M/NFSQ/6jelcjf4e2DO2Wvh77ySE0h6l8hIh2JLfA5vv6W3R3gq
+XXSSXDpAivLi2DVUshMf18gLyNmJVr1y0IQUyLZ5uCK30CCa71kNygyZrSfaP8j1
+AjviX5htAgMBAAECggEABtpp+tduk141f2CoziZJMN2eD4YEGT8l60KvD4yEdqWr
+i9UKUHeQJvxTRegimvPxVhTdaa1kLd/1yDw+WjQNAxx2vYnGYjVbNCE8HkfBR6L8
+1L+Zl0UHrvFr0CzQNvPIqfmTwgwQ14PmCENBJzx5VsavdV+OQOXYBM+AW4AZCOrp
+yrRUVklecZwOF+lrkS+QgUuv5ZvufJq20PcuGhMGwFHaiOH+BHSfcPdqLKwxUjv0
+vpN36cXw4vELYUMpM7jd4B+0gsoJZXqFwTHBt/3wrqlOFWFqq+X+k9RcmWofP1kT
+yZGOKhexw6tuQB25ejnGJEIAcnCGT2fX7WMmPCoB0QKBgQDOv8OJwKiKLYNSv1Ln
+Ep6Q71xx2P7UcE6fF08mI+U8j1zAGnUVrVS2M9ysTyuZuiLtj6dBZ63ej4hdC+Q5
+elLo/r8KFR5k+i6KT6XfidpOcIxhIAIjHaXx/X/x1jOGl6kvr4CJqdWd9wrMMglx
+Wi3EmsVHmcjB14xtKX0WgXvJSQKBgQC/sPhWHOFAraM4Izemd+0GL4LkjpdtiWyQ
+TiFjvlSbYTgPyl3d8IQY5ubWpHfx7meZmWNj6lmiSBUIFV5/TNpuPbr5wD/KK/L6
+2cZevlPUYC4nSF+PTB9Hm5c6ocLbP6ddcD98cQz2efQZXixQhECoX8UDMxL3pIjb
+LdPrTalaBQKBgDiZ+1h9LCcYKrm+s12blVmsjiyE8c8LKBsZ8ItKjHm17fiRxbg3
+ideP/zwVOKSPdvx+tZWMYudpeDWxCbxKpuQuyfJisb2HWLJ497ppLSEIYwY8Exm2
+BjZn5l04/UY9ww3RCGmn21mxxnz8veUQgTMwBA6EJZgcAM/p6dr9e/wxAoGBAIQj
+AYyaq8th5jk0TZA66vBwn9HdWRTwvh1bPjj7YmcZRQPdg4cR3H0t7cHX7bafmFqR
+GaouSUtMVPMVh+ZIm+mSM+klVNOQKBYzOELm//JNuoLpqLWmy4kY/84y45cu8be/
+QIQPidf9iP5TpEh8YfWuzqe99T0v9gbgOEzjY/HhAoGBALr7Cwu3mvNLFug3n5UW
+1o+ImxlSI5LI1eqV9gG4pfKZbWzXuw8fXd8LLBxF3+WoE6eoSnnYVce8aUX3nDhd
+ZxUPattdKDOXmItHW+Oak2jZB6OSyTPM0uZWt3KfPDE+dPwnLmKuc7ZElo0rVwYW
+UiQnz6mwRNWK1Z/OGfkXqTxw
+-----END PRIVATE KEY-----
diff --git a/httpcore5-testing/src/test/resources/test-ca.jks b/httpcore5-testing/src/test/resources/test-ca.jks
new file mode 100644
index 000000000..fb70ffb15
Binary files /dev/null and b/httpcore5-testing/src/test/resources/test-ca.jks differ
diff --git a/test-CA/ca-cert.pem b/test-CA/ca-cert.pem
new file mode 100644
index 000000000..a40c7631b
--- /dev/null
+++ b/test-CA/ca-cert.pem
@@ -0,0 +1,23 @@
+-----BEGIN CERTIFICATE-----
+MIIDyTCCArGgAwIBAgIJAO3mCIu9mboMMA0GCSqGSIb3DQEBCwUAMHoxIzAhBgNV
+BAoMGkFwYWNoZSBTb2Z0d2FyZSBGb3VuZGF0aW9uMR8wHQYDVQQLDBZIdHRwQ29t
+cG9uZW50cyBQcm9qZWN0MRAwDgYDVQQDDAdUZXN0IENBMSAwHgYJKoZIhvcNAQkB
+FhFkZXZAaGMuYXBhY2hlLm9yZzAgFw0xNDEwMTMxNTAxMjBaGA8yMjg4MDcyODE1
+MDEyMFowejEjMCEGA1UECgwaQXBhY2hlIFNvZnR3YXJlIEZvdW5kYXRpb24xHzAd
+BgNVBAsMFkh0dHBDb21wb25lbnRzIFByb2plY3QxEDAOBgNVBAMMB1Rlc3QgQ0Ex
+IDAeBgkqhkiG9w0BCQEWEWRldkBoYy5hcGFjaGUub3JnMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEApXhHtKRvAxbLI+f21zNe68dkVXAhSMIfHQJGb2en
+S1H8yE4HPIb4vPQ0U7fQCb7RXplm6cHExpof4cO3DmyqD5KeQk0TdM8XrhviDgwj
+Y0KQ/lgwGHR5CpYoZ6LYWaLSE/wt9dVu80UcK8a3hW9G0X/4b79fMO6HYDix+CI4
+b17sqZ4K0tWKA10Xe+2RJU8Y01pPBaPR/UsAn+a1pZ6f8BhL879oWHfLWKcgZOYP
+U4sYED0S8gs4/ED1zRj2/uHb313sHTl+OU4X5v+OvwBvbNBrl5qfMTZnRNxlOfRq
+UTJdcopsp2aNeqHiorSDOrHwMIJpxQ2XqHT2l9s8msXf4wIDAQABo1AwTjAdBgNV
+HQ4EFgQUA+Tn2g9k2xMevYWrdrwpyi+nx0swHwYDVR0jBBgwFoAUA+Tn2g9k2xMe
+vYWrdrwpyi+nx0swDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAFVEp
+8Nv6JoFY7oGgu6068fH/kq7A3SllqMpbv7dddI9fgwy352cBtg6PkYkGtEE037xs
+FQSYV1NiAkNWTJER+Q+kVbQrhuPNKZqh1g0sUKwv3X20BmgJ9hbU9klWZjdjujyd
+h9Ybjuntkn5XPp1zN6zHD0sQReEJnRlD6FT1axrQWpICzE4qoo8k64G+6/rqFywc
+oMc/Of3KCAHjtbWklEu97hjBvGC/nEP4/VhRrjWWSeGHv88LCyO/Yg6v3zrZHFLW
++KhsDCPyLxSSISFskLQfukiqf2lr87kQq/oF27sAr3sR3Jqh4qzflM2XLgjmZuRE
+OrHT6lvUemRyksA5qg==
+-----END CERTIFICATE-----
diff --git a/test-CA/ca-key.pem b/test-CA/ca-key.pem
new file mode 100644
index 000000000..a8a304241
--- /dev/null
+++ b/test-CA/ca-key.pem
@@ -0,0 +1,30 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIq0bLh96mWv4CAggA
+MBQGCCqGSIb3DQMHBAimZqUiELx13QSCBMgaLWrGFqveIzwQUsebS6FBdVq0lodz
+Vlekje8ycFDYSd21V9jPMwrSupZceeBQjCrpyLZ3oPkR+MvObmznev8XYcJzVCkF
+E9ApAaHZe248wWcu1/D7auHNG3GyZfvYS0c//Rs2OzMZfsUvX93RVullCRREvCYS
+qXhaO3ywFocndKRpSnkOBs2SRa0yc9POl4n4dwyKhsJUaMSmhPbJr9UBvCbXHZIA
+gLcSWzVon3EtZCSubMp9eo90G5MzIXEyPBTcIHwpyqRWTkaTUTq4R0c4/RTX+l7K
+OZuRIEeBEW6z009fSagymN/KEH3gUkg5pG6i1YWF63OVKTMGn+yQGWwYXwTyEGi5
+HZpD98wh3ycucmL93XLk+yYXQcTp1i+u4GaXNWGREQvNW6onCGeg6WWj1PrIsqoi
+TZ2pgQUJWPR1K3037hY0o9sakAkyYSyTPVvHOUcbf3+GhqGS1FsSNOxKRNpYm/3v
+Gf0SUN8BavPliK9NSU5JAbprr/hoL5o72dCX9DiOgwfW3HyD/gLh7sVyVBdAzTnE
+XFaYFnrb5QnqHbgWvaLbJUT5K7MW3OFLVConydYtYdaUl5z49OflhgnvYOPgTSUr
+k9c7exQjedAduPd8dXODh9l2g+QEXJoT+YYFEYHkQlsZgH1hCLXD1TmAeI4LMklb
+vPaGE8Ouj1pfbejdTNsqLfW0IiR/jZzEjRgqrueMf2VUjtqTZyPayc2rU4kOoKhv
+JzQ0wOFhgRztWJy2voRe+iYss3ToqZ7qLpjBfCTsxCJqbuaGeJWWSnOlDpSysgr+
+q4BvCzDcvf/0mKD2cQuJx/kynQMCcWB/VegRsQ24Y+3T7IU1w8ccmRfSZ93AwkAh
+MKJzKaVhD/gn9vUG/we18p7RMIc9pk1o2Z2Ru3mKjkO3QYRP6Y7yk0ah2JKrHIPf
+LWfPuHmtzHQXkY3RbVvxvwD/+qHm8ogXq52w8cpGhY5UwAEHrLLwypdBHccrAJjo
+bE13M/MrtTry/k8OMRqhhRzHUXBq6mLaWffCaP2SAVfJEez2iASvGJFvgy3bSkWY
+rwWMSfZKDkauwDMW5gpFrpeuqgD64LO72sN01riVDpaEyNODRCEEBGce+O+91R9K
+TLVgRYFsxClyZy1nynD66gkTepEm1yOgcdqV3651Os+TGm39jGYHy1k9mPz8ypqf
+8n8uw4nV3SbIwfpy4Z8onHixfc/Fugm7yQHW4dSuCpahyIJHom6Cq7SZfPuo9e3t
+8tqaxvK4U/dAXoimvN1eakH2FoVFIj3mk7OAKBgmDINH9GlzXPwRsTfiJSP4Xaod
+ouWIQLLeXQuuOc5VJd1Xex75o8ciSOomAS0uR4Fvk/2NkAm0EMddjZnuWLQaXPry
+JiUIgSx3w3yRq9RSQOxDRQpp2nP2roX7cyeGPzTmeujikExGTa3YBxuAShDLx5pt
+fpi0ol8H8ohDU4eV9pv96KRBG9e8sQf1zpGjeYLTFiN35IQxYJx3HTXp9/oFWkmA
+OdCEwggIKJ/RtgkWOWogTilQVA41p4XZr661fxoSE86sHXkZKn8IGnAKLFT46nWM
+IYVDalYUiSNZr+KbzmLIV3LmYE3mlqGI4vDvQtd9zQk/uatYBc2DetuTWPZHCEKS
+3Nk=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/test-CA/openssl.cnf b/test-CA/openssl.cnf
new file mode 100644
index 000000000..ab73071ba
--- /dev/null
+++ b/test-CA/openssl.cnf
@@ -0,0 +1,357 @@
+# 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 definition stops the following lines choking if HOME isn't
+# defined.
+HOME = .
+RANDFILE = $ENV::HOME/.rnd
+
+# Extra OBJECT IDENTIFIER info:
+#oid_file = $ENV::HOME/.oid
+oid_section = new_oids
+
+# To use this configuration file with the "-extfile" option of the
+# "openssl x509" utility, name here the section containing the
+# X.509v3 extensions to use:
+# extensions =
+# (Alternatively, use a configuration file that has only
+# X.509v3 extensions in its main [= default] section.)
+
+[ new_oids ]
+
+# We can add new OIDs in here for use by 'ca', 'req' and 'ts'.
+# Add a simple OID like this:
+# testoid1=1.2.3.4
+# Or use config file substitution like this:
+# testoid2=${testoid1}.5.6
+
+# Policies used by the TSA examples.
+tsa_policy1 = 1.2.3.4.1
+tsa_policy2 = 1.2.3.4.5.6
+tsa_policy3 = 1.2.3.4.5.7
+
+####################################################################
+[ ca ]
+default_ca = CA_default # The default ca section
+
+####################################################################
+[ CA_default ]
+
+dir = ./test-CA # Where everything is kept
+certs = $dir/certs # Where the issued certs are kept
+crl_dir = $dir/crl # Where the issued crl are kept
+database = $dir/index.txt # database index file.
+#unique_subject = no # Set to 'no' to allow creation of
+ # several ctificates with same subject.
+new_certs_dir = $dir/newcerts # default place for new certs.
+
+certificate = $dir/ca-cert.pem # The CA certificate
+serial = $dir/serial.txt # The current serial number
+crlnumber = $dir/crlnumber # the current crl number
+ # must be commented out to leave a V1 CRL
+crl = $dir/crl.pem # The current CRL
+private_key = $dir/ca-key.pem# The private key
+RANDFILE = $dir/.rand # private random number file
+
+x509_extensions = usr_cert # The extentions to add to the cert
+
+# Comment out the following two lines for the "traditional"
+# (and highly broken) format.
+name_opt = ca_default # Subject Name options
+cert_opt = ca_default # Certificate field options
+
+# Extension copying option: use with caution.
+# copy_extensions = copy
+
+# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs
+# so this is commented out by default to leave a V1 CRL.
+# crlnumber must also be commented out to leave a V1 CRL.
+# crl_extensions = crl_ext
+
+default_days = 365 # how long to certify for
+default_crl_days= 30 # how long before next CRL
+default_md = default # use public key default MD
+preserve = no # keep passed DN ordering
+
+# A few difference way of specifying how similar the request should look
+# For type CA, the listed attributes must be the same, and the optional
+# and supplied fields are just that :-)
+policy = policy_match
+
+# For the CA policy
+[ policy_match ]
+countryName = optional
+stateOrProvinceName = optional
+organizationName = match
+organizationalUnitName = optional
+commonName = supplied
+emailAddress = optional
+
+# For the 'anything' policy
+# At this point in time, you must list all acceptable 'object'
+# types.
+[ policy_anything ]
+countryName = optional
+stateOrProvinceName = optional
+localityName = optional
+organizationName = optional
+organizationalUnitName = optional
+commonName = supplied
+emailAddress = optional
+
+####################################################################
+[ req ]
+default_bits = 2048
+default_keyfile = privkey.pem
+distinguished_name = req_distinguished_name
+attributes = req_attributes
+x509_extensions = v3_ca # The extentions to add to the self signed cert
+
+# Passwords for private keys if not present they will be prompted for
+# input_password = secret
+# output_password = secret
+
+# This sets a mask for permitted string types. There are several options.
+# default: PrintableString, T61String, BMPString.
+# pkix : PrintableString, BMPString (PKIX recommendation before 2004)
+# utf8only: only UTF8Strings (PKIX recommendation after 2004).
+# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings).
+# MASK:XXXX a literal mask value.
+# WARNING: ancient versions of Netscape crash on BMPStrings or UTF8Strings.
+string_mask = utf8only
+
+# req_extensions = v3_req # The extensions to add to a certificate request
+
+[ req_distinguished_name ]
+countryName = Country Name (2 letter code)
+countryName_default =
+
+stateOrProvinceName = State or Province Name (full name)
+stateOrProvinceName_default = Some-State
+
+localityName = Locality Name (eg, city)
+
+0.organizationName = Organization Name (eg, company)
+0.organizationName_default = Apache Software Foundation
+
+organizationalUnitName = Organizational Unit Name (eg, section)
+organizationalUnitName_default = HttpComponents Project
+
+commonName = Common Name (e.g. server FQDN or YOUR name)
+commonName_max = 64
+
+emailAddress = Email Address
+emailAddress_max = 64
+
+# SET-ex3 = SET extension number 3
+
+[ req_attributes ]
+challengePassword = A challenge password
+challengePassword_min = 4
+challengePassword_max = 20
+
+unstructuredName = An optional company name
+
+[ usr_cert ]
+
+# These extensions are added when 'ca' signs a request.
+
+# This goes against PKIX guidelines but some CAs do it and some software
+# requires this to avoid interpreting an end user certificate as a CA.
+
+basicConstraints=CA:FALSE
+
+# Here are some examples of the usage of nsCertType. If it is omitted
+# the certificate can be used for anything *except* object signing.
+
+# This is OK for an SSL server.
+# nsCertType = server
+
+# For an object signing certificate this would be used.
+# nsCertType = objsign
+
+# For normal client use this is typical
+# nsCertType = client, email
+
+# and for everything including object signing:
+# nsCertType = client, email, objsign
+
+# This is typical in keyUsage for a client certificate.
+# keyUsage = nonRepudiation, digitalSignature, keyEncipherment
+
+# This will be displayed in Netscape's comment listbox.
+nsComment = "OpenSSL Generated Certificate"
+
+# PKIX recommendations harmless if included in all certificates.
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid,issuer
+
+# This stuff is for subjectAltName and issuerAltname.
+# Import the email address.
+# subjectAltName=email:copy
+# An alternative to produce certificates that aren't
+# deprecated according to PKIX.
+# subjectAltName=email:move
+
+# Copy subject details
+# issuerAltName=issuer:copy
+
+#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem
+#nsBaseUrl
+#nsRevocationUrl
+#nsRenewalUrl
+#nsCaPolicyUrl
+#nsSslServerName
+
+# This is required for TSA certificates.
+# extendedKeyUsage = critical,timeStamping
+
+[ v3_req ]
+
+# Extensions to add to a certificate request
+
+basicConstraints = CA:FALSE
+keyUsage = nonRepudiation, digitalSignature, keyEncipherment
+
+[ v3_ca ]
+
+
+# Extensions for a typical CA
+
+
+# PKIX recommendation.
+
+subjectKeyIdentifier=hash
+
+authorityKeyIdentifier=keyid:always,issuer
+
+# This is what PKIX recommends but some broken software chokes on critical
+# extensions.
+#basicConstraints = critical,CA:true
+# So we do this instead.
+basicConstraints = CA:true
+
+# Key usage: this is typical for a CA certificate. However since it will
+# prevent it being used as an test self-signed certificate it is best
+# left out by default.
+# keyUsage = cRLSign, keyCertSign
+
+# Some might want this also
+# nsCertType = sslCA, emailCA
+
+# Include email address in subject alt name: another PKIX recommendation
+# subjectAltName=email:copy
+# Copy issuer details
+# issuerAltName=issuer:copy
+
+# DER hex encoding of an extension: beware experts only!
+# obj=DER:02:03
+# Where 'obj' is a standard or added object
+# You can even override a supported extension:
+# basicConstraints= critical, DER:30:03:01:01:FF
+
+[ crl_ext ]
+
+# CRL extensions.
+# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL.
+
+# issuerAltName=issuer:copy
+authorityKeyIdentifier=keyid:always
+
+[ proxy_cert_ext ]
+# These extensions should be added when creating a proxy certificate
+
+# This goes against PKIX guidelines but some CAs do it and some software
+# requires this to avoid interpreting an end user certificate as a CA.
+
+basicConstraints=CA:FALSE
+
+# Here are some examples of the usage of nsCertType. If it is omitted
+# the certificate can be used for anything *except* object signing.
+
+# This is OK for an SSL server.
+# nsCertType = server
+
+# For an object signing certificate this would be used.
+# nsCertType = objsign
+
+# For normal client use this is typical
+# nsCertType = client, email
+
+# and for everything including object signing:
+# nsCertType = client, email, objsign
+
+# This is typical in keyUsage for a client certificate.
+# keyUsage = nonRepudiation, digitalSignature, keyEncipherment
+
+# This will be displayed in Netscape's comment listbox.
+nsComment = "OpenSSL Generated Certificate"
+
+# PKIX recommendations harmless if included in all certificates.
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid,issuer
+
+# This stuff is for subjectAltName and issuerAltname.
+# Import the email address.
+# subjectAltName=email:copy
+# An alternative to produce certificates that aren't
+# deprecated according to PKIX.
+# subjectAltName=email:move
+
+# Copy subject details
+# issuerAltName=issuer:copy
+
+#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem
+#nsBaseUrl
+#nsRevocationUrl
+#nsRenewalUrl
+#nsCaPolicyUrl
+#nsSslServerName
+
+# This really needs to be in place for it to be a proxy certificate.
+proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo
+
+####################################################################
+[ tsa ]
+
+default_tsa = tsa_config1 # the default TSA section
+
+[ tsa_config1 ]
+
+# These are used by the TSA reply generation only.
+dir = ./demoCA # TSA root directory
+serial = $dir/tsaserial # The current serial number (mandatory)
+crypto_device = builtin # OpenSSL engine to use for signing
+signer_cert = $dir/tsacert.pem # The TSA signing certificate
+ # (optional)
+certs = $dir/cacert.pem # Certificate chain to include in reply
+ # (optional)
+signer_key = $dir/private/tsakey.pem # The TSA private key (optional)
+
+default_policy = tsa_policy1 # Policy if request did not specify it
+ # (optional)
+other_policies = tsa_policy2, tsa_policy3 # acceptable policies (optional)
+digests = md5, sha1 # Acceptable message digests (mandatory)
+accuracy = secs:1, millisecs:500, microsecs:100 # (optional)
+clock_precision_digits = 0 # number of digits after dot. (optional)
+ordering = yes # Is ordering defined for timestamps?
+ # (optional, default: no)
+tsa_name = yes # Must the TSA name be included in the reply?
+ # (optional, default: no)
+ess_cert_id_chain = no # Must the ESS cert id chain be included?
+ # (optional, default: no)