This is an automated email from the ASF dual-hosted git repository.

cstamas pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git


The following commit(s) were added to refs/heads/master by this push:
     new d013a328 [MRESOLVER-584] Jetty fix for GOAWAY (#533)
d013a328 is described below

commit d013a3289fdfecf30932c63133ae41e1661aa5ab
Author: Tamas Cservenak <ta...@cservenak.net>
AuthorDate: Fri Aug 2 15:19:46 2024 +0200

    [MRESOLVER-584] Jetty fix for GOAWAY (#533)
    
    Just shorten the client lifespan to connector transaction duration vs as 
before, for whole session duration. Also simplify the code.
    
    ---
    
    https://issues.apache.org/jira/browse/MRESOLVER-584
---
 .../aether/transport/jetty/JettyTransporter.java   | 310 +++++++++------------
 1 file changed, 134 insertions(+), 176 deletions(-)

diff --git 
a/maven-resolver-transport-jetty/src/main/java/org/eclipse/aether/transport/jetty/JettyTransporter.java
 
b/maven-resolver-transport-jetty/src/main/java/org/eclipse/aether/transport/jetty/JettyTransporter.java
index 4dcb500b..83f88ced 100644
--- 
a/maven-resolver-transport-jetty/src/main/java/org/eclipse/aether/transport/jetty/JettyTransporter.java
+++ 
b/maven-resolver-transport-jetty/src/main/java/org/eclipse/aether/transport/jetty/JettyTransporter.java
@@ -70,8 +70,6 @@ import org.eclipse.jetty.http2.client.HTTP2Client;
 import org.eclipse.jetty.http2.client.http.ClientConnectionFactoryOverHTTP2;
 import org.eclipse.jetty.io.ClientConnector;
 import org.eclipse.jetty.util.ssl.SslContextFactory;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import static 
org.eclipse.aether.spi.connector.transport.http.HttpConstants.ACCEPT_ENCODING;
 import static 
org.eclipse.aether.spi.connector.transport.http.HttpConstants.CONTENT_LENGTH;
@@ -93,6 +91,10 @@ import static 
org.eclipse.aether.spi.connector.transport.http.HttpConstants.USER
 final class JettyTransporter extends AbstractTransporter implements 
HttpTransporter {
     private static final long MODIFICATION_THRESHOLD = 60L * 1000L;
 
+    private final RepositorySystemSession session;
+
+    private final RemoteRepository repository;
+
     private final ChecksumExtractor checksumExtractor;
 
     private final PathProcessor pathProcessor;
@@ -109,9 +111,11 @@ final class JettyTransporter extends AbstractTransporter 
implements HttpTranspor
 
     private final boolean preemptivePutAuth;
 
-    private final BasicAuthentication.BasicResult 
basicServerAuthenticationResult;
+    private final boolean insecure;
+
+    private final AtomicReference<BasicAuthentication.BasicResult> 
basicServerAuthenticationResult;
 
-    private final BasicAuthentication.BasicResult 
basicProxyAuthenticationResult;
+    private final AtomicReference<BasicAuthentication.BasicResult> 
basicProxyAuthenticationResult;
 
     JettyTransporter(
             RepositorySystemSession session,
@@ -119,6 +123,8 @@ final class JettyTransporter extends AbstractTransporter 
implements HttpTranspor
             ChecksumExtractor checksumExtractor,
             PathProcessor pathProcessor)
             throws NoTransporterException {
+        this.session = session;
+        this.repository = repository;
         this.checksumExtractor = checksumExtractor;
         this.pathProcessor = pathProcessor;
         try {
@@ -177,14 +183,34 @@ final class JettyTransporter extends AbstractTransporter 
implements HttpTranspor
                 ConfigurationProperties.DEFAULT_HTTP_PREEMPTIVE_PUT_AUTH,
                 ConfigurationProperties.HTTP_PREEMPTIVE_PUT_AUTH + "." + 
repository.getId(),
                 ConfigurationProperties.HTTP_PREEMPTIVE_PUT_AUTH);
+        final String httpsSecurityMode = ConfigUtils.getString(
+                session,
+                ConfigurationProperties.HTTPS_SECURITY_MODE_DEFAULT,
+                ConfigurationProperties.HTTPS_SECURITY_MODE + "." + 
repository.getId(),
+                ConfigurationProperties.HTTPS_SECURITY_MODE);
 
-        this.client = getOrCreateClient(session, repository);
+        if 
(!ConfigurationProperties.HTTPS_SECURITY_MODE_DEFAULT.equals(httpsSecurityMode)
+                && 
!ConfigurationProperties.HTTPS_SECURITY_MODE_INSECURE.equals(httpsSecurityMode))
 {
+            throw new IllegalArgumentException("Unsupported '" + 
httpsSecurityMode + "' HTTPS security mode.");
+        }
+        this.insecure = 
ConfigurationProperties.HTTPS_SECURITY_MODE_INSECURE.equals(httpsSecurityMode);
+
+        this.basicServerAuthenticationResult = new AtomicReference<>(null);
+        this.basicProxyAuthenticationResult = new AtomicReference<>(null);
+        try {
+            this.client = createClient();
+        } catch (Exception e) {
+            throw new NoTransporterException(repository, e);
+        }
+    }
 
-        final String instanceKey = JETTY_INSTANCE_KEY_PREFIX + 
repository.getId();
-        this.basicServerAuthenticationResult =
-                (BasicAuthentication.BasicResult) 
session.getData().get(instanceKey + ".serverAuth");
-        this.basicProxyAuthenticationResult =
-                (BasicAuthentication.BasicResult) 
session.getData().get(instanceKey + ".proxyAuth");
+    private void mayApplyPreemptiveAuth(Request request) {
+        if (basicServerAuthenticationResult.get() != null) {
+            basicServerAuthenticationResult.get().apply(request);
+        }
+        if (basicProxyAuthenticationResult.get() != null) {
+            basicProxyAuthenticationResult.get().apply(request);
+        }
     }
 
     private URI resolve(TransportTask task) {
@@ -207,12 +233,7 @@ final class JettyTransporter extends AbstractTransporter 
implements HttpTranspor
                 .method("HEAD");
         request.headers(m -> headers.forEach(m::add));
         if (preemptiveAuth) {
-            if (basicServerAuthenticationResult != null) {
-                basicServerAuthenticationResult.apply(request);
-            }
-            if (basicProxyAuthenticationResult != null) {
-                basicProxyAuthenticationResult.apply(request);
-            }
+            mayApplyPreemptiveAuth(request);
         }
         Response response = request.send();
         if (response.getStatus() >= MULTIPLE_CHOICES) {
@@ -232,12 +253,7 @@ final class JettyTransporter extends AbstractTransporter 
implements HttpTranspor
                     .method("GET");
             request.headers(m -> headers.forEach(m::add));
             if (preemptiveAuth) {
-                if (basicServerAuthenticationResult != null) {
-                    basicServerAuthenticationResult.apply(request);
-                }
-                if (basicProxyAuthenticationResult != null) {
-                    basicProxyAuthenticationResult.apply(request);
-                }
+                mayApplyPreemptiveAuth(request);
             }
 
             if (resume) {
@@ -335,12 +351,7 @@ final class JettyTransporter extends AbstractTransporter 
implements HttpTranspor
         Request request = 
client.newRequest(resolve(task)).method("PUT").timeout(requestTimeout, 
TimeUnit.MILLISECONDS);
         request.headers(m -> headers.forEach(m::add));
         if (preemptiveAuth || preemptivePutAuth) {
-            if (basicServerAuthenticationResult != null) {
-                basicServerAuthenticationResult.apply(request);
-            }
-            if (basicProxyAuthenticationResult != null) {
-                basicProxyAuthenticationResult.apply(request);
-            }
+            mayApplyPreemptiveAuth(request);
         }
         request.body(new PutTaskRequestContent(task));
         AtomicBoolean started = new AtomicBoolean(false);
@@ -395,176 +406,123 @@ final class JettyTransporter extends 
AbstractTransporter implements HttpTranspor
 
     @Override
     protected void implClose() {
-        // noop
+        try {
+            this.client.stop();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
     }
 
-    /**
-     * Visible for testing.
-     */
-    static final String JETTY_INSTANCE_KEY_PREFIX = 
JettyTransporterFactory.class.getName() + ".jetty.";
+    @SuppressWarnings("checkstyle:methodlength")
+    private HttpClient createClient() throws Exception {
+        BasicAuthentication.BasicResult serverAuth = null;
+        BasicAuthentication.BasicResult proxyAuth = null;
+        SSLContext sslContext = null;
+        BasicAuthentication basicAuthentication = null;
+        try (AuthenticationContext repoAuthContext = 
AuthenticationContext.forRepository(session, repository)) {
+            if (repoAuthContext != null) {
+                sslContext = 
repoAuthContext.get(AuthenticationContext.SSL_CONTEXT, SSLContext.class);
+
+                String username = 
repoAuthContext.get(AuthenticationContext.USERNAME);
+                String password = 
repoAuthContext.get(AuthenticationContext.PASSWORD);
+
+                URI uri = URI.create(repository.getUrl());
+                basicAuthentication = new BasicAuthentication(uri, 
Authentication.ANY_REALM, username, password);
+                if (preemptiveAuth || preemptivePutAuth) {
+                    serverAuth = new BasicAuthentication.BasicResult(uri, 
HttpHeader.AUTHORIZATION, username, password);
+                }
+            }
+        }
 
-    static final Logger LOGGER = 
LoggerFactory.getLogger(JettyTransporter.class);
+        if (sslContext == null) {
+            if (insecure) {
+                sslContext = SSLContext.getInstance("TLS");
+                X509TrustManager tm = new X509TrustManager() {
+                    @Override
+                    public void checkClientTrusted(X509Certificate[] chain, 
String authType) {}
 
-    @SuppressWarnings("checkstyle:methodlength")
-    private HttpClient getOrCreateClient(RepositorySystemSession session, 
RemoteRepository repository)
-            throws NoTransporterException {
+                    @Override
+                    public void checkServerTrusted(X509Certificate[] chain, 
String authType) {}
 
-        final String instanceKey = JETTY_INSTANCE_KEY_PREFIX + 
repository.getId();
+                    @Override
+                    public X509Certificate[] getAcceptedIssuers() {
+                        return new X509Certificate[0];
+                    }
+                };
+                sslContext.init(null, new X509TrustManager[] {tm}, null);
+            } else {
+                sslContext = SSLContext.getDefault();
+            }
+        }
 
-        final String httpsSecurityMode = ConfigUtils.getString(
+        int connectTimeout = ConfigUtils.getInteger(
                 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.");
+                ConfigurationProperties.DEFAULT_CONNECT_TIMEOUT,
+                ConfigurationProperties.CONNECT_TIMEOUT + "." + 
repository.getId(),
+                ConfigurationProperties.CONNECT_TIMEOUT);
+
+        SslContextFactory.Client sslContextFactory = new 
SslContextFactory.Client();
+        sslContextFactory.setSslContext(sslContext);
+        if (insecure) {
+            sslContextFactory.setEndpointIdentificationAlgorithm(null);
+            sslContextFactory.setHostnameVerifier((name, context) -> true);
         }
-        final boolean insecure = 
ConfigurationProperties.HTTPS_SECURITY_MODE_INSECURE.equals(httpsSecurityMode);
 
-        try {
-            AtomicReference<BasicAuthentication.BasicResult> serverAuth = new 
AtomicReference<>(null);
-            AtomicReference<BasicAuthentication.BasicResult> proxyAuth = new 
AtomicReference<>(null);
-            HttpClient client = (HttpClient) 
session.getData().computeIfAbsent(instanceKey, () -> {
-                SSLContext sslContext = null;
-                BasicAuthentication basicAuthentication = null;
-                try {
-                    try (AuthenticationContext repoAuthContext =
-                            AuthenticationContext.forRepository(session, 
repository)) {
-                        if (repoAuthContext != null) {
-                            sslContext = 
repoAuthContext.get(AuthenticationContext.SSL_CONTEXT, SSLContext.class);
-
-                            String username = 
repoAuthContext.get(AuthenticationContext.USERNAME);
-                            String password = 
repoAuthContext.get(AuthenticationContext.PASSWORD);
-
-                            URI uri = URI.create(repository.getUrl());
-                            basicAuthentication =
-                                    new BasicAuthentication(uri, 
Authentication.ANY_REALM, username, password);
-                            if (preemptiveAuth || preemptivePutAuth) {
-                                serverAuth.set(new 
BasicAuthentication.BasicResult(
-                                        uri, HttpHeader.AUTHORIZATION, 
username, password));
-                            }
-                        }
-                    }
+        ClientConnector clientConnector = new ClientConnector();
+        clientConnector.setSslContextFactory(sslContextFactory);
 
-                    if (sslContext == null) {
-                        if (insecure) {
-                            sslContext = SSLContext.getInstance("TLS");
-                            X509TrustManager tm = new X509TrustManager() {
-                                @Override
-                                public void 
checkClientTrusted(X509Certificate[] chain, String authType) {}
+        HTTP2Client http2Client = new HTTP2Client(clientConnector);
+        ClientConnectionFactoryOverHTTP2.HTTP2 http2 = new 
ClientConnectionFactoryOverHTTP2.HTTP2(http2Client);
 
-                                @Override
-                                public void 
checkServerTrusted(X509Certificate[] chain, String authType) {}
+        HttpClientTransportDynamic transport;
+        if ("https".equalsIgnoreCase(repository.getProtocol())) {
+            transport = new HttpClientTransportDynamic(
+                    clientConnector, http2, 
HttpClientConnectionFactory.HTTP11); // HTTPS, prefer H2
+        } else {
+            transport = new HttpClientTransportDynamic(
+                    clientConnector, HttpClientConnectionFactory.HTTP11, 
http2); // plaintext HTTP, H2 cannot be used
+        }
 
-                                @Override
-                                public X509Certificate[] getAcceptedIssuers() {
-                                    return new X509Certificate[0];
-                                }
-                            };
-                            sslContext.init(null, new X509TrustManager[] {tm}, 
null);
-                        } else {
-                            sslContext = SSLContext.getDefault();
-                        }
-                    }
+        HttpClient httpClient = new HttpClient(transport);
+        httpClient.setConnectTimeout(connectTimeout);
+        httpClient.setFollowRedirects(true);
+        httpClient.setMaxRedirects(2);
 
-                    int connectTimeout = ConfigUtils.getInteger(
-                            session,
-                            ConfigurationProperties.DEFAULT_CONNECT_TIMEOUT,
-                            ConfigurationProperties.CONNECT_TIMEOUT + "." + 
repository.getId(),
-                            ConfigurationProperties.CONNECT_TIMEOUT);
-
-                    SslContextFactory.Client sslContextFactory = new 
SslContextFactory.Client();
-                    sslContextFactory.setSslContext(sslContext);
-                    if (insecure) {
-                        
sslContextFactory.setEndpointIdentificationAlgorithm(null);
-                        sslContextFactory.setHostnameVerifier((name, context) 
-> true);
-                    }
+        httpClient.setUserAgentField(null); // we manage it
 
-                    ClientConnector clientConnector = new ClientConnector();
-                    clientConnector.setSslContextFactory(sslContextFactory);
-
-                    HTTP2Client http2Client = new HTTP2Client(clientConnector);
-                    ClientConnectionFactoryOverHTTP2.HTTP2 http2 =
-                            new 
ClientConnectionFactoryOverHTTP2.HTTP2(http2Client);
-
-                    HttpClientTransportDynamic transport;
-                    if ("https".equalsIgnoreCase(repository.getProtocol())) {
-                        transport = new HttpClientTransportDynamic(
-                                clientConnector, http2, 
HttpClientConnectionFactory.HTTP11); // HTTPS, prefer H2
-                    } else {
-                        transport = new HttpClientTransportDynamic(
-                                clientConnector,
-                                HttpClientConnectionFactory.HTTP11,
-                                http2); // plaintext HTTP, H2 cannot be used
-                    }
+        if (basicAuthentication != null) {
+            
httpClient.getAuthenticationStore().addAuthentication(basicAuthentication);
+        }
 
-                    HttpClient httpClient = new HttpClient(transport);
-                    httpClient.setConnectTimeout(connectTimeout);
-                    httpClient.setFollowRedirects(true);
-                    httpClient.setMaxRedirects(2);
+        if (repository.getProxy() != null) {
+            HttpProxy proxy = new HttpProxy(
+                    repository.getProxy().getHost(), 
repository.getProxy().getPort());
 
-                    httpClient.setUserAgentField(null); // we manage it
+            httpClient.getProxyConfiguration().addProxy(proxy);
+            try (AuthenticationContext proxyAuthContext = 
AuthenticationContext.forProxy(session, repository)) {
+                if (proxyAuthContext != null) {
+                    String username = 
proxyAuthContext.get(AuthenticationContext.USERNAME);
+                    String password = 
proxyAuthContext.get(AuthenticationContext.PASSWORD);
 
-                    if (basicAuthentication != null) {
-                        
httpClient.getAuthenticationStore().addAuthentication(basicAuthentication);
-                    }
+                    BasicAuthentication proxyAuthentication =
+                            new BasicAuthentication(proxy.getURI(), 
Authentication.ANY_REALM, username, password);
 
-                    if (repository.getProxy() != null) {
-                        HttpProxy proxy = new HttpProxy(
-                                repository.getProxy().getHost(),
-                                repository.getProxy().getPort());
-
-                        httpClient.getProxyConfiguration().addProxy(proxy);
-                        try (AuthenticationContext proxyAuthContext =
-                                AuthenticationContext.forProxy(session, 
repository)) {
-                            if (proxyAuthContext != null) {
-                                String username = 
proxyAuthContext.get(AuthenticationContext.USERNAME);
-                                String password = 
proxyAuthContext.get(AuthenticationContext.PASSWORD);
-
-                                BasicAuthentication proxyAuthentication = new 
BasicAuthentication(
-                                        proxy.getURI(), 
Authentication.ANY_REALM, username, password);
-
-                                
httpClient.getAuthenticationStore().addAuthentication(proxyAuthentication);
-                                if (preemptiveAuth || preemptivePutAuth) {
-                                    proxyAuth.set(new 
BasicAuthentication.BasicResult(
-                                            proxy.getURI(), 
HttpHeader.PROXY_AUTHORIZATION, username, password));
-                                }
-                            }
-                        }
+                    
httpClient.getAuthenticationStore().addAuthentication(proxyAuthentication);
+                    if (preemptiveAuth || preemptivePutAuth) {
+                        proxyAuth = new BasicAuthentication.BasicResult(
+                                proxy.getURI(), 
HttpHeader.PROXY_AUTHORIZATION, username, password);
                     }
-                    if (!session.addOnSessionEndedHandler(() -> {
-                        try {
-                            httpClient.stop();
-                        } catch (Exception e) {
-                            throw new RuntimeException(e);
-                        }
-                    })) {
-                        LOGGER.warn(
-                                "Using Resolver 2 feature without Resolver 2 
session handling, you may leak resources.");
-                    }
-                    httpClient.start();
-                    return httpClient;
-                } catch (Exception e) {
-                    throw new WrapperEx(e);
                 }
-            });
-            if (serverAuth.get() != null) {
-                session.getData().set(instanceKey + ".serverAuth", 
serverAuth.get());
-            }
-            if (proxyAuth.get() != null) {
-                session.getData().set(instanceKey + ".proxyAuth", 
proxyAuth.get());
             }
-            return client;
-        } catch (WrapperEx e) {
-            throw new NoTransporterException(repository, e.getCause());
         }
-    }
-
-    private static final class WrapperEx extends RuntimeException {
-        private WrapperEx(Throwable cause) {
-            super(cause);
+        if (serverAuth != null) {
+            this.basicServerAuthenticationResult.set(serverAuth);
         }
+        if (proxyAuth != null) {
+            this.basicProxyAuthenticationResult.set(proxyAuth);
+        }
+
+        httpClient.start();
+        return httpClient;
     }
 }

Reply via email to