1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.aether.transport.http;
20
21 import javax.net.ssl.HostnameVerifier;
22 import javax.net.ssl.SSLSocketFactory;
23
24 import java.io.Closeable;
25 import java.util.Arrays;
26 import java.util.Iterator;
27 import java.util.Map;
28 import java.util.concurrent.ConcurrentHashMap;
29 import java.util.concurrent.ConcurrentMap;
30
31 import org.apache.http.HttpHost;
32 import org.apache.http.config.RegistryBuilder;
33 import org.apache.http.conn.HttpClientConnectionManager;
34 import org.apache.http.conn.socket.ConnectionSocketFactory;
35 import org.apache.http.conn.socket.PlainConnectionSocketFactory;
36 import org.apache.http.conn.ssl.NoopHostnameVerifier;
37 import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
38 import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
39 import org.apache.http.ssl.SSLContextBuilder;
40 import org.apache.http.ssl.SSLInitializationException;
41 import org.eclipse.aether.ConfigurationProperties;
42 import org.eclipse.aether.RepositoryCache;
43 import org.eclipse.aether.RepositorySystemSession;
44 import org.eclipse.aether.util.ConfigUtils;
45
46
47
48
49
50 final class GlobalState implements Closeable {
51
52 static class CompoundKey {
53
54 private final Object[] keys;
55
56 CompoundKey(Object... keys) {
57 this.keys = keys;
58 }
59
60 @Override
61 public boolean equals(Object obj) {
62 if (this == obj) {
63 return true;
64 }
65 if (obj == null || !getClass().equals(obj.getClass())) {
66 return false;
67 }
68 CompoundKey that = (CompoundKey) obj;
69 return Arrays.equals(keys, that.keys);
70 }
71
72 @Override
73 public int hashCode() {
74 int hash = 17;
75 hash = hash * 31 + Arrays.hashCode(keys);
76 return hash;
77 }
78
79 @Override
80 public String toString() {
81 return Arrays.toString(keys);
82 }
83 }
84
85 private static final String KEY = GlobalState.class.getName();
86
87 private static final String CONFIG_PROP_CACHE_STATE = "aether.connector.http.cacheState";
88
89 private final ConcurrentMap<SslConfig, HttpClientConnectionManager> connectionManagers;
90
91 private final ConcurrentMap<CompoundKey, Object> userTokens;
92
93 private final ConcurrentMap<HttpHost, AuthSchemePool> authSchemePools;
94
95 private final ConcurrentMap<CompoundKey, Boolean> expectContinues;
96
97 public static GlobalState get(RepositorySystemSession session) {
98 GlobalState cache;
99 RepositoryCache repoCache = session.getCache();
100 if (repoCache == null || !ConfigUtils.getBoolean(session, true, CONFIG_PROP_CACHE_STATE)) {
101 cache = null;
102 } else {
103 Object tmp = repoCache.get(session, KEY);
104 if (tmp instanceof GlobalState) {
105 cache = (GlobalState) tmp;
106 } else {
107 synchronized (GlobalState.class) {
108 tmp = repoCache.get(session, KEY);
109 if (tmp instanceof GlobalState) {
110 cache = (GlobalState) tmp;
111 } else {
112 cache = new GlobalState();
113 repoCache.put(session, KEY, cache);
114 }
115 }
116 }
117 }
118 return cache;
119 }
120
121 private GlobalState() {
122 connectionManagers = new ConcurrentHashMap<>();
123 userTokens = new ConcurrentHashMap<>();
124 authSchemePools = new ConcurrentHashMap<>();
125 expectContinues = new ConcurrentHashMap<>();
126 }
127
128 @Override
129 public void close() {
130 for (Iterator<Map.Entry<SslConfig, HttpClientConnectionManager>> it =
131 connectionManagers.entrySet().iterator();
132 it.hasNext(); ) {
133 HttpClientConnectionManager connMgr = it.next().getValue();
134 it.remove();
135 connMgr.shutdown();
136 }
137 }
138
139 public HttpClientConnectionManager getConnectionManager(SslConfig config) {
140 HttpClientConnectionManager manager = connectionManagers.get(config);
141 if (manager == null) {
142 HttpClientConnectionManager connMgr = newConnectionManager(config);
143 manager = connectionManagers.putIfAbsent(config, connMgr);
144 if (manager != null) {
145 connMgr.shutdown();
146 } else {
147 manager = connMgr;
148 }
149 }
150 return manager;
151 }
152
153 @SuppressWarnings("checkstyle:magicnumber")
154 public static HttpClientConnectionManager newConnectionManager(SslConfig sslConfig) {
155 RegistryBuilder<ConnectionSocketFactory> registryBuilder = RegistryBuilder.<ConnectionSocketFactory>create()
156 .register("http", PlainConnectionSocketFactory.getSocketFactory());
157
158 if (sslConfig == null) {
159 registryBuilder.register("https", SSLConnectionSocketFactory.getSystemSocketFactory());
160 } else {
161
162 SSLSocketFactory sslSocketFactory = sslConfig.context != null ? sslConfig.context.getSocketFactory() : null;
163 HostnameVerifier hostnameVerifier = sslConfig.verifier;
164 if (ConfigurationProperties.HTTPS_SECURITY_MODE_DEFAULT.equals(sslConfig.httpsSecurityMode)) {
165 if (sslSocketFactory == null) {
166 sslSocketFactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
167 }
168 if (hostnameVerifier == null) {
169 hostnameVerifier = SSLConnectionSocketFactory.getDefaultHostnameVerifier();
170 }
171 } else if (ConfigurationProperties.HTTPS_SECURITY_MODE_INSECURE.equals(sslConfig.httpsSecurityMode)) {
172 if (sslSocketFactory == null) {
173 try {
174 sslSocketFactory = new SSLContextBuilder()
175 .loadTrustMaterial(null, (chain, auth) -> true)
176 .build()
177 .getSocketFactory();
178 } catch (Exception e) {
179 throw new SSLInitializationException(
180 "Could not configure '" + sslConfig.httpsSecurityMode + "' HTTPS security mode", e);
181 }
182 }
183 if (hostnameVerifier == null) {
184 hostnameVerifier = NoopHostnameVerifier.INSTANCE;
185 }
186 } else {
187 throw new IllegalArgumentException(
188 "Unsupported '" + sslConfig.httpsSecurityMode + "' HTTPS security mode.");
189 }
190
191 registryBuilder.register(
192 "https",
193 new SSLConnectionSocketFactory(
194 sslSocketFactory, sslConfig.protocols, sslConfig.cipherSuites, hostnameVerifier));
195 }
196
197 PoolingHttpClientConnectionManager connMgr = new PoolingHttpClientConnectionManager(registryBuilder.build());
198 connMgr.setMaxTotal(100);
199 connMgr.setDefaultMaxPerRoute(50);
200 return connMgr;
201 }
202
203 public Object getUserToken(CompoundKey key) {
204 return userTokens.get(key);
205 }
206
207 public void setUserToken(CompoundKey key, Object userToken) {
208 if (userToken != null) {
209 userTokens.put(key, userToken);
210 } else {
211 userTokens.remove(key);
212 }
213 }
214
215 public ConcurrentMap<HttpHost, AuthSchemePool> getAuthSchemePools() {
216 return authSchemePools;
217 }
218
219 public Boolean getExpectContinue(CompoundKey key) {
220 return expectContinues.get(key);
221 }
222
223 public void setExpectContinue(CompoundKey key, boolean enabled) {
224 expectContinues.put(key, enabled);
225 }
226 }