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