Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/jdk/java/net/httpclient/CancelledResponse.java
41149 views
1
/*
2
* Copyright (c) 2015, 2018, 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
import java.net.http.HttpClient;
25
import java.net.http.HttpClient.Version;
26
import java.net.http.HttpHeaders;
27
import java.net.http.HttpRequest;
28
import java.net.http.HttpResponse;
29
import jdk.test.lib.net.SimpleSSLContext;
30
31
import javax.net.ServerSocketFactory;
32
import javax.net.ssl.SSLContext;
33
import javax.net.ssl.SSLException;
34
import javax.net.ssl.SSLServerSocketFactory;
35
import java.io.IOException;
36
import java.net.SocketException;
37
import java.net.URI;
38
import java.nio.ByteBuffer;
39
import java.util.List;
40
import java.util.concurrent.CompletableFuture;
41
import java.util.concurrent.CompletionException;
42
import java.util.concurrent.CompletionStage;
43
import java.util.concurrent.ExecutionException;
44
import java.util.concurrent.Flow;
45
import java.util.concurrent.atomic.AtomicBoolean;
46
import java.util.concurrent.atomic.AtomicInteger;
47
48
import java.net.http.HttpResponse.BodyHandler;
49
import java.net.http.HttpResponse.BodySubscriber;
50
51
import static java.lang.String.format;
52
import static java.lang.System.out;
53
import static java.nio.charset.StandardCharsets.ISO_8859_1;
54
55
/**
56
* @test
57
* @bug 8087112
58
* @library /test/lib
59
* @modules java.net.http/jdk.internal.net.http.common
60
* @build jdk.test.lib.net.SimpleSSLContext
61
* @build MockServer ReferenceTracker
62
* @run main/othervm CancelledResponse
63
* @run main/othervm CancelledResponse SSL
64
*/
65
66
/**
67
* Similar test to SplitResponse except that the client will cancel the response
68
* before receiving it fully.
69
*/
70
public class CancelledResponse {
71
72
static String response(String body, boolean serverKeepalive) {
73
StringBuilder sb = new StringBuilder();
74
sb.append("HTTP/1.1 200 OK\r\n");
75
if (!serverKeepalive)
76
sb.append("Connection: Close\r\n");
77
78
sb.append("Content-length: ")
79
.append(body.getBytes(ISO_8859_1).length)
80
.append("\r\n");
81
sb.append("\r\n");
82
sb.append(body);
83
return sb.toString();
84
}
85
86
static final String responses[] = {
87
"Lorem ipsum dolor sit amet consectetur adipiscing elit,",
88
"sed do eiusmod tempor quis nostrud exercitation ullamco laboris nisi ut",
89
"aliquip ex ea commodo consequat."
90
};
91
92
static final ReferenceTracker TRACKER = ReferenceTracker.INSTANCE;
93
final ServerSocketFactory factory;
94
final SSLContext context;
95
final boolean useSSL;
96
CancelledResponse(boolean useSSL) throws IOException {
97
this.useSSL = useSSL;
98
context = new SimpleSSLContext().get();
99
SSLContext.setDefault(context);
100
factory = useSSL ? SSLServerSocketFactory.getDefault()
101
: ServerSocketFactory.getDefault();
102
}
103
104
public HttpClient newHttpClient() {
105
HttpClient client;
106
if (useSSL) {
107
client = HttpClient.newBuilder()
108
.sslContext(context)
109
.build();
110
} else {
111
client = HttpClient.newHttpClient();
112
}
113
return TRACKER.track(client);
114
}
115
116
public static void main(String[] args) throws Exception {
117
boolean useSSL = false;
118
if (args != null && args.length == 1) {
119
useSSL = "SSL".equals(args[0]);
120
}
121
CancelledResponse sp = new CancelledResponse(useSSL);
122
123
Throwable failed = null;
124
try {
125
for (Version version : Version.values()) {
126
for (boolean serverKeepalive : new boolean[]{true, false}) {
127
// Note: the mock server doesn't support Keep-Alive, but
128
// pretending that it might exercises code paths in and out of
129
// the connection pool, and retry logic
130
for (boolean async : new boolean[]{true, false}) {
131
sp.test(version, serverKeepalive, async);
132
}
133
}
134
}
135
} catch (Exception | Error t) {
136
failed = t;
137
throw t;
138
} finally {
139
Thread.sleep(100);
140
AssertionError trackFailed = TRACKER.check(500);
141
if (trackFailed != null) {
142
if (failed != null) {
143
failed.addSuppressed(trackFailed);
144
if (failed instanceof Error) throw (Error) failed;
145
if (failed instanceof Exception) throw (Exception) failed;
146
}
147
throw trackFailed;
148
}
149
}
150
}
151
152
static class CancelException extends IOException {
153
}
154
155
// @Test
156
void test(Version version, boolean serverKeepalive, boolean async)
157
throws Exception
158
{
159
out.println(format("*** version %s, serverKeepAlive: %s, async: %s ***",
160
version, serverKeepalive, async));
161
MockServer server = new MockServer(0, factory);
162
URI uri = new URI(server.getURL());
163
out.println("server is: " + uri);
164
server.start();
165
166
HttpClient client = newHttpClient();
167
HttpRequest request = HttpRequest.newBuilder(uri).version(version).build();
168
try {
169
for (int i = 0; i < responses.length; i++) {
170
HttpResponse<String> r = null;
171
CompletableFuture<HttpResponse<String>> cf1;
172
CancelException expected = null;
173
AtomicBoolean cancelled = new AtomicBoolean();
174
175
out.println("----- iteration " + i + " -----");
176
String body = responses[i];
177
Thread t = sendSplitResponse(response(body, serverKeepalive), server, cancelled);
178
179
try {
180
if (async) {
181
out.println("send async: " + request);
182
cf1 = client.sendAsync(request, ofString(body, cancelled));
183
r = cf1.get();
184
} else { // sync
185
out.println("send sync: " + request);
186
r = client.send(request, ofString(body, cancelled));
187
}
188
} catch (CancelException c1) {
189
System.out.println("Got expected exception: " + c1);
190
expected = c1;
191
} catch (IOException | ExecutionException | CompletionException c2) {
192
Throwable c = c2;
193
while (c != null && !(c instanceof CancelException)) {
194
c = c.getCause();
195
}
196
if (c instanceof CancelException) {
197
System.out.println("Got expected exception: " + c);
198
expected = (CancelException)c;
199
} else throw c2;
200
}
201
if (r != null) {
202
if (r.statusCode() != 200)
203
throw new RuntimeException("Failed");
204
205
String rxbody = r.body();
206
out.println("received " + rxbody);
207
if (!rxbody.equals(body))
208
throw new RuntimeException(format("Expected:%s, got:%s", body, rxbody));
209
}
210
t.join();
211
conn.close();
212
if (expected == null) {
213
throw new RuntimeException("Expected exception not raised for "
214
+ i + " cancelled=" + cancelled.get());
215
}
216
}
217
} finally {
218
server.close();
219
}
220
System.out.println("OK");
221
}
222
223
static class CancellingSubscriber implements BodySubscriber<String> {
224
private final String expected;
225
private final CompletableFuture<String> result;
226
private Flow.Subscription subscription;
227
final AtomicInteger index = new AtomicInteger();
228
final AtomicBoolean cancelled;
229
CancellingSubscriber(String expected, AtomicBoolean cancelled) {
230
this.cancelled = cancelled;
231
this.expected = expected;
232
result = new CompletableFuture<>();
233
}
234
235
@Override
236
public CompletionStage<String> getBody() {
237
return result;
238
}
239
240
@Override
241
public void onSubscribe(Flow.Subscription subscription) {
242
this.subscription = subscription;
243
subscription.request(1);
244
}
245
246
@Override
247
public void onNext(List<ByteBuffer> item) {
248
//if (result.isDone())
249
for (ByteBuffer b : item) {
250
while (b.hasRemaining() && !result.isDone()) {
251
int i = index.getAndIncrement();
252
char at = expected.charAt(i);
253
byte[] data = new byte[b.remaining()];
254
b.get(data); // we know that the server writes 1 char
255
String s = new String(data);
256
char c = s.charAt(0);
257
if (c != at) {
258
Throwable x = new IllegalStateException("char at "
259
+ i + " is '" + c + "' expected '"
260
+ at + "' for \"" + expected +"\"");
261
out.println("unexpected char received, cancelling");
262
subscription.cancel();
263
result.completeExceptionally(x);
264
return;
265
}
266
}
267
}
268
if (index.get() > 0 && !result.isDone()) {
269
// we should complete the result here, but let's
270
// see if we get something back...
271
out.println("Cancelling subscription after reading " + index.get());
272
cancelled.set(true);
273
subscription.cancel();
274
result.completeExceptionally(new CancelException());
275
return;
276
}
277
if (!result.isDone()) {
278
out.println("requesting 1 more");
279
subscription.request(1);
280
}
281
}
282
283
@Override
284
public void onError(Throwable throwable) {
285
result.completeExceptionally(throwable);
286
}
287
288
@Override
289
public void onComplete() {
290
int len = index.get();
291
if (len == expected.length()) {
292
result.complete(expected);
293
} else {
294
Throwable x = new IllegalStateException("received only "
295
+ len + " chars, expected " + expected.length()
296
+ " for \"" + expected +"\"");
297
result.completeExceptionally(x);
298
}
299
}
300
}
301
302
static class CancellingHandler implements BodyHandler<String> {
303
final String expected;
304
final AtomicBoolean cancelled;
305
CancellingHandler(String expected, AtomicBoolean cancelled) {
306
this.expected = expected;
307
this.cancelled = cancelled;
308
}
309
@Override
310
public BodySubscriber<String> apply(HttpResponse.ResponseInfo rinfo) {
311
assert !cancelled.get();
312
return new CancellingSubscriber(expected, cancelled);
313
}
314
}
315
316
BodyHandler<String> ofString(String expected, AtomicBoolean cancelled) {
317
return new CancellingHandler(expected, cancelled);
318
}
319
320
// required for cleanup
321
volatile MockServer.Connection conn;
322
323
// Sends the response, mostly, one byte at a time with a small delay
324
// between bytes, to encourage that each byte is read in a separate read
325
Thread sendSplitResponse(String s, MockServer server, AtomicBoolean cancelled) {
326
System.out.println("Sending: ");
327
Thread t = new Thread(() -> {
328
System.out.println("Waiting for server to receive headers");
329
conn = server.activity();
330
System.out.println("Start sending response");
331
int sent = 0;
332
try {
333
int len = s.length();
334
out.println("sending " + s);
335
for (int i = 0; i < len; i++) {
336
String onechar = s.substring(i, i + 1);
337
conn.send(onechar);
338
sent++;
339
Thread.sleep(10);
340
}
341
out.println("sent " + s);
342
} catch (SSLException | SocketException | RuntimeException x) {
343
// if SSL then we might get a "Broken Pipe", or a
344
// RuntimeException wrapping an InvalidAlgorithmParameterException
345
// (probably if the channel is closed during the handshake),
346
// otherwise we get a "Socket closed".
347
boolean expected = cancelled.get();
348
if (sent > 0 && expected) {
349
System.out.println("Connection closed by peer as expected: " + x);
350
return;
351
} else {
352
System.out.println("Unexpected exception (sent="
353
+ sent + ", cancelled=" + expected + "): " + x);
354
if (x instanceof RuntimeException) throw (RuntimeException) x;
355
throw new RuntimeException(x);
356
}
357
} catch (IOException | InterruptedException e) {
358
throw new RuntimeException(e);
359
}
360
});
361
t.setDaemon(true);
362
t.start();
363
return t;
364
}
365
}
366
367