Clean up http-client changes (#295)

* pkl-excutor tests: symlink 0.25.0 distribution into pkl-executable/build
* Use `IoUtils.getPklHomeDir` in HttpClientBuilder
* Simplify Exceptions.java
* Enable testing for older pkl-executor distribution
This commit is contained in:
Daniel Chao
2024-03-07 10:43:04 -08:00
committed by GitHub
parent 3fb1f03780
commit 9defe868c0
7 changed files with 84 additions and 66 deletions

View File

@@ -26,24 +26,26 @@ import java.util.List;
import java.util.function.Supplier;
import org.pkl.core.Release;
import org.pkl.core.util.ErrorMessages;
import org.pkl.core.util.IoUtils;
final class HttpClientBuilder implements HttpClient.Builder {
private final Path userHome;
private String userAgent;
private Duration connectTimeout = Duration.ofSeconds(60);
private Duration requestTimeout = Duration.ofSeconds(60);
private final Path caCertsDir;
private final List<Path> certificateFiles = new ArrayList<>();
private final List<URI> certificateUris = new ArrayList<>();
HttpClientBuilder() {
this(Path.of(System.getProperty("user.home")));
this(IoUtils.getPklHomeDir().resolve("cacerts"));
}
// only exists for testing
HttpClientBuilder(Path userHome) {
this.userHome = userHome;
HttpClientBuilder(Path caCertsDir) {
var release = Release.current();
userAgent = "Pkl/" + release.version() + " (" + release.os() + "; " + release.flavor() + ")";
this.caCertsDir = caCertsDir;
this.userAgent =
"Pkl/" + release.version() + " (" + release.os() + "; " + release.flavor() + ")";
}
public HttpClient.Builder setUserAgent(String userAgent) {
@@ -80,10 +82,9 @@ final class HttpClientBuilder implements HttpClient.Builder {
}
public HttpClient.Builder addDefaultCliCertificates() {
var directory = userHome.resolve(".pkl").resolve("cacerts");
var fileCount = certificateFiles.size();
if (Files.isDirectory(directory)) {
try (var files = Files.list(directory)) {
if (Files.isDirectory(caCertsDir)) {
try (var files = Files.list(caCertsDir)) {
files.filter(Files::isRegularFile).forEach(certificateFiles::add);
} catch (IOException e) {
throw new HttpClientInitException(e);

View File

@@ -132,11 +132,18 @@ public class ExecutorSpiImpl implements ExecutorSpi {
private HttpClient getOrCreateHttpClient(ExecutorSpiOptions options) {
List<Path> certificateFiles;
List<URI> certificateUris;
if (options instanceof ExecutorSpiOptions2) {
var options2 = (ExecutorSpiOptions2) options;
certificateFiles = options2.getCertificateFiles();
certificateUris = options2.getCertificateUris();
} else {
try {
if (options instanceof ExecutorSpiOptions2) {
var options2 = (ExecutorSpiOptions2) options;
certificateFiles = options2.getCertificateFiles();
certificateUris = options2.getCertificateUris();
} else {
certificateFiles = List.of();
certificateUris = List.of();
}
// host pkl-executor does not have class ExecutorOptions2 defined.
// this will happen if the pkl-executor distribution is too old.
} catch (NoClassDefFoundError e) {
certificateFiles = List.of();
certificateUris = List.of();
}

View File

@@ -20,10 +20,8 @@ public final class Exceptions {
public static Throwable getRootCause(Throwable t) {
var result = t;
var cause = result.getCause();
while (cause != null) {
result = cause;
cause = cause.getCause();
while (result.getCause() != null) {
result = result.getCause();
}
return result;
}

View File

@@ -22,42 +22,42 @@ class HttpClientTest {
val client = assertDoesNotThrow {
HttpClient.builder().build()
}
assertThat(client).isInstanceOf(RequestRewritingClient::class.java)
client as RequestRewritingClient
val release = Release.current()
assertThat(client.userAgent).isEqualTo("Pkl/${release.version()} (${release.os()}; ${release.flavor()})")
assertThat(client.requestTimeout).isEqualTo(Duration.ofSeconds(60))
assertThat(client.delegate).isInstanceOf(JdkHttpClient::class.java)
val delegate = client.delegate as JdkHttpClient
assertThat(delegate.underlying.connectTimeout()).hasValue(Duration.ofSeconds(60))
}
@Test
fun `can build custom client`() {
val client = HttpClient.builder()
.setUserAgent("Agent 1")
.setRequestTimeout(Duration.ofHours(86))
.setConnectTimeout(Duration.ofMinutes(42))
.setConnectTimeout(Duration.ofMinutes(42))
.build() as RequestRewritingClient
assertThat(client.userAgent).isEqualTo("Agent 1")
assertThat(client.requestTimeout).isEqualTo(Duration.ofHours(86))
val delegate = client.delegate as JdkHttpClient
assertThat(delegate.underlying.connectTimeout()).hasValue(Duration.ofMinutes(42))
}
@Test
fun `can load certificates from file system`() {
assertDoesNotThrow {
HttpClient.builder().addCertificates(FileTestUtils.selfSignedCertificate).build()
}
}
@Test
fun `certificate file located on file system cannot be empty`(@TempDir tempDir: Path) {
val file = tempDir.resolve("certs.pem").createFile()
@@ -75,7 +75,7 @@ class HttpClientTest {
HttpClient.builder().addCertificates(javaClass.getResource("/org/pkl/certs/PklCARoots.pem")!!.toURI()).build()
}
}
@Test
fun `only allows loading jar and file certificate URIs`() {
assertThrows<HttpClientInitException> {
@@ -96,46 +96,47 @@ class HttpClientTest {
@Test
fun `can load built-in certificates`() {
assertDoesNotThrow {
assertDoesNotThrow {
HttpClient.builder().addBuiltInCertificates().build()
}
}
@Test
fun `can load certificates from Pkl user home cacerts directory`(@TempDir tempDir: Path) {
val certFile = tempDir.resolve(".pkl")
val certsDir = tempDir.resolve(".pkl")
.resolve("cacerts")
.createDirectories()
.resolve("certs.pem")
FileTestUtils.selfSignedCertificate.copyTo(certFile)
.also { dir ->
FileTestUtils.selfSignedCertificate.copyTo(dir.resolve("certs.pem"))
}
assertDoesNotThrow {
HttpClientBuilder(tempDir).addDefaultCliCertificates().build()
HttpClientBuilder(certsDir).addDefaultCliCertificates().build()
}
}
@Test
fun `loading certificates from cacerts directory falls back to built-in certificates`(@TempDir userHome: Path) {
fun `loading certificates from cacerts directory falls back to built-in certificates`(@TempDir certsDir: Path) {
assertDoesNotThrow {
HttpClientBuilder(userHome).addDefaultCliCertificates().build()
HttpClientBuilder(certsDir).addDefaultCliCertificates().build()
}
}
@Test
fun `can be closed multiple times`() {
val client = HttpClient.builder().build()
assertDoesNotThrow {
client.close()
client.close()
}
}
@Test
fun `refuses to send messages once closed`() {
val client = HttpClient.builder().build()
val request = HttpRequest.newBuilder(URI("https://example.com")).build()
client.close()
assertThrows<IllegalStateException> {

View File

@@ -11,7 +11,7 @@ class ExceptionsTest {
val e = IOException("io")
assertThat(Exceptions.getRootCause(e)).isSameAs(e)
}
@Test
fun `get root cause of nested exception`() {
val e = IOException("io")
@@ -29,7 +29,7 @@ class ExceptionsTest {
e.initCause(e2)
assertThat(Exceptions.getRootReason(e)).isEqualTo("the root reason")
}
@Test
fun `get root reason if null`() {
val e = IOException("io")