Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/jdk/java/net/httpclient/CustomRequestPublisher.java
41149 views
1
/*
2
* Copyright (c) 2017, 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
/*
25
* @test
26
* @summary Checks correct handling of Publishers that call onComplete without demand
27
* @modules java.base/sun.net.www.http
28
* java.net.http/jdk.internal.net.http.common
29
* java.net.http/jdk.internal.net.http.frame
30
* java.net.http/jdk.internal.net.http.hpack
31
* java.logging
32
* jdk.httpserver
33
* @library /test/lib http2/server
34
* @build Http2TestServer
35
* @build jdk.test.lib.net.SimpleSSLContext
36
* @run testng/othervm CustomRequestPublisher
37
*/
38
39
import com.sun.net.httpserver.HttpExchange;
40
import com.sun.net.httpserver.HttpHandler;
41
import com.sun.net.httpserver.HttpServer;
42
import com.sun.net.httpserver.HttpsConfigurator;
43
import com.sun.net.httpserver.HttpsServer;
44
import java.io.IOException;
45
import java.io.InputStream;
46
import java.io.OutputStream;
47
import java.net.InetAddress;
48
import java.net.InetSocketAddress;
49
import java.net.URI;
50
import java.nio.ByteBuffer;
51
import java.util.Arrays;
52
import java.util.Optional;
53
import java.util.concurrent.CompletableFuture;
54
import java.util.concurrent.Flow;
55
import java.util.concurrent.atomic.AtomicBoolean;
56
import java.util.concurrent.atomic.AtomicInteger;
57
import java.util.concurrent.atomic.AtomicLong;
58
import java.util.function.Supplier;
59
import java.util.stream.Collectors;
60
import javax.net.ssl.SSLContext;
61
import javax.net.ssl.SSLSession;
62
import java.net.http.HttpClient;
63
import java.net.http.HttpRequest;
64
import java.net.http.HttpResponse;
65
import jdk.test.lib.net.SimpleSSLContext;
66
import org.testng.annotations.AfterTest;
67
import org.testng.annotations.BeforeTest;
68
import org.testng.annotations.DataProvider;
69
import org.testng.annotations.Test;
70
import static java.lang.System.out;
71
import static java.net.http.HttpClient.Version.HTTP_1_1;
72
import static java.net.http.HttpClient.Version.HTTP_2;
73
import static java.nio.charset.StandardCharsets.US_ASCII;
74
import static java.net.http.HttpResponse.BodyHandlers.ofString;
75
import static org.testng.Assert.assertEquals;
76
import static org.testng.Assert.assertTrue;
77
import static org.testng.Assert.fail;
78
79
public class CustomRequestPublisher {
80
81
SSLContext sslContext;
82
HttpServer httpTestServer; // HTTP/1.1 [ 4 servers ]
83
HttpsServer httpsTestServer; // HTTPS/1.1
84
Http2TestServer http2TestServer; // HTTP/2 ( h2c )
85
Http2TestServer https2TestServer; // HTTP/2 ( h2 )
86
String httpURI;
87
String httpsURI;
88
String http2URI;
89
String https2URI;
90
91
@DataProvider(name = "variants")
92
public Object[][] variants() {
93
Supplier<BodyPublisher> fixedSupplier = () -> new FixedLengthBodyPublisher();
94
Supplier<BodyPublisher> unknownSupplier = () -> new UnknownLengthBodyPublisher();
95
96
return new Object[][]{
97
{ httpURI, fixedSupplier, false },
98
{ httpURI, unknownSupplier, false },
99
{ httpsURI, fixedSupplier, false },
100
{ httpsURI, unknownSupplier, false },
101
{ http2URI, fixedSupplier, false },
102
{ http2URI, unknownSupplier, false },
103
{ https2URI, fixedSupplier, false,},
104
{ https2URI, unknownSupplier, false },
105
106
{ httpURI, fixedSupplier, true },
107
{ httpURI, unknownSupplier, true },
108
{ httpsURI, fixedSupplier, true },
109
{ httpsURI, unknownSupplier, true },
110
{ http2URI, fixedSupplier, true },
111
{ http2URI, unknownSupplier, true },
112
{ https2URI, fixedSupplier, true,},
113
{ https2URI, unknownSupplier, true },
114
};
115
}
116
117
static final int ITERATION_COUNT = 10;
118
119
/** Asserts HTTP Version, and SSLSession presence when applicable. */
120
static void assertVersionAndSession(HttpResponse response, String uri) {
121
if (uri.contains("http2") || uri.contains("https2"))
122
assertEquals(response.version(), HTTP_2);
123
else if (uri.contains("http1") || uri.contains("https1"))
124
assertEquals(response.version(), HTTP_1_1);
125
else
126
fail("Unknown HTTP version in test for: " + uri);
127
128
Optional<SSLSession> ssl = response.sslSession();
129
if (uri.contains("https")) {
130
assertTrue(ssl.isPresent(),
131
"Expected optional containing SSLSession but got:" + ssl);
132
try {
133
ssl.get().invalidate();
134
fail("SSLSession is not immutable: " + ssl.get());
135
} catch (UnsupportedOperationException expected) { }
136
} else {
137
assertTrue(!ssl.isPresent(), "UNEXPECTED non-empty optional:" + ssl);
138
}
139
}
140
141
@Test(dataProvider = "variants")
142
void test(String uri, Supplier<BodyPublisher> bpSupplier, boolean sameClient)
143
throws Exception
144
{
145
HttpClient client = null;
146
for (int i=0; i< ITERATION_COUNT; i++) {
147
if (!sameClient || client == null)
148
client = HttpClient.newBuilder().sslContext(sslContext).build();
149
150
BodyPublisher bodyPublisher = bpSupplier.get();
151
HttpRequest request = HttpRequest.newBuilder(URI.create(uri))
152
.POST(bodyPublisher)
153
.build();
154
155
HttpResponse<String> resp = client.send(request, ofString());
156
157
out.println("Got response: " + resp);
158
out.println("Got body: " + resp.body());
159
assertTrue(resp.statusCode() == 200,
160
"Expected 200, got:" + resp.statusCode());
161
assertEquals(resp.body(), bodyPublisher.bodyAsString());
162
163
assertVersionAndSession(resp, uri);
164
}
165
}
166
167
@Test(dataProvider = "variants")
168
void testAsync(String uri, Supplier<BodyPublisher> bpSupplier, boolean sameClient)
169
throws Exception
170
{
171
HttpClient client = null;
172
for (int i=0; i< ITERATION_COUNT; i++) {
173
if (!sameClient || client == null)
174
client = HttpClient.newBuilder().sslContext(sslContext).build();
175
176
BodyPublisher bodyPublisher = bpSupplier.get();
177
HttpRequest request = HttpRequest.newBuilder(URI.create(uri))
178
.POST(bodyPublisher)
179
.build();
180
181
CompletableFuture<HttpResponse<String>> cf = client.sendAsync(request, ofString());
182
HttpResponse<String> resp = cf.get();
183
184
out.println("Got response: " + resp);
185
out.println("Got body: " + resp.body());
186
assertTrue(resp.statusCode() == 200,
187
"Expected 200, got:" + resp.statusCode());
188
assertEquals(resp.body(), bodyPublisher.bodyAsString());
189
190
assertVersionAndSession(resp, uri);
191
}
192
}
193
194
/** A Publisher that returns an UNKNOWN content length. */
195
static class UnknownLengthBodyPublisher extends BodyPublisher {
196
@Override
197
public long contentLength() {
198
return -1; // unknown
199
}
200
}
201
202
/** A Publisher that returns a FIXED content length. */
203
static class FixedLengthBodyPublisher extends BodyPublisher {
204
final int LENGTH = Arrays.stream(BODY)
205
.mapToInt(s-> s.getBytes(US_ASCII).length)
206
.sum();
207
@Override
208
public long contentLength() {
209
return LENGTH;
210
}
211
}
212
213
/**
214
* A Publisher that ( quite correctly ) invokes onComplete, after the last
215
* item has been published, even without any outstanding demand.
216
*/
217
static abstract class BodyPublisher implements HttpRequest.BodyPublisher {
218
219
String[] BODY = new String[]
220
{ "Say ", "Hello ", "To ", "My ", "Little ", "Friend" };
221
222
protected volatile Flow.Subscriber subscriber;
223
224
@Override
225
public void subscribe(Flow.Subscriber<? super ByteBuffer> subscriber) {
226
this.subscriber = subscriber;
227
subscriber.onSubscribe(new InternalSubscription());
228
}
229
230
@Override
231
public abstract long contentLength();
232
233
String bodyAsString() {
234
return Arrays.stream(BODY).collect(Collectors.joining());
235
}
236
237
class InternalSubscription implements Flow.Subscription {
238
239
private final AtomicLong demand = new AtomicLong();
240
private final AtomicBoolean cancelled = new AtomicBoolean();
241
private volatile int position;
242
243
private static final int IDLE = 1;
244
private static final int PUSHING = 2;
245
private static final int AGAIN = 4;
246
private final AtomicInteger state = new AtomicInteger(IDLE);
247
248
@Override
249
public void request(long n) {
250
if (n <= 0L) {
251
subscriber.onError(new IllegalArgumentException(
252
"non-positive subscription request"));
253
return;
254
}
255
if (cancelled.get()) {
256
return;
257
}
258
259
while (true) {
260
long prev = demand.get(), d;
261
if ((d = prev + n) < prev) // saturate
262
d = Long.MAX_VALUE;
263
if (demand.compareAndSet(prev, d))
264
break;
265
}
266
267
while (true) {
268
int s = state.get();
269
if (s == IDLE) {
270
if (state.compareAndSet(IDLE, PUSHING)) {
271
while (true) {
272
push();
273
if (state.compareAndSet(PUSHING, IDLE))
274
return;
275
else if (state.compareAndSet(AGAIN, PUSHING))
276
continue;
277
}
278
}
279
} else if (s == PUSHING) {
280
if (state.compareAndSet(PUSHING, AGAIN))
281
return;
282
} else if (s == AGAIN){
283
// do nothing, the pusher will already rerun
284
return;
285
} else {
286
throw new AssertionError("Unknown state:" + s);
287
}
288
}
289
}
290
291
private void push() {
292
long prev;
293
while ((prev = demand.get()) > 0) {
294
if (!demand.compareAndSet(prev, prev -1))
295
continue;
296
297
int index = position;
298
if (index < BODY.length) {
299
position++;
300
subscriber.onNext(ByteBuffer.wrap(BODY[index].getBytes(US_ASCII)));
301
}
302
}
303
304
if (position == BODY.length && !cancelled.get()) {
305
cancelled.set(true);
306
subscriber.onComplete(); // NOTE: onComplete without demand
307
}
308
}
309
310
@Override
311
public void cancel() {
312
if (cancelled.compareAndExchange(false, true))
313
return; // already cancelled
314
}
315
}
316
}
317
318
static String serverAuthority(HttpServer server) {
319
return InetAddress.getLoopbackAddress().getHostName() + ":"
320
+ server.getAddress().getPort();
321
}
322
323
@BeforeTest
324
public void setup() throws Exception {
325
sslContext = new SimpleSSLContext().get();
326
if (sslContext == null)
327
throw new AssertionError("Unexpected null sslContext");
328
329
InetSocketAddress sa = new InetSocketAddress(InetAddress.getLoopbackAddress(), 0);
330
httpTestServer = HttpServer.create(sa, 0);
331
httpTestServer.createContext("/http1/echo", new Http1EchoHandler());
332
httpURI = "http://" + serverAuthority(httpTestServer) + "/http1/echo";
333
334
httpsTestServer = HttpsServer.create(sa, 0);
335
httpsTestServer.setHttpsConfigurator(new HttpsConfigurator(sslContext));
336
httpsTestServer.createContext("/https1/echo", new Http1EchoHandler());
337
httpsURI = "https://" + serverAuthority(httpsTestServer) + "/https1/echo";
338
339
http2TestServer = new Http2TestServer("localhost", false, 0);
340
http2TestServer.addHandler(new Http2EchoHandler(), "/http2/echo");
341
http2URI = "http://" + http2TestServer.serverAuthority() + "/http2/echo";
342
343
https2TestServer = new Http2TestServer("localhost", true, sslContext);
344
https2TestServer.addHandler(new Http2EchoHandler(), "/https2/echo");
345
https2URI = "https://" + https2TestServer.serverAuthority() + "/https2/echo";
346
347
httpTestServer.start();
348
httpsTestServer.start();
349
http2TestServer.start();
350
https2TestServer.start();
351
}
352
353
@AfterTest
354
public void teardown() throws Exception {
355
httpTestServer.stop(0);
356
httpsTestServer.stop(0);
357
http2TestServer.stop();
358
https2TestServer.stop();
359
}
360
361
static class Http1EchoHandler implements HttpHandler {
362
@Override
363
public void handle(HttpExchange t) throws IOException {
364
try (InputStream is = t.getRequestBody();
365
OutputStream os = t.getResponseBody()) {
366
byte[] bytes = is.readAllBytes();
367
t.sendResponseHeaders(200, bytes.length);
368
os.write(bytes);
369
}
370
}
371
}
372
373
static class Http2EchoHandler implements Http2Handler {
374
@Override
375
public void handle(Http2TestExchange t) throws IOException {
376
try (InputStream is = t.getRequestBody();
377
OutputStream os = t.getResponseBody()) {
378
byte[] bytes = is.readAllBytes();
379
t.sendResponseHeaders(200, bytes.length);
380
os.write(bytes);
381
}
382
}
383
}
384
}
385
386