32 import java.net.URL;
33 import java.security.AccessController;
34 import java.security.PrivilegedAction;
35 import java.util.ArrayDeque;
36 import java.util.ArrayList;
37 import java.util.HashMap;
38 import java.util.List;
39
40 import jdk.internal.misc.InnocuousThread;
41 import sun.security.action.GetIntegerAction;
42
43 /**
44 * A class that implements a cache of idle Http connections for keep-alive
45 *
46 * @author Stephen R. Pietrowicz (NCSA)
47 * @author Dave Brown
48 */
49 public class KeepAliveCache
50 extends HashMap<KeepAliveKey, ClientVector>
51 implements Runnable {
52 private static final long serialVersionUID = -2937172892064557949L;
53
54 /* maximum # keep-alive connections to maintain at once
55 * This should be 2 by the HTTP spec, but because we don't support pipe-lining
56 * a larger value is more appropriate. So we now set a default of 5, and the value
57 * refers to the number of idle connections per destination (in the cache) only.
58 * It can be reset by setting system property "http.maxConnections".
59 */
60 static final int MAX_CONNECTIONS = 5;
61 static int result = -1;
62 static int getMaxConnections() {
63 if (result == -1) {
64 result = AccessController.doPrivileged(
65 new GetIntegerAction("http.maxConnections", MAX_CONNECTIONS))
66 .intValue();
67 if (result <= 0) {
68 result = MAX_CONNECTIONS;
69 }
70 }
71 return result;
186 }
187 e = v.peek();
188 }
189
190 if (v.isEmpty()) {
191 keysToRemove.add(key);
192 }
193 }
194 }
195
196 for (KeepAliveKey key : keysToRemove) {
197 removeVector(key);
198 }
199 }
200 } while (!isEmpty());
201 }
202
203 /*
204 * Do not serialize this class!
205 */
206 private void writeObject(ObjectOutputStream stream) throws IOException {
207 throw new NotSerializableException();
208 }
209
210 private void readObject(ObjectInputStream stream)
211 throws IOException, ClassNotFoundException
212 {
213 throw new NotSerializableException();
214 }
215 }
216
217 /* FILO order for recycling HttpClients, should run in a thread
218 * to time them out. If > maxConns are in use, block.
219 */
220 class ClientVector extends ArrayDeque<KeepAliveEntry> {
221 private static final long serialVersionUID = -8680532108106489459L;
222
223 // sleep time in milliseconds, before cache clear
224 int nap;
225
226 ClientVector(int nap) {
227 this.nap = nap;
228 }
229
230 synchronized HttpClient get() {
231 if (isEmpty()) {
232 return null;
233 }
234
235 // Loop until we find a connection that has not timed out
236 HttpClient hc = null;
237 long currentTime = System.currentTimeMillis();
238 do {
239 KeepAliveEntry e = pop();
240 if ((currentTime - e.idleStartTime) > nap) {
251 if (size() >= KeepAliveCache.getMaxConnections()) {
252 h.closeServer(); // otherwise the connection remains in limbo
253 } else {
254 push(new KeepAliveEntry(h, System.currentTimeMillis()));
255 }
256 }
257
258 /* remove an HttpClient */
259 synchronized boolean remove(HttpClient h) {
260 for (KeepAliveEntry curr : this) {
261 if (curr.hc == h) {
262 return super.remove(curr);
263 }
264 }
265 return false;
266 }
267
268 /*
269 * Do not serialize this class!
270 */
271 private void writeObject(ObjectOutputStream stream) throws IOException {
272 throw new NotSerializableException();
273 }
274
275 private void readObject(ObjectInputStream stream)
276 throws IOException, ClassNotFoundException
277 {
278 throw new NotSerializableException();
279 }
280 }
281
282 class KeepAliveKey {
283 private String protocol = null;
284 private String host = null;
285 private int port = 0;
286 private Object obj = null; // additional key, such as socketfactory
287
288 /**
289 * Constructor
290 *
291 * @param url the URL containing the protocol, host and port information
292 */
293 public KeepAliveKey(URL url, Object obj) {
294 this.protocol = url.getProtocol();
|
32 import java.net.URL;
33 import java.security.AccessController;
34 import java.security.PrivilegedAction;
35 import java.util.ArrayDeque;
36 import java.util.ArrayList;
37 import java.util.HashMap;
38 import java.util.List;
39
40 import jdk.internal.misc.InnocuousThread;
41 import sun.security.action.GetIntegerAction;
42
43 /**
44 * A class that implements a cache of idle Http connections for keep-alive
45 *
46 * @author Stephen R. Pietrowicz (NCSA)
47 * @author Dave Brown
48 */
49 public class KeepAliveCache
50 extends HashMap<KeepAliveKey, ClientVector>
51 implements Runnable {
52 @java.io.Serial
53 private static final long serialVersionUID = -2937172892064557949L;
54
55 /* maximum # keep-alive connections to maintain at once
56 * This should be 2 by the HTTP spec, but because we don't support pipe-lining
57 * a larger value is more appropriate. So we now set a default of 5, and the value
58 * refers to the number of idle connections per destination (in the cache) only.
59 * It can be reset by setting system property "http.maxConnections".
60 */
61 static final int MAX_CONNECTIONS = 5;
62 static int result = -1;
63 static int getMaxConnections() {
64 if (result == -1) {
65 result = AccessController.doPrivileged(
66 new GetIntegerAction("http.maxConnections", MAX_CONNECTIONS))
67 .intValue();
68 if (result <= 0) {
69 result = MAX_CONNECTIONS;
70 }
71 }
72 return result;
187 }
188 e = v.peek();
189 }
190
191 if (v.isEmpty()) {
192 keysToRemove.add(key);
193 }
194 }
195 }
196
197 for (KeepAliveKey key : keysToRemove) {
198 removeVector(key);
199 }
200 }
201 } while (!isEmpty());
202 }
203
204 /*
205 * Do not serialize this class!
206 */
207 @java.io.Serial
208 private void writeObject(ObjectOutputStream stream) throws IOException {
209 throw new NotSerializableException();
210 }
211
212 @java.io.Serial
213 private void readObject(ObjectInputStream stream)
214 throws IOException, ClassNotFoundException
215 {
216 throw new NotSerializableException();
217 }
218 }
219
220 /* FILO order for recycling HttpClients, should run in a thread
221 * to time them out. If > maxConns are in use, block.
222 */
223 class ClientVector extends ArrayDeque<KeepAliveEntry> {
224 @java.io.Serial
225 private static final long serialVersionUID = -8680532108106489459L;
226
227 // sleep time in milliseconds, before cache clear
228 int nap;
229
230 ClientVector(int nap) {
231 this.nap = nap;
232 }
233
234 synchronized HttpClient get() {
235 if (isEmpty()) {
236 return null;
237 }
238
239 // Loop until we find a connection that has not timed out
240 HttpClient hc = null;
241 long currentTime = System.currentTimeMillis();
242 do {
243 KeepAliveEntry e = pop();
244 if ((currentTime - e.idleStartTime) > nap) {
255 if (size() >= KeepAliveCache.getMaxConnections()) {
256 h.closeServer(); // otherwise the connection remains in limbo
257 } else {
258 push(new KeepAliveEntry(h, System.currentTimeMillis()));
259 }
260 }
261
262 /* remove an HttpClient */
263 synchronized boolean remove(HttpClient h) {
264 for (KeepAliveEntry curr : this) {
265 if (curr.hc == h) {
266 return super.remove(curr);
267 }
268 }
269 return false;
270 }
271
272 /*
273 * Do not serialize this class!
274 */
275 @java.io.Serial
276 private void writeObject(ObjectOutputStream stream) throws IOException {
277 throw new NotSerializableException();
278 }
279
280 @java.io.Serial
281 private void readObject(ObjectInputStream stream)
282 throws IOException, ClassNotFoundException
283 {
284 throw new NotSerializableException();
285 }
286 }
287
288 class KeepAliveKey {
289 private String protocol = null;
290 private String host = null;
291 private int port = 0;
292 private Object obj = null; // additional key, such as socketfactory
293
294 /**
295 * Constructor
296 *
297 * @param url the URL containing the protocol, host and port information
298 */
299 public KeepAliveKey(URL url, Object obj) {
300 this.protocol = url.getProtocol();
|