Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/jdk/sun/net/www/http/HttpClient/MultiThreadTest.java
41155 views
1
/*
2
* Copyright (c) 2002, 2019, 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.
8
*
9
* This code is distributed in the hope that it will be useful, but WITHOUT
10
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12
* version 2 for more details (a copy is included in the LICENSE file that
13
* accompanied this code).
14
*
15
* You should have received a copy of the GNU General Public License version
16
* 2 along with this work; if not, write to the Free Software Foundation,
17
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18
*
19
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20
* or visit www.oracle.com if you need additional information or have any
21
* questions.
22
*/
23
24
/*
25
* @test
26
* @bug 4636628
27
* @summary HttpURLConnection duplicates HTTP GET requests when used with multiple threads
28
*/
29
30
/*
31
* This tests keep-alive behavior using chunkedinputstreams
32
* It checks that keep-alive connections are used and also
33
* that requests are not being repeated (due to errors)
34
*
35
* It also checks that the keepalive connections are closed eventually
36
* because the test will not terminate if the connections
37
* are not closed by the keep-alive timer.
38
*/
39
40
import java.net.*;
41
import java.io.*;
42
import java.time.Duration;
43
import java.util.Queue;
44
import java.util.concurrent.ConcurrentLinkedQueue;
45
import java.util.concurrent.atomic.AtomicInteger;
46
47
public class MultiThreadTest extends Thread {
48
49
/*
50
* Is debugging enabled - start with -d to enable.
51
*/
52
static boolean debug = true; // disable debug once stability proven
53
54
static Object threadlock = new Object ();
55
static int threadCounter = 0;
56
57
static Object getLock() { return threadlock; }
58
59
static void debug(String msg) {
60
if (debug)
61
System.out.println(msg);
62
}
63
64
static final AtomicInteger reqnum = new AtomicInteger();
65
66
void doRequest(String uri) throws Exception {
67
URL url = new URL(uri + "?foo="+reqnum.getAndIncrement());
68
HttpURLConnection http = (HttpURLConnection)url.openConnection();
69
InputStream in = http.getInputStream();
70
byte b[] = new byte[100];
71
int total = 0;
72
int n;
73
do {
74
n = in.read(b);
75
if (n > 0) total += n;
76
} while (n > 0);
77
debug ("client: read " + total + " bytes");
78
in.close();
79
http.disconnect();
80
}
81
82
String uri;
83
byte[] b;
84
int requests;
85
86
MultiThreadTest(String authority, int requests) throws Exception {
87
uri = "http://" + authority + "/foo.html";
88
89
b = new byte [256];
90
this.requests = requests;
91
92
synchronized (threadlock) {
93
threadCounter ++;
94
}
95
}
96
97
public void run() {
98
long start = System.nanoTime();
99
100
try {
101
for (int i=0; i<requests; i++) {
102
doRequest (uri);
103
}
104
} catch (Exception e) {
105
throw new RuntimeException (e.getMessage());
106
} finally {
107
synchronized (threadlock) {
108
threadCounter --;
109
if (threadCounter == 0) {
110
threadlock.notifyAll();
111
}
112
}
113
}
114
debug("client: end - " + Duration.ofNanos(System.nanoTime() - start));
115
}
116
117
static int threads=5;
118
119
public static void main(String args[]) throws Exception {
120
long start = System.nanoTime();
121
122
int x = 0, arg_len = args.length;
123
int requests = 20;
124
125
if (arg_len > 0 && args[0].equals("-d")) {
126
debug = true;
127
x = 1;
128
arg_len --;
129
}
130
if (arg_len > 0) {
131
threads = Integer.parseInt (args[x]);
132
requests = Integer.parseInt (args[x+1]);
133
}
134
135
/* start the server */
136
InetAddress loopback = InetAddress.getLoopbackAddress();
137
ServerSocket ss = new ServerSocket();
138
ss.bind(new InetSocketAddress(loopback, 0));
139
Server svr = new Server(ss);
140
svr.start();
141
142
Object lock = MultiThreadTest.getLock();
143
synchronized (lock) {
144
for (int i=0; i<threads; i++) {
145
MultiThreadTest t = new MultiThreadTest(svr.getAuthority(), requests);
146
t.start ();
147
}
148
try {
149
lock.wait();
150
} catch (InterruptedException e) {}
151
}
152
153
// shutdown server - we're done.
154
svr.shutdown();
155
156
int cnt = svr.connectionCount();
157
MultiThreadTest.debug("Connections = " + cnt);
158
int reqs = Worker.getRequests ();
159
MultiThreadTest.debug("Requests = " + reqs);
160
System.out.println ("Connection count = " + cnt + " Request count = " + reqs);
161
162
// We may have received traffic from something else than
163
// our client. We should only count those workers for which
164
// the expected header has been found.
165
int validConnections = 0;
166
for (Worker w : svr.workers()) {
167
if (w.headerFound) validConnections++;
168
}
169
170
if (validConnections > threads + 1 || validConnections == 0) { // could be less
171
throw new RuntimeException ("Expected " + threads + " connections: used " + validConnections);
172
}
173
174
// Sometimes the client drops a connection after a while and
175
// spawns a new one. Why this is happening is not clear,
176
// and JDK-8223783 is logged to follow up on this. For the sake
177
// of test stabilization we don't fail on `threads + 1` connections
178
// but log a warning instead.
179
if (validConnections == threads + 1) {
180
debug("WARNING: " + validConnections
181
+ " have been used, where only " + threads
182
+ " were expected!");
183
}
184
185
if (validConnections != cnt) {
186
debug("WARNING: got " + (cnt - validConnections) + " unexpected connections!");
187
}
188
if (validConnections == cnt && reqs != threads*requests) {
189
throw new RuntimeException ("Expected "+ threads*requests+ " requests: got " +reqs);
190
}
191
192
for (Thread worker : svr.workers()) {
193
worker.join(60_000);
194
}
195
196
debug("main thread end - " + Duration.ofNanos(System.nanoTime() - start));
197
}
198
}
199
200
/*
201
* Server thread to accept connection and create worker threads
202
* to service each connection.
203
*/
204
class Server extends Thread {
205
ServerSocket ss;
206
int connectionCount;
207
boolean shutdown = false;
208
private final Queue<Worker> workers = new ConcurrentLinkedQueue<>();
209
210
Server(ServerSocket ss) {
211
this.ss = ss;
212
}
213
214
public String getAuthority() {
215
InetAddress address = ss.getInetAddress();
216
String hostaddr = address.isAnyLocalAddress()
217
? "localhost" : address.getHostAddress();
218
if (hostaddr.indexOf(':') > -1) {
219
hostaddr = "[" + hostaddr + "]";
220
}
221
return hostaddr + ":" + ss.getLocalPort();
222
}
223
224
public Queue<Worker> workers() {
225
return workers;
226
}
227
228
public synchronized int connectionCount() {
229
return connectionCount;
230
}
231
232
public synchronized void shutdown() {
233
shutdown = true;
234
}
235
236
public void run() {
237
try {
238
ss.setSoTimeout(2000);
239
240
for (;;) {
241
Socket s;
242
try {
243
MultiThreadTest.debug("server: calling accept.");
244
s = ss.accept();
245
MultiThreadTest.debug("server: return accept.");
246
} catch (SocketTimeoutException te) {
247
MultiThreadTest.debug("server: STE");
248
synchronized (this) {
249
if (shutdown) {
250
MultiThreadTest.debug("server: Shuting down.");
251
return;
252
}
253
}
254
continue;
255
}
256
257
int id;
258
Worker w;
259
synchronized (this) {
260
id = connectionCount++;
261
w = new Worker(s, id);
262
workers.add(w);
263
}
264
w.start();
265
MultiThreadTest.debug("server: Started worker " + id);
266
}
267
268
} catch (Exception e) {
269
e.printStackTrace();
270
} finally {
271
try {
272
ss.close();
273
} catch (Exception e) { }
274
}
275
}
276
}
277
278
/*
279
* Worker thread to service single connection - can service
280
* multiple http requests on same connection.
281
*/
282
class Worker extends Thread {
283
Socket s;
284
int id;
285
volatile boolean headerFound;
286
287
Worker(Socket s, int id) {
288
super("Worker-" + id);
289
this.s = s;
290
this.id = id;
291
}
292
293
static int requests = 0;
294
static final Object rlock = new Object();
295
296
public static int getRequests () {
297
synchronized (rlock) {
298
return requests;
299
}
300
}
301
302
public static void incRequests () {
303
synchronized (rlock) {
304
requests++;
305
}
306
}
307
308
int readUntil(InputStream in, StringBuilder headers, char[] seq) throws IOException {
309
int i=0, count=0;
310
while (true) {
311
int c = in.read();
312
if (c == -1)
313
return -1;
314
headers.append((char)c);
315
count++;
316
if (c == seq[i]) {
317
i++;
318
if (i == seq.length)
319
return count;
320
continue;
321
} else {
322
i = 0;
323
}
324
}
325
}
326
327
public void run() {
328
long start = System.nanoTime();
329
330
try {
331
int max = 400;
332
byte b[] = new byte[1000];
333
InputStream in = new BufferedInputStream(s.getInputStream());
334
// response to client
335
PrintStream out = new PrintStream(
336
new BufferedOutputStream(
337
s.getOutputStream() ));
338
339
for (;;) {
340
341
// read entire request from client
342
int n=0;
343
StringBuilder headers = new StringBuilder();
344
n = readUntil(in, headers, new char[] {'\r','\n', '\r','\n'});
345
if (n <= 0) {
346
MultiThreadTest.debug("worker: " + id + ": Shutdown");
347
s.close();
348
return;
349
}
350
if (headers.toString().contains("/foo.html?foo=")) {
351
headerFound = true;
352
} else {
353
MultiThreadTest.debug("worker: " + id + ": Unexpected request received: " + headers);
354
}
355
356
MultiThreadTest.debug("worker " + id +
357
": Read request from client " +
358
"(" + n + " bytes).");
359
360
incRequests();
361
out.print("HTTP/1.1 200 OK\r\n");
362
out.print("Transfer-Encoding: chunked\r\n");
363
out.print("Content-Type: text/html\r\n");
364
out.print("Connection: Keep-Alive\r\n");
365
out.print("Keep-Alive: timeout=15, max="+max+"\r\n");
366
out.print("\r\n");
367
out.print("6\r\nHello \r\n");
368
out.print("5\r\nWorld\r\n");
369
out.print("0\r\n\r\n");
370
out.flush();
371
372
if (--max == 0) {
373
s.close();
374
return;
375
}
376
}
377
378
} catch (Exception e) {
379
e.printStackTrace();
380
} finally {
381
try {
382
s.close();
383
} catch (Exception e) { }
384
MultiThreadTest.debug("worker: " + id + " end - " +
385
Duration.ofNanos(System.nanoTime() - start));
386
}
387
}
388
}
389
390