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

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


The following commit(s) were added to refs/heads/maven-resolver-1.9.x by this 
push:
     new 96da9ccc6 GH-1768 Drastically simplify auth caching (#1790)
96da9ccc6 is described below

commit 96da9ccc65687a7eecbe5424abea3e24b406fe5f
Author: Tamas Cservenak <[email protected]>
AuthorDate: Thu Feb 12 12:17:41 2026 +0100

    GH-1768 Drastically simplify auth caching (#1790)
    
    As there is a reproducible issue for proxy auth cache. Seems auth cache 
fall apart in the moment non-single thread flow happens. Instead to chase and 
wrap around our head, I just went to drastically simplify the whole stuff, 
without dropping any existing feature, and making sure that reproducer does not 
reproduce anymore.
    
    Fixes #1768
---
 .../aether/transport/http/AuthSchemePool.java      | 60 --------------
 .../eclipse/aether/transport/http/GlobalState.java |  8 --
 .../aether/transport/http/HttpTransporter.java     | 23 +++++-
 .../eclipse/aether/transport/http/LocalState.java  | 28 -------
 .../aether/transport/http/SharingAuthCache.java    | 95 ----------------------
 .../aether/transport/http/SharingHttpContext.java  | 13 +--
 6 files changed, 23 insertions(+), 204 deletions(-)

diff --git 
a/maven-resolver-transport-http/src/main/java/org/eclipse/aether/transport/http/AuthSchemePool.java
 
b/maven-resolver-transport-http/src/main/java/org/eclipse/aether/transport/http/AuthSchemePool.java
deleted file mode 100644
index 2603eae56..000000000
--- 
a/maven-resolver-transport-http/src/main/java/org/eclipse/aether/transport/http/AuthSchemePool.java
+++ /dev/null
@@ -1,60 +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.http;
-
-import java.util.LinkedList;
-
-import org.apache.http.auth.AuthScheme;
-import org.apache.http.client.config.AuthSchemes;
-import org.apache.http.impl.auth.BasicScheme;
-
-/**
- * Pool of (equivalent) auth schemes for a single host.
- */
-final class AuthSchemePool {
-
-    private final LinkedList<AuthScheme> authSchemes;
-
-    private String schemeName;
-
-    AuthSchemePool() {
-        authSchemes = new LinkedList<>();
-    }
-
-    public synchronized AuthScheme get() {
-        AuthScheme authScheme = null;
-        if (!authSchemes.isEmpty()) {
-            authScheme = authSchemes.removeLast();
-        } else if (AuthSchemes.BASIC.equalsIgnoreCase(schemeName)) {
-            authScheme = new BasicScheme();
-        }
-        return authScheme;
-    }
-
-    public synchronized void put(AuthScheme authScheme) {
-        if (authScheme == null) {
-            return;
-        }
-        if (!authScheme.getSchemeName().equals(schemeName)) {
-            schemeName = authScheme.getSchemeName();
-            authSchemes.clear();
-        }
-        authSchemes.add(authScheme);
-    }
-}
diff --git 
a/maven-resolver-transport-http/src/main/java/org/eclipse/aether/transport/http/GlobalState.java
 
b/maven-resolver-transport-http/src/main/java/org/eclipse/aether/transport/http/GlobalState.java
index 3ac06619a..ae6cc4607 100644
--- 
a/maven-resolver-transport-http/src/main/java/org/eclipse/aether/transport/http/GlobalState.java
+++ 
b/maven-resolver-transport-http/src/main/java/org/eclipse/aether/transport/http/GlobalState.java
@@ -29,7 +29,6 @@ import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.TimeUnit;
 
-import org.apache.http.HttpHost;
 import org.apache.http.config.RegistryBuilder;
 import org.apache.http.conn.HttpClientConnectionManager;
 import org.apache.http.conn.socket.ConnectionSocketFactory;
@@ -95,8 +94,6 @@ final class GlobalState implements Closeable {
 
     private final ConcurrentMap<CompoundKey, Object> userTokens;
 
-    private final ConcurrentMap<HttpHost, AuthSchemePool> authSchemePools;
-
     private final ConcurrentMap<CompoundKey, Boolean> expectContinues;
 
     public static GlobalState get(RepositorySystemSession session) {
@@ -126,7 +123,6 @@ final class GlobalState implements Closeable {
     private GlobalState() {
         connectionManagers = new ConcurrentHashMap<>();
         userTokens = new ConcurrentHashMap<>();
-        authSchemePools = new ConcurrentHashMap<>();
         expectContinues = new ConcurrentHashMap<>();
     }
 
@@ -216,10 +212,6 @@ final class GlobalState implements Closeable {
         }
     }
 
-    public ConcurrentMap<HttpHost, AuthSchemePool> getAuthSchemePools() {
-        return authSchemePools;
-    }
-
     public Boolean getExpectContinue(CompoundKey key) {
         return expectContinues.get(key);
     }
diff --git 
a/maven-resolver-transport-http/src/main/java/org/eclipse/aether/transport/http/HttpTransporter.java
 
b/maven-resolver-transport-http/src/main/java/org/eclipse/aether/transport/http/HttpTransporter.java
index 0d44af1a9..85d5068a1 100644
--- 
a/maven-resolver-transport-http/src/main/java/org/eclipse/aether/transport/http/HttpTransporter.java
+++ 
b/maven-resolver-transport-http/src/main/java/org/eclipse/aether/transport/http/HttpTransporter.java
@@ -49,6 +49,7 @@ import org.apache.http.HttpResponse;
 import org.apache.http.HttpStatus;
 import org.apache.http.auth.AuthSchemeProvider;
 import org.apache.http.auth.AuthScope;
+import org.apache.http.client.AuthCache;
 import org.apache.http.client.CredentialsProvider;
 import org.apache.http.client.HttpRequestRetryHandler;
 import org.apache.http.client.HttpResponseException;
@@ -76,6 +77,7 @@ import org.apache.http.impl.auth.DigestSchemeFactory;
 import org.apache.http.impl.auth.KerberosSchemeFactory;
 import org.apache.http.impl.auth.NTLMSchemeFactory;
 import org.apache.http.impl.auth.SPNegoSchemeFactory;
+import org.apache.http.impl.client.BasicAuthCache;
 import org.apache.http.impl.client.CloseableHttpClient;
 import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
 import org.apache.http.impl.client.HttpClientBuilder;
@@ -99,6 +101,7 @@ import 
org.eclipse.aether.transport.http.RFC9457.HttpRFC9457Exception;
 import org.eclipse.aether.transport.http.RFC9457.RFC9457Reporter;
 import org.eclipse.aether.util.ConfigUtils;
 import org.eclipse.aether.util.FileUtils;
+import org.eclipse.aether.util.StringDigestUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -155,6 +158,10 @@ final class HttpTransporter extends AbstractTransporter {
 
     private final boolean supportWebDav;
 
+    private final AuthCache authCache;
+
+    private static final Object AUTH_CACHE_MUTEX = new Object();
+
     @SuppressWarnings("checkstyle:methodlength")
     HttpTransporter(
             Map<String, ChecksumExtractor> checksumExtractors,
@@ -358,6 +365,20 @@ final class HttpTransporter extends AbstractTransporter {
             
builder.setConnectionReuseStrategy(NoConnectionReuseStrategy.INSTANCE);
         }
 
+        if (session.getCache() != null) {
+            String authCacheKey = getClass().getSimpleName() + "-" + 
repository.getId() + "-"
+                    + StringDigestUtil.sha1(repository.toString());
+            synchronized (AUTH_CACHE_MUTEX) {
+                AuthCache cache = (AuthCache) session.getCache().get(session, 
authCacheKey);
+                if (cache == null) {
+                    cache = new BasicAuthCache();
+                    session.getCache().put(session, authCacheKey, cache);
+                }
+                this.authCache = cache;
+            }
+        } else {
+            this.authCache = new BasicAuthCache();
+        }
         this.client = builder.build();
     }
 
@@ -504,10 +525,10 @@ final class HttpTransporter extends AbstractTransporter {
     private void execute(HttpUriRequest request, EntityGetter getter) throws 
Exception {
         try {
             SharingHttpContext context = new SharingHttpContext(state);
+            context.setAuthCache(authCache);
             prepare(request, context);
             try (CloseableHttpResponse response = client.execute(server, 
request, context)) {
                 try {
-                    context.close();
                     handleStatus(response);
                     if (getter != null) {
                         getter.handle(response);
diff --git 
a/maven-resolver-transport-http/src/main/java/org/eclipse/aether/transport/http/LocalState.java
 
b/maven-resolver-transport-http/src/main/java/org/eclipse/aether/transport/http/LocalState.java
index c7352bcd0..28e9fcf43 100644
--- 
a/maven-resolver-transport-http/src/main/java/org/eclipse/aether/transport/http/LocalState.java
+++ 
b/maven-resolver-transport-http/src/main/java/org/eclipse/aether/transport/http/LocalState.java
@@ -19,11 +19,7 @@
 package org.eclipse.aether.transport.http;
 
 import java.io.Closeable;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
 
-import org.apache.http.HttpHost;
-import org.apache.http.auth.AuthScheme;
 import org.apache.http.conn.HttpClientConnectionManager;
 import org.eclipse.aether.RepositorySystemSession;
 import org.eclipse.aether.repository.RemoteRepository;
@@ -48,8 +44,6 @@ final class LocalState implements Closeable {
 
     private volatile Boolean webDav;
 
-    private final ConcurrentMap<HttpHost, AuthSchemePool> authSchemePools;
-
     LocalState(RepositorySystemSession session, RemoteRepository repo, 
ConnMgrConfig connMgrConfig) {
         global = GlobalState.get(session);
         userToken = this;
@@ -57,12 +51,10 @@ final class LocalState implements Closeable {
             connMgr = GlobalState.newConnectionManager(connMgrConfig);
             userTokenKey = null;
             expectContinueKey = null;
-            authSchemePools = new ConcurrentHashMap<>();
         } else {
             connMgr = global.getConnectionManager(connMgrConfig);
             userTokenKey = new CompoundKey(repo.getId(), repo.getUrl(), 
repo.getAuthentication(), repo.getProxy());
             expectContinueKey = new CompoundKey(repo.getUrl(), 
repo.getProxy());
-            authSchemePools = global.getAuthSchemePools();
         }
     }
 
@@ -107,26 +99,6 @@ final class LocalState implements Closeable {
         this.webDav = webDav;
     }
 
-    public AuthScheme getAuthScheme(HttpHost host) {
-        AuthSchemePool pool = authSchemePools.get(host);
-        if (pool != null) {
-            return pool.get();
-        }
-        return null;
-    }
-
-    public void setAuthScheme(HttpHost host, AuthScheme authScheme) {
-        AuthSchemePool pool = authSchemePools.get(host);
-        if (pool == null) {
-            AuthSchemePool p = new AuthSchemePool();
-            pool = authSchemePools.putIfAbsent(host, p);
-            if (pool == null) {
-                pool = p;
-            }
-        }
-        pool.put(authScheme);
-    }
-
     @Override
     public void close() {
         if (global == null) {
diff --git 
a/maven-resolver-transport-http/src/main/java/org/eclipse/aether/transport/http/SharingAuthCache.java
 
b/maven-resolver-transport-http/src/main/java/org/eclipse/aether/transport/http/SharingAuthCache.java
deleted file mode 100644
index d7ed9c591..000000000
--- 
a/maven-resolver-transport-http/src/main/java/org/eclipse/aether/transport/http/SharingAuthCache.java
+++ /dev/null
@@ -1,95 +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.http;
-
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.apache.http.HttpHost;
-import org.apache.http.auth.AuthScheme;
-import org.apache.http.client.AuthCache;
-
-/**
- * Auth scheme cache that upon clearing releases all cached schemes into a 
pool for future reuse by other requests,
- * thereby reducing challenge-response roundtrips.
- */
-final class SharingAuthCache implements AuthCache {
-
-    private final LocalState state;
-
-    private final ConcurrentHashMap<HttpHost, AuthScheme> authSchemes;
-
-    SharingAuthCache(LocalState state) {
-        this.state = state;
-        authSchemes = new ConcurrentHashMap<>();
-    }
-
-    private static HttpHost toKey(HttpHost host) {
-        if (host.getPort() <= 0) {
-            int port = host.getSchemeName().equalsIgnoreCase("https") ? 443 : 
80;
-            return new HttpHost(host.getHostName(), port, 
host.getSchemeName());
-        }
-        return host;
-    }
-
-    @Override
-    public AuthScheme get(HttpHost host) {
-        host = toKey(host);
-        AuthScheme authScheme = authSchemes.get(host);
-        if (authScheme == null) {
-            authScheme = state.getAuthScheme(host);
-            if (authScheme != null) {
-                authSchemes.put(host, authScheme);
-            }
-        }
-        return authScheme;
-    }
-
-    @Override
-    public void put(HttpHost host, AuthScheme authScheme) {
-        host = toKey(host);
-        if (authScheme != null) {
-            authSchemes.put(host, authScheme);
-        } else {
-            authSchemes.remove(host);
-        }
-    }
-
-    @Override
-    public void remove(HttpHost host) {
-        authSchemes.remove(toKey(host));
-    }
-
-    @Override
-    public void clear() {
-        share();
-        authSchemes.clear();
-    }
-
-    private void share() {
-        for (Map.Entry<HttpHost, AuthScheme> entry : authSchemes.entrySet()) {
-            state.setAuthScheme(entry.getKey(), entry.getValue());
-        }
-    }
-
-    @Override
-    public String toString() {
-        return authSchemes.toString();
-    }
-}
diff --git 
a/maven-resolver-transport-http/src/main/java/org/eclipse/aether/transport/http/SharingHttpContext.java
 
b/maven-resolver-transport-http/src/main/java/org/eclipse/aether/transport/http/SharingHttpContext.java
index 3a2db193c..51021c6ea 100644
--- 
a/maven-resolver-transport-http/src/main/java/org/eclipse/aether/transport/http/SharingHttpContext.java
+++ 
b/maven-resolver-transport-http/src/main/java/org/eclipse/aether/transport/http/SharingHttpContext.java
@@ -18,8 +18,6 @@
  */
 package org.eclipse.aether.transport.http;
 
-import java.io.Closeable;
-
 import org.apache.http.client.protocol.HttpClientContext;
 
 /**
@@ -28,16 +26,12 @@ import org.apache.http.client.protocol.HttpClientContext;
  * @see <a 
href="http://hc.apache.org/httpcomponents-client-ga/tutorial/html/advanced.html#stateful_conn";>Stateful
 HTTP
  *      connections</a>
  */
-final class SharingHttpContext extends HttpClientContext implements Closeable {
+final class SharingHttpContext extends HttpClientContext {
 
     private final LocalState state;
 
-    private final SharingAuthCache authCache;
-
     SharingHttpContext(LocalState state) {
         this.state = state;
-        authCache = new SharingAuthCache(state);
-        super.setAttribute(HttpClientContext.AUTH_CACHE, authCache);
     }
 
     @Override
@@ -65,9 +59,4 @@ final class SharingHttpContext extends HttpClientContext 
implements Closeable {
         }
         return super.removeAttribute(id);
     }
-
-    @Override
-    public void close() {
-        authCache.clear();
-    }
 }

Reply via email to