Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/share/classes/sun/net/www/http/KeepAliveCache.java
41161 views
1
/*
2
* Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package sun.net.www.http;
27
28
import java.io.IOException;
29
import java.io.NotSerializableException;
30
import java.io.ObjectInputStream;
31
import java.io.ObjectOutputStream;
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
import java.util.concurrent.locks.Lock;
40
import java.util.concurrent.locks.ReentrantLock;
41
42
import jdk.internal.misc.InnocuousThread;
43
import sun.security.action.GetIntegerAction;
44
45
/**
46
* A class that implements a cache of idle Http connections for keep-alive
47
*
48
* @author Stephen R. Pietrowicz (NCSA)
49
* @author Dave Brown
50
*/
51
public class KeepAliveCache
52
extends HashMap<KeepAliveKey, ClientVector>
53
implements Runnable {
54
@java.io.Serial
55
private static final long serialVersionUID = -2937172892064557949L;
56
57
/* maximum # keep-alive connections to maintain at once
58
* This should be 2 by the HTTP spec, but because we don't support pipe-lining
59
* a larger value is more appropriate. So we now set a default of 5, and the value
60
* refers to the number of idle connections per destination (in the cache) only.
61
* It can be reset by setting system property "http.maxConnections".
62
*/
63
static final int MAX_CONNECTIONS = 5;
64
static int result = -1;
65
@SuppressWarnings("removal")
66
static int getMaxConnections() {
67
if (result == -1) {
68
result = AccessController.doPrivileged(
69
new GetIntegerAction("http.maxConnections", MAX_CONNECTIONS))
70
.intValue();
71
if (result <= 0) {
72
result = MAX_CONNECTIONS;
73
}
74
}
75
return result;
76
}
77
78
static final int LIFETIME = 5000;
79
80
// This class is never serialized (see writeObject/readObject).
81
private final ReentrantLock cacheLock = new ReentrantLock();
82
private Thread keepAliveTimer = null;
83
84
/**
85
* Constructor
86
*/
87
public KeepAliveCache() {}
88
89
/**
90
* Register this URL and HttpClient (that supports keep-alive) with the cache
91
* @param url The URL contains info about the host and port
92
* @param http The HttpClient to be cached
93
*/
94
@SuppressWarnings("removal")
95
public void put(final URL url, Object obj, HttpClient http) {
96
cacheLock.lock();
97
try {
98
boolean startThread = (keepAliveTimer == null);
99
if (!startThread) {
100
if (!keepAliveTimer.isAlive()) {
101
startThread = true;
102
}
103
}
104
if (startThread) {
105
clear();
106
/* Unfortunately, we can't always believe the keep-alive timeout we got
107
* back from the server. If I'm connected through a Netscape proxy
108
* to a server that sent me a keep-alive
109
* time of 15 sec, the proxy unilaterally terminates my connection
110
* The robustness to get around this is in HttpClient.parseHTTP()
111
*/
112
final KeepAliveCache cache = this;
113
AccessController.doPrivileged(new PrivilegedAction<>() {
114
public Void run() {
115
keepAliveTimer = InnocuousThread.newSystemThread("Keep-Alive-Timer", cache);
116
keepAliveTimer.setDaemon(true);
117
keepAliveTimer.setPriority(Thread.MAX_PRIORITY - 2);
118
keepAliveTimer.start();
119
return null;
120
}
121
});
122
}
123
124
KeepAliveKey key = new KeepAliveKey(url, obj);
125
ClientVector v = super.get(key);
126
127
if (v == null) {
128
int keepAliveTimeout = http.getKeepAliveTimeout();
129
v = new ClientVector(keepAliveTimeout > 0 ?
130
keepAliveTimeout * 1000 : LIFETIME);
131
v.put(http);
132
super.put(key, v);
133
} else {
134
v.put(http);
135
}
136
} finally {
137
cacheLock.unlock();
138
}
139
}
140
141
/* remove an obsolete HttpClient from its VectorCache */
142
public void remove(HttpClient h, Object obj) {
143
cacheLock.lock();
144
try {
145
KeepAliveKey key = new KeepAliveKey(h.url, obj);
146
ClientVector v = super.get(key);
147
if (v != null) {
148
v.remove(h);
149
if (v.isEmpty()) {
150
removeVector(key);
151
}
152
}
153
} finally {
154
cacheLock.unlock();
155
}
156
}
157
158
/* called by a clientVector thread when all its connections have timed out
159
* and that vector of connections should be removed.
160
*/
161
private void removeVector(KeepAliveKey k) {
162
assert cacheLock.isHeldByCurrentThread();
163
super.remove(k);
164
}
165
166
/**
167
* Check to see if this URL has a cached HttpClient
168
*/
169
public HttpClient get(URL url, Object obj) {
170
cacheLock.lock();
171
try {
172
KeepAliveKey key = new KeepAliveKey(url, obj);
173
ClientVector v = super.get(key);
174
if (v == null) { // nothing in cache yet
175
return null;
176
}
177
return v.get();
178
} finally {
179
cacheLock.unlock();
180
}
181
}
182
183
/* Sleeps for an alloted timeout, then checks for timed out connections.
184
* Errs on the side of caution (leave connections idle for a relatively
185
* short time).
186
*/
187
@Override
188
public void run() {
189
do {
190
try {
191
Thread.sleep(LIFETIME);
192
} catch (InterruptedException e) {}
193
194
// Remove all outdated HttpClients.
195
cacheLock.lock();
196
try {
197
long currentTime = System.currentTimeMillis();
198
List<KeepAliveKey> keysToRemove = new ArrayList<>();
199
200
for (KeepAliveKey key : keySet()) {
201
ClientVector v = get(key);
202
v.lock();
203
try {
204
KeepAliveEntry e = v.peek();
205
while (e != null) {
206
if ((currentTime - e.idleStartTime) > v.nap) {
207
v.poll();
208
e.hc.closeServer();
209
} else {
210
break;
211
}
212
e = v.peek();
213
}
214
215
if (v.isEmpty()) {
216
keysToRemove.add(key);
217
}
218
} finally {
219
v.unlock();
220
}
221
}
222
223
for (KeepAliveKey key : keysToRemove) {
224
removeVector(key);
225
}
226
} finally {
227
cacheLock.unlock();
228
}
229
} while (!isEmpty());
230
}
231
232
/*
233
* Do not serialize this class!
234
*/
235
@java.io.Serial
236
private void writeObject(ObjectOutputStream stream) throws IOException {
237
throw new NotSerializableException();
238
}
239
240
@java.io.Serial
241
private void readObject(ObjectInputStream stream)
242
throws IOException, ClassNotFoundException
243
{
244
throw new NotSerializableException();
245
}
246
}
247
248
/* FILO order for recycling HttpClients, should run in a thread
249
* to time them out. If > maxConns are in use, block.
250
*/
251
class ClientVector extends ArrayDeque<KeepAliveEntry> {
252
@java.io.Serial
253
private static final long serialVersionUID = -8680532108106489459L;
254
private final ReentrantLock lock = new ReentrantLock();
255
256
// sleep time in milliseconds, before cache clear
257
int nap;
258
259
ClientVector(int nap) {
260
this.nap = nap;
261
}
262
263
HttpClient get() {
264
lock();
265
try {
266
if (isEmpty()) {
267
return null;
268
}
269
270
// Loop until we find a connection that has not timed out
271
HttpClient hc = null;
272
long currentTime = System.currentTimeMillis();
273
do {
274
KeepAliveEntry e = pop();
275
if ((currentTime - e.idleStartTime) > nap) {
276
e.hc.closeServer();
277
} else {
278
hc = e.hc;
279
}
280
} while ((hc == null) && (!isEmpty()));
281
return hc;
282
} finally {
283
unlock();
284
}
285
}
286
287
/* return a still valid, unused HttpClient */
288
void put(HttpClient h) {
289
lock();
290
try {
291
if (size() >= KeepAliveCache.getMaxConnections()) {
292
h.closeServer(); // otherwise the connection remains in limbo
293
} else {
294
push(new KeepAliveEntry(h, System.currentTimeMillis()));
295
}
296
} finally {
297
unlock();
298
}
299
}
300
301
/* remove an HttpClient */
302
boolean remove(HttpClient h) {
303
lock();
304
try {
305
for (KeepAliveEntry curr : this) {
306
if (curr.hc == h) {
307
return super.remove(curr);
308
}
309
}
310
return false;
311
} finally {
312
unlock();
313
}
314
}
315
316
final void lock() {
317
lock.lock();
318
}
319
320
final void unlock() {
321
lock.unlock();
322
}
323
324
/*
325
* Do not serialize this class!
326
*/
327
@java.io.Serial
328
private void writeObject(ObjectOutputStream stream) throws IOException {
329
throw new NotSerializableException();
330
}
331
332
@java.io.Serial
333
private void readObject(ObjectInputStream stream)
334
throws IOException, ClassNotFoundException
335
{
336
throw new NotSerializableException();
337
}
338
}
339
340
class KeepAliveKey {
341
private String protocol = null;
342
private String host = null;
343
private int port = 0;
344
private Object obj = null; // additional key, such as socketfactory
345
346
/**
347
* Constructor
348
*
349
* @param url the URL containing the protocol, host and port information
350
*/
351
public KeepAliveKey(URL url, Object obj) {
352
this.protocol = url.getProtocol();
353
this.host = url.getHost();
354
this.port = url.getPort();
355
this.obj = obj;
356
}
357
358
/**
359
* Determine whether or not two objects of this type are equal
360
*/
361
@Override
362
public boolean equals(Object obj) {
363
if ((obj instanceof KeepAliveKey) == false)
364
return false;
365
KeepAliveKey kae = (KeepAliveKey)obj;
366
return host.equals(kae.host)
367
&& (port == kae.port)
368
&& protocol.equals(kae.protocol)
369
&& this.obj == kae.obj;
370
}
371
372
/**
373
* The hashCode() for this object is the string hashCode() of
374
* concatenation of the protocol, host name and port.
375
*/
376
@Override
377
public int hashCode() {
378
String str = protocol+host+port;
379
return this.obj == null? str.hashCode() :
380
str.hashCode() + this.obj.hashCode();
381
}
382
}
383
384
class KeepAliveEntry {
385
HttpClient hc;
386
long idleStartTime;
387
388
KeepAliveEntry(HttpClient hc, long idleStartTime) {
389
this.hc = hc;
390
this.idleStartTime = idleStartTime;
391
}
392
}
393
394