Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/jdk/sun/net/www/http/KeepAliveCache/B5045306.java
41155 views
1
/*
2
* Copyright (c) 2005, 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 5045306 6356004 6993490 8255124
27
* @modules java.base/sun.net.www
28
* java.management
29
* @library ../../httptest/
30
* @build HttpCallback TestHttpServer HttpTransaction
31
* @run main/othervm B5045306
32
* @summary Http keep-alive implementation is not efficient
33
*/
34
35
import java.net.*;
36
import java.io.*;
37
import java.lang.management.*;
38
import java.util.ArrayList;
39
import java.util.List;
40
41
/* Part 1:
42
* The http client makes a connection to a URL whos content contains a lot of
43
* data, more than can fit in the socket buffer. The client only reads
44
* 1 byte of the data from the InputStream leaving behind more data than can
45
* fit in the socket buffer. The client then makes a second call to the http
46
* server. If the connection port used by the client is the same as for the
47
* first call then that means that the connection is being reused.
48
*
49
* Part 2:
50
* Test buggy webserver that sends less data than it specifies in its
51
* Content-length header.
52
*/
53
54
public class B5045306
55
{
56
static SimpleHttpTransaction httpTrans;
57
static TestHttpServer server;
58
59
public static void main(String[] args) throws Exception {
60
startHttpServer();
61
clientHttpCalls();
62
}
63
64
public static void startHttpServer() {
65
try {
66
httpTrans = new SimpleHttpTransaction();
67
server = new TestHttpServer(httpTrans, 1, 10, InetAddress.getLocalHost(), 0);
68
} catch (IOException e) {
69
e.printStackTrace();
70
}
71
}
72
73
public static void clientHttpCalls() {
74
List<Throwable> uncaught = new ArrayList<>();
75
Thread.setDefaultUncaughtExceptionHandler((t, ex) -> {
76
uncaught.add(ex);
77
});
78
try {
79
System.out.println("http server listen on: " + server.getLocalPort());
80
String hostAddr = InetAddress.getLocalHost().getHostAddress();
81
if (hostAddr.indexOf(':') > -1) hostAddr = "[" + hostAddr + "]";
82
String baseURLStr = "http://" + hostAddr + ":" + server.getLocalPort() + "/";
83
84
URL bigDataURL = new URL (baseURLStr + "firstCall");
85
URL smallDataURL = new URL (baseURLStr + "secondCall");
86
87
HttpURLConnection uc = (HttpURLConnection)bigDataURL.openConnection(Proxy.NO_PROXY);
88
89
//Only read 1 byte of response data and close the stream
90
InputStream is = uc.getInputStream();
91
byte[] ba = new byte[1];
92
is.read(ba);
93
is.close();
94
95
// Allow the KeepAliveStreamCleaner thread to read the data left behind and cache the connection.
96
try { Thread.sleep(2000); } catch (Exception e) {}
97
98
uc = (HttpURLConnection)smallDataURL.openConnection(Proxy.NO_PROXY);
99
uc.getResponseCode();
100
101
if (SimpleHttpTransaction.failed)
102
throw new RuntimeException("Failed: Initial Keep Alive Connection is not being reused");
103
104
// Part 2
105
URL part2Url = new URL (baseURLStr + "part2");
106
uc = (HttpURLConnection)part2Url.openConnection(Proxy.NO_PROXY);
107
is = uc.getInputStream();
108
is.close();
109
110
// Allow the KeepAliveStreamCleaner thread to try and read the data left behind and cache the connection.
111
try { Thread.sleep(2000); } catch (Exception e) {}
112
113
ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
114
if (threadMXBean.isThreadCpuTimeSupported()) {
115
long[] threads = threadMXBean.getAllThreadIds();
116
ThreadInfo[] threadInfo = threadMXBean.getThreadInfo(threads);
117
for (int i=0; i<threadInfo.length; i++) {
118
if (threadInfo[i].getThreadName().equals("Keep-Alive-SocketCleaner")) {
119
System.out.println("Found Keep-Alive-SocketCleaner thread");
120
long threadID = threadInfo[i].getThreadId();
121
long before = threadMXBean.getThreadCpuTime(threadID);
122
try { Thread.sleep(2000); } catch (Exception e) {}
123
long after = threadMXBean.getThreadCpuTime(threadID);
124
125
if (before ==-1 || after == -1)
126
break; // thread has died, OK
127
128
// if Keep-Alive-SocketCleaner consumes more than 50% of cpu then we
129
// can assume a recursive loop.
130
long total = after - before;
131
if (total >= 1000000000) // 1 second, or 1 billion nanoseconds
132
throw new RuntimeException("Failed: possible recursive loop in Keep-Alive-SocketCleaner");
133
}
134
}
135
}
136
137
} catch (IOException e) {
138
e.printStackTrace();
139
} finally {
140
server.terminate();
141
}
142
if (!uncaught.isEmpty()) {
143
throw new RuntimeException("Unhandled exception:", uncaught.get(0));
144
}
145
}
146
}
147
148
class SimpleHttpTransaction implements HttpCallback
149
{
150
static boolean failed = false;
151
152
// Need to have enough data here that is too large for the socket buffer to hold.
153
// Also http.KeepAlive.remainingData must be greater than this value, default is 256K.
154
static final int RESPONSE_DATA_LENGTH = 128 * 1024;
155
156
int port1;
157
158
public void request(HttpTransaction trans) {
159
try {
160
String path = trans.getRequestURI().getPath();
161
if (path.equals("/firstCall")) {
162
port1 = trans.channel().socket().getPort();
163
System.out.println("First connection on client port = " + port1);
164
165
byte[] responseBody = new byte[RESPONSE_DATA_LENGTH];
166
for (int i=0; i<responseBody.length; i++)
167
responseBody[i] = 0x41;
168
trans.setResponseEntityBody (responseBody, responseBody.length);
169
trans.sendResponse(200, "OK");
170
} else if (path.equals("/secondCall")) {
171
int port2 = trans.channel().socket().getPort();
172
System.out.println("Second connection on client port = " + port2);
173
174
if (port1 != port2)
175
failed = true;
176
177
trans.setResponseHeader ("Content-length", Integer.toString(0));
178
179
/* Force the server to not respond for more that the timeout
180
* set by the keepalive cleaner (5000 millis). This ensures the
181
* timeout is correctly resets the default read timeout,
182
* infinity. See 6993490. */
183
System.out.println("server sleeping...");
184
try {Thread.sleep(6000); } catch (InterruptedException e) {}
185
186
trans.sendResponse(200, "OK");
187
} else if(path.equals("/part2")) {
188
System.out.println("Call to /part2");
189
byte[] responseBody = new byte[RESPONSE_DATA_LENGTH];
190
for (int i=0; i<responseBody.length; i++)
191
responseBody[i] = 0x41;
192
trans.setResponseEntityBody (responseBody, responseBody.length);
193
194
// override the Content-length header to be greater than the actual response body
195
trans.setResponseHeader("Content-length", Integer.toString(responseBody.length+1));
196
trans.sendResponse(200, "OK");
197
198
// now close the socket
199
trans.channel().socket().close();
200
}
201
} catch (Exception e) {
202
e.printStackTrace();
203
}
204
}
205
}
206
207