diff --git a/maven-resolver-transport-jdk-parent/maven-resolver-transport-jdk-11/src/main/java/org/eclipse/aether/transport/jdk/JdkTransporter.java b/maven-resolver-transport-jdk-parent/maven-resolver-transport-jdk-11/src/main/java/org/eclipse/aether/transport/jdk/JdkTransporter.java index 32da764ea..15a37326f 100644 --- a/maven-resolver-transport-jdk-parent/maven-resolver-transport-jdk-11/src/main/java/org/eclipse/aether/transport/jdk/JdkTransporter.java +++ b/maven-resolver-transport-jdk-parent/maven-resolver-transport-jdk-11/src/main/java/org/eclipse/aether/transport/jdk/JdkTransporter.java @@ -197,6 +197,17 @@ final class JdkTransporter extends AbstractTransporter implements HttpTransporte javaVersion); } } + final String httpsSecurityMode = ConfigUtils.getString( + session, + ConfigurationProperties.HTTPS_SECURITY_MODE_DEFAULT, + ConfigurationProperties.HTTPS_SECURITY_MODE + "." + repository.getId(), + ConfigurationProperties.HTTPS_SECURITY_MODE); + + if (!ConfigurationProperties.HTTPS_SECURITY_MODE_DEFAULT.equals(httpsSecurityMode) + && !ConfigurationProperties.HTTPS_SECURITY_MODE_INSECURE.equals(httpsSecurityMode)) { + throw new IllegalArgumentException("Unsupported '" + httpsSecurityMode + "' HTTPS security mode."); + } + final boolean insecure = ConfigurationProperties.HTTPS_SECURITY_MODE_INSECURE.equals(httpsSecurityMode); this.maxConcurrentRequests = new Semaphore(ConfigUtils.getInteger( session, @@ -205,7 +216,11 @@ final class JdkTransporter extends AbstractTransporter implements HttpTransporte CONFIG_PROP_MAX_CONCURRENT_REQUESTS)); this.headers = headers; - this.client = getOrCreateClient(session, repository, javaVersion); + try { + this.client = createClient(session, repository, insecure); + } catch (Exception e) { + throw new NoTransporterException(repository, e); + } } private URI resolve(TransportTask task) { @@ -386,7 +401,7 @@ protected void implPut(PutTask task) throws Exception { } private HttpResponse send(HttpRequest request, HttpResponse.BodyHandler responseBodyHandler) - throws IOException, InterruptedException { + throws Exception { maxConcurrentRequests.acquire(); try { return client.send(request, responseBodyHandler); @@ -397,176 +412,134 @@ private HttpResponse send(HttpRequest request, HttpResponse.BodyHandler authentications = new HashMap<>(); + SSLContext sslContext = null; + try (AuthenticationContext repoAuthContext = AuthenticationContext.forRepository(session, repository)) { + if (repoAuthContext != null) { + sslContext = repoAuthContext.get(AuthenticationContext.SSL_CONTEXT, SSLContext.class); - final String httpsSecurityMode = ConfigUtils.getString( - session, - ConfigurationProperties.HTTPS_SECURITY_MODE_DEFAULT, - ConfigurationProperties.HTTPS_SECURITY_MODE + "." + repository.getId(), - ConfigurationProperties.HTTPS_SECURITY_MODE); + String username = repoAuthContext.get(AuthenticationContext.USERNAME); + String password = repoAuthContext.get(AuthenticationContext.PASSWORD); - if (!ConfigurationProperties.HTTPS_SECURITY_MODE_DEFAULT.equals(httpsSecurityMode) - && !ConfigurationProperties.HTTPS_SECURITY_MODE_INSECURE.equals(httpsSecurityMode)) { - throw new IllegalArgumentException("Unsupported '" + httpsSecurityMode + "' HTTPS security mode."); + authentications.put( + Authenticator.RequestorType.SERVER, + new PasswordAuthentication(username, password.toCharArray())); + } } - final boolean insecure = ConfigurationProperties.HTTPS_SECURITY_MODE_INSECURE.equals(httpsSecurityMode); - // todo: normally a single client per JVM is sufficient - in particular cause part of the config - // is global and not per instance so we should create a client only when conf changes for a repo - // else fallback on a global client - try { - return (HttpClient) session.getData().computeIfAbsent(instanceKey, () -> { - HashMap authentications = new HashMap<>(); - SSLContext sslContext = null; - try { - try (AuthenticationContext repoAuthContext = - AuthenticationContext.forRepository(session, repository)) { - if (repoAuthContext != null) { - sslContext = repoAuthContext.get(AuthenticationContext.SSL_CONTEXT, SSLContext.class); + if (sslContext == null) { + if (insecure) { + sslContext = SSLContext.getInstance("TLS"); + X509ExtendedTrustManager tm = new X509ExtendedTrustManager() { + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType) {} - String username = repoAuthContext.get(AuthenticationContext.USERNAME); - String password = repoAuthContext.get(AuthenticationContext.PASSWORD); + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType) {} - authentications.put( - Authenticator.RequestorType.SERVER, - new PasswordAuthentication(username, password.toCharArray())); - } - } + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType, Socket socket) {} - if (sslContext == null) { - if (insecure) { - sslContext = SSLContext.getInstance("TLS"); - X509ExtendedTrustManager tm = new X509ExtendedTrustManager() { - @Override - public void checkClientTrusted(X509Certificate[] chain, String authType) {} - - @Override - public void checkServerTrusted(X509Certificate[] chain, String authType) {} - - @Override - public void checkClientTrusted( - X509Certificate[] chain, String authType, Socket socket) {} - - @Override - public void checkServerTrusted( - X509Certificate[] chain, String authType, Socket socket) {} - - @Override - public void checkClientTrusted( - X509Certificate[] chain, String authType, SSLEngine engine) {} - - @Override - public void checkServerTrusted( - X509Certificate[] chain, String authType, SSLEngine engine) {} - - @Override - public X509Certificate[] getAcceptedIssuers() { - return null; - } - }; - sslContext.init(null, new X509TrustManager[] {tm}, null); - } else { - sslContext = SSLContext.getDefault(); - } - } + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType, Socket socket) {} - int connectTimeout = ConfigUtils.getInteger( - session, - ConfigurationProperties.DEFAULT_CONNECT_TIMEOUT, - ConfigurationProperties.CONNECT_TIMEOUT + "." + repository.getId(), - ConfigurationProperties.CONNECT_TIMEOUT); - - HttpClient.Builder builder = HttpClient.newBuilder() - .version(HttpClient.Version.valueOf(ConfigUtils.getString( - session, - DEFAULT_HTTP_VERSION, - CONFIG_PROP_HTTP_VERSION + "." + repository.getId(), - CONFIG_PROP_HTTP_VERSION))) - .followRedirects(HttpClient.Redirect.NORMAL) - .connectTimeout(Duration.ofMillis(connectTimeout)) - .sslContext(sslContext); - - if (insecure) { - SSLParameters sslParameters = sslContext.getDefaultSSLParameters(); - sslParameters.setEndpointIdentificationAlgorithm(null); - builder.sslParameters(sslParameters); - } + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType, SSLEngine engine) {} - setLocalAddress(builder, () -> getHttpLocalAddress(session, repository)); + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType, SSLEngine engine) {} - if (repository.getProxy() != null) { - ProxySelector proxy = ProxySelector.of(new InetSocketAddress( - repository.getProxy().getHost(), - repository.getProxy().getPort())); + @Override + public X509Certificate[] getAcceptedIssuers() { + return null; + } + }; + sslContext.init(null, new X509TrustManager[] {tm}, null); + } else { + sslContext = SSLContext.getDefault(); + } + } - builder.proxy(proxy); - try (AuthenticationContext proxyAuthContext = - AuthenticationContext.forProxy(session, repository)) { - if (proxyAuthContext != null) { - String username = proxyAuthContext.get(AuthenticationContext.USERNAME); - String password = proxyAuthContext.get(AuthenticationContext.PASSWORD); + int connectTimeout = ConfigUtils.getInteger( + session, + ConfigurationProperties.DEFAULT_CONNECT_TIMEOUT, + ConfigurationProperties.CONNECT_TIMEOUT + "." + repository.getId(), + ConfigurationProperties.CONNECT_TIMEOUT); + + HttpClient.Builder builder = HttpClient.newBuilder() + .version(HttpClient.Version.valueOf(ConfigUtils.getString( + session, + DEFAULT_HTTP_VERSION, + CONFIG_PROP_HTTP_VERSION + "." + repository.getId(), + CONFIG_PROP_HTTP_VERSION))) + .followRedirects(HttpClient.Redirect.NORMAL) + .connectTimeout(Duration.ofMillis(connectTimeout)) + .sslContext(sslContext); + + if (insecure) { + SSLParameters sslParameters = sslContext.getDefaultSSLParameters(); + sslParameters.setEndpointIdentificationAlgorithm(null); + builder.sslParameters(sslParameters); + } - authentications.put( - Authenticator.RequestorType.PROXY, - new PasswordAuthentication(username, password.toCharArray())); - } - } - } + setLocalAddress(builder, () -> getHttpLocalAddress(session, repository)); - if (!authentications.isEmpty()) { - builder.authenticator(new Authenticator() { - @Override - protected PasswordAuthentication getPasswordAuthentication() { - return authentications.get(getRequestorType()); - } - }); - } + if (repository.getProxy() != null) { + ProxySelector proxy = ProxySelector.of(new InetSocketAddress( + repository.getProxy().getHost(), repository.getProxy().getPort())); - HttpClient result = builder.build(); - if (!session.addOnSessionEndedHandler(JdkTransporterCloser.closer(javaVersion, result))) { - LOGGER.warn( - "Using Resolver 2 feature without Resolver 2 session handling, you may leak resources."); - } + builder.proxy(proxy); + try (AuthenticationContext proxyAuthContext = AuthenticationContext.forProxy(session, repository)) { + if (proxyAuthContext != null) { + String username = proxyAuthContext.get(AuthenticationContext.USERNAME); + String password = proxyAuthContext.get(AuthenticationContext.PASSWORD); - return result; - } catch (Exception e) { - throw new WrapperEx(e); + authentications.put( + Authenticator.RequestorType.PROXY, + new PasswordAuthentication(username, password.toCharArray())); + } + } + } + + if (!authentications.isEmpty()) { + builder.authenticator(new Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return authentications.get(getRequestorType()); } }); - } catch (WrapperEx e) { - throw new NoTransporterException(repository, e.getCause()); } + + return builder.build(); } - private void setLocalAddress(HttpClient.Builder builder, Supplier addressSupplier) { + private static InetAddress getHttpLocalAddress(RepositorySystemSession session, RemoteRepository repository) { + String bindAddress = ConfigUtils.getString( + session, + null, + ConfigurationProperties.HTTP_LOCAL_ADDRESS + "." + repository.getId(), + ConfigurationProperties.HTTP_LOCAL_ADDRESS); + if (bindAddress == null) { + return null; + } + try { + return InetAddress.getByName(bindAddress); + } catch (UnknownHostException uhe) { + throw new IllegalArgumentException( + "Given bind address (" + bindAddress + ") cannot be resolved for remote repository " + repository, + uhe); + } + } + + private static void setLocalAddress(HttpClient.Builder builder, Supplier addressSupplier) { try { final InetAddress address = addressSupplier.get(); if (address == null) { @@ -586,10 +559,4 @@ private void setLocalAddress(HttpClient.Builder builder, Supplier a throw new IllegalStateException(e); } } - - private static final class WrapperEx extends RuntimeException { - private WrapperEx(Throwable cause) { - super(cause); - } - } } diff --git a/maven-resolver-transport-jdk-parent/maven-resolver-transport-jdk-11/src/main/java/org/eclipse/aether/transport/jdk/JdkTransporterCloser.java b/maven-resolver-transport-jdk-parent/maven-resolver-transport-jdk-11/src/main/java/org/eclipse/aether/transport/jdk/JdkTransporterCloser.java index a273c014c..69f839a72 100644 --- a/maven-resolver-transport-jdk-parent/maven-resolver-transport-jdk-11/src/main/java/org/eclipse/aether/transport/jdk/JdkTransporterCloser.java +++ b/maven-resolver-transport-jdk-parent/maven-resolver-transport-jdk-11/src/main/java/org/eclipse/aether/transport/jdk/JdkTransporterCloser.java @@ -27,7 +27,7 @@ */ public final class JdkTransporterCloser { @SuppressWarnings("checkstyle:MagicNumber") - static Runnable closer(int javaVersion, HttpClient httpClient) { + static Runnable closer(HttpClient httpClient) { return () -> { if (httpClient instanceof AutoCloseable) { try { diff --git a/maven-resolver-transport-jdk-parent/maven-resolver-transport-jdk-21/pom.xml b/maven-resolver-transport-jdk-parent/maven-resolver-transport-jdk-21/pom.xml deleted file mode 100644 index cdf0e3051..000000000 --- a/maven-resolver-transport-jdk-parent/maven-resolver-transport-jdk-21/pom.xml +++ /dev/null @@ -1,98 +0,0 @@ - - - - 4.0.0 - - - org.apache.maven.resolver - maven-resolver-transport-jdk-parent - 2.0.1-SNAPSHOT - - - maven-resolver-transport-jdk-21 - jar - - Maven Artifact Resolver Transport JDK 21 - Maven Artifact Transport JDK Java 11+. - - - 21 - - - - - org.slf4j - slf4j-api - - - org.apache.maven.resolver - maven-resolver-api - - - org.apache.maven.resolver - maven-resolver-spi - - - org.apache.maven.resolver - maven-resolver-util - - - javax.inject - javax.inject - provided - true - - - - org.junit.jupiter - junit-jupiter-api - test - - - org.slf4j - slf4j-simple - test - - - org.apache.maven.resolver - maven-resolver-test-util - test - - - org.apache.maven.resolver - maven-resolver-test-http - test - - - org.apache.maven.resolver - maven-resolver-impl - test - - - - - - - org.eclipse.sisu - sisu-maven-plugin - - - - diff --git a/maven-resolver-transport-jdk-parent/maven-resolver-transport-jdk-21/src/main/java/org/eclipse/aether/transport/jdk/JdkTransporterCloser.java b/maven-resolver-transport-jdk-parent/maven-resolver-transport-jdk-21/src/main/java/org/eclipse/aether/transport/jdk/JdkTransporterCloser.java deleted file mode 100644 index b7da9a81a..000000000 --- a/maven-resolver-transport-jdk-parent/maven-resolver-transport-jdk-21/src/main/java/org/eclipse/aether/transport/jdk/JdkTransporterCloser.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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. - */ -package org.eclipse.aether.transport.jdk; - -import java.net.http.HttpClient; - -/** - * JDK Transport that properly closes {@link HttpClient} on Java 21+. - * - * @since 2.0.0 - */ -public final class JdkTransporterCloser { - static Runnable closer(int javaVersion, HttpClient httpClient) { - return httpClient::shutdownNow; - } -} diff --git a/maven-resolver-transport-jdk-parent/maven-resolver-transport-jdk/pom.xml b/maven-resolver-transport-jdk-parent/maven-resolver-transport-jdk/pom.xml index 7fe556a58..97f03208d 100644 --- a/maven-resolver-transport-jdk-parent/maven-resolver-transport-jdk/pom.xml +++ b/maven-resolver-transport-jdk-parent/maven-resolver-transport-jdk/pom.xml @@ -53,12 +53,6 @@ ${project.version} true - - org.apache.maven.resolver - maven-resolver-transport-jdk-21 - ${project.version} - true - org.slf4j @@ -135,18 +129,6 @@ **/*.class - - java21 - - unpack-dependencies - - generate-resources - - maven-resolver-transport-jdk-21 - ${project.build.directory}/generated-resources/META-INF/versions/21 - **/*.class - - diff --git a/maven-resolver-transport-jdk-parent/pom.xml b/maven-resolver-transport-jdk-parent/pom.xml index 83d26deb1..16d4966e5 100644 --- a/maven-resolver-transport-jdk-parent/pom.xml +++ b/maven-resolver-transport-jdk-parent/pom.xml @@ -35,7 +35,6 @@ maven-resolver-transport-jdk-8 maven-resolver-transport-jdk-11 - maven-resolver-transport-jdk-21 maven-resolver-transport-jdk