Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/jdk/java/net/httpclient/EncodedCharsInURI.java
41152 views
1
/*
2
* Copyright (c) 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
* @bug 8199683
27
* @summary Tests that escaped characters in URI are correctly
28
* handled (not re-escaped and not unescaped)
29
* @library /test/lib http2/server
30
* @build jdk.test.lib.net.SimpleSSLContext HttpServerAdapters EncodedCharsInURI
31
* @modules java.base/sun.net.www.http
32
* java.net.http/jdk.internal.net.http.common
33
* java.net.http/jdk.internal.net.http.frame
34
* java.net.http/jdk.internal.net.http.hpack
35
* @run testng/othervm
36
* -Djdk.tls.acknowledgeCloseNotify=true
37
* -Djdk.internal.httpclient.debug=true
38
* -Djdk.httpclient.HttpClient.log=headers,errors EncodedCharsInURI
39
*/
40
//* -Djdk.internal.httpclient.debug=true
41
42
import com.sun.net.httpserver.HttpServer;
43
import com.sun.net.httpserver.HttpsConfigurator;
44
import com.sun.net.httpserver.HttpsServer;
45
import jdk.test.lib.net.SimpleSSLContext;
46
import org.testng.annotations.AfterClass;
47
import org.testng.annotations.AfterTest;
48
import org.testng.annotations.BeforeTest;
49
import org.testng.annotations.DataProvider;
50
import org.testng.annotations.Test;
51
52
import javax.net.ServerSocketFactory;
53
import javax.net.ssl.SSLContext;
54
import java.io.IOException;
55
import java.io.InputStream;
56
import java.io.OutputStream;
57
import java.net.InetAddress;
58
import java.net.InetSocketAddress;
59
import java.net.ServerSocket;
60
import java.net.Socket;
61
import java.net.URI;
62
import java.net.http.HttpClient;
63
import java.net.http.HttpRequest;
64
import java.net.http.HttpRequest.BodyPublisher;
65
import java.net.http.HttpRequest.BodyPublishers;
66
import java.net.http.HttpResponse;
67
import java.net.http.HttpResponse.BodyHandler;
68
import java.net.http.HttpResponse.BodyHandlers;
69
import java.util.List;
70
import java.util.Locale;
71
import java.util.StringTokenizer;
72
import java.util.concurrent.CompletableFuture;
73
import java.util.concurrent.ConcurrentHashMap;
74
import java.util.concurrent.ConcurrentLinkedQueue;
75
import java.util.concurrent.ConcurrentMap;
76
import java.util.concurrent.Executor;
77
import java.util.concurrent.Executors;
78
import java.util.concurrent.atomic.AtomicLong;
79
80
import static java.lang.String.format;
81
import static java.lang.System.in;
82
import static java.lang.System.out;
83
import static java.nio.charset.StandardCharsets.US_ASCII;
84
import static java.nio.charset.StandardCharsets.UTF_8;
85
import static java.net.http.HttpClient.Builder.NO_PROXY;
86
import static org.testng.Assert.assertEquals;
87
import static org.testng.Assert.assertTrue;
88
89
public class EncodedCharsInURI implements HttpServerAdapters {
90
91
SSLContext sslContext;
92
HttpTestServer httpTestServer; // HTTP/1.1 [ 4 servers ]
93
HttpTestServer httpsTestServer; // HTTPS/1.1
94
HttpTestServer http2TestServer; // HTTP/2 ( h2c )
95
HttpTestServer https2TestServer; // HTTP/2 ( h2 )
96
DummyServer httpDummyServer; // HTTP/1.1 [ 2 servers ]
97
DummyServer httpsDummyServer; // HTTPS/1.1
98
String httpURI_fixed;
99
String httpURI_chunk;
100
String httpsURI_fixed;
101
String httpsURI_chunk;
102
String http2URI_fixed;
103
String http2URI_chunk;
104
String https2URI_fixed;
105
String https2URI_chunk;
106
String httpDummy;
107
String httpsDummy;
108
109
static final int ITERATION_COUNT = 1;
110
// a shared executor helps reduce the amount of threads created by the test
111
static final Executor executor = new TestExecutor(Executors.newCachedThreadPool());
112
static final ConcurrentMap<String, Throwable> FAILURES = new ConcurrentHashMap<>();
113
static volatile boolean tasksFailed;
114
static final AtomicLong serverCount = new AtomicLong();
115
static final AtomicLong clientCount = new AtomicLong();
116
static final long start = System.nanoTime();
117
public static String now() {
118
long now = System.nanoTime() - start;
119
long secs = now / 1000_000_000;
120
long mill = (now % 1000_000_000) / 1000_000;
121
long nan = now % 1000_000;
122
return String.format("[%d s, %d ms, %d ns] ", secs, mill, nan);
123
}
124
125
private volatile HttpClient sharedClient;
126
127
static class TestExecutor implements Executor {
128
final AtomicLong tasks = new AtomicLong();
129
Executor executor;
130
TestExecutor(Executor executor) {
131
this.executor = executor;
132
}
133
134
@Override
135
public void execute(Runnable command) {
136
long id = tasks.incrementAndGet();
137
executor.execute(() -> {
138
try {
139
command.run();
140
} catch (Throwable t) {
141
tasksFailed = true;
142
System.out.printf(now() + "Task %s failed: %s%n", id, t);
143
System.err.printf(now() + "Task %s failed: %s%n", id, t);
144
FAILURES.putIfAbsent("Task " + id, t);
145
throw t;
146
}
147
});
148
}
149
}
150
151
@AfterClass
152
static final void printFailedTests() {
153
out.println("\n=========================");
154
try {
155
out.printf("%n%sCreated %d servers and %d clients%n",
156
now(), serverCount.get(), clientCount.get());
157
if (FAILURES.isEmpty()) return;
158
out.println("Failed tests: ");
159
FAILURES.entrySet().forEach((e) -> {
160
out.printf("\t%s: %s%n", e.getKey(), e.getValue());
161
e.getValue().printStackTrace(out);
162
});
163
if (tasksFailed) {
164
System.out.println("WARNING: Some tasks failed");
165
}
166
} finally {
167
out.println("\n=========================\n");
168
}
169
}
170
171
private String[] uris() {
172
return new String[] {
173
httpDummy,
174
httpsDummy,
175
httpURI_fixed,
176
httpURI_chunk,
177
httpsURI_fixed,
178
httpsURI_chunk,
179
http2URI_fixed,
180
http2URI_chunk,
181
https2URI_fixed,
182
https2URI_chunk,
183
};
184
}
185
186
@DataProvider(name = "noThrows")
187
public Object[][] noThrows() {
188
String[] uris = uris();
189
Object[][] result = new Object[uris.length * 2][];
190
//Object[][] result = new Object[uris.length][];
191
int i = 0;
192
for (boolean sameClient : List.of(false, true)) {
193
//if (!sameClient) continue;
194
for (String uri: uris()) {
195
result[i++] = new Object[] {uri, sameClient};
196
}
197
}
198
assert i == uris.length * 2;
199
// assert i == uris.length ;
200
return result;
201
}
202
203
private HttpClient makeNewClient() {
204
clientCount.incrementAndGet();
205
return HttpClient.newBuilder()
206
.executor(executor)
207
.proxy(NO_PROXY)
208
.sslContext(sslContext)
209
.build();
210
}
211
212
HttpClient newHttpClient(boolean share) {
213
if (!share) return makeNewClient();
214
HttpClient shared = sharedClient;
215
if (shared != null) return shared;
216
synchronized (this) {
217
shared = sharedClient;
218
if (shared == null) {
219
shared = sharedClient = makeNewClient();
220
}
221
return shared;
222
}
223
}
224
225
final String ENCODED = "/01%252F03/";
226
227
@Test(dataProvider = "noThrows")
228
public void testEncodedChars(String uri, boolean sameClient)
229
throws Exception {
230
HttpClient client = null;
231
out.printf("%n%s testEncodedChars(%s, %b)%n", now(), uri, sameClient);
232
uri = uri + ENCODED;
233
for (int i=0; i< ITERATION_COUNT; i++) {
234
if (!sameClient || client == null)
235
client = newHttpClient(sameClient);
236
237
BodyPublisher bodyPublisher = BodyPublishers.ofString(uri);
238
239
HttpRequest req = HttpRequest.newBuilder(URI.create(uri))
240
.POST(bodyPublisher)
241
.build();
242
BodyHandler<String> handler = BodyHandlers.ofString();
243
CompletableFuture<HttpResponse<String>> responseCF = client.sendAsync(req, handler);
244
HttpResponse<String> response = responseCF.join();
245
String body = response.body();
246
if (!uri.contains(body)) {
247
System.err.println("Test failed: " + response);
248
throw new RuntimeException(uri + " doesn't contain '" + body + "'");
249
} else {
250
System.out.println("Found expected " + body + " in " + uri);
251
}
252
}
253
}
254
255
@BeforeTest
256
public void setup() throws Exception {
257
sslContext = new SimpleSSLContext().get();
258
if (sslContext == null)
259
throw new AssertionError("Unexpected null sslContext");
260
261
// HTTP/1.1
262
HttpTestHandler h1_fixedLengthHandler = new HTTP_FixedLengthHandler();
263
HttpTestHandler h1_chunkHandler = new HTTP_ChunkedHandler();
264
InetSocketAddress sa = new InetSocketAddress(InetAddress.getLoopbackAddress(), 0);
265
httpTestServer = HttpTestServer.of(HttpServer.create(sa, 0));
266
httpTestServer.addHandler(h1_fixedLengthHandler, "/http1/fixed");
267
httpTestServer.addHandler(h1_chunkHandler, "/http1/chunk");
268
httpURI_fixed = "http://" + httpTestServer.serverAuthority() + "/http1/fixed/x";
269
httpURI_chunk = "http://" + httpTestServer.serverAuthority() + "/http1/chunk/x";
270
271
HttpsServer httpsServer = HttpsServer.create(sa, 0);
272
httpsServer.setHttpsConfigurator(new HttpsConfigurator(sslContext));
273
httpsTestServer = HttpTestServer.of(httpsServer);
274
httpsTestServer.addHandler(h1_fixedLengthHandler, "/https1/fixed");
275
httpsTestServer.addHandler(h1_chunkHandler, "/https1/chunk");
276
httpsURI_fixed = "https://" + httpsTestServer.serverAuthority() + "/https1/fixed/x";
277
httpsURI_chunk = "https://" + httpsTestServer.serverAuthority() + "/https1/chunk/x";
278
279
// HTTP/2
280
HttpTestHandler h2_fixedLengthHandler = new HTTP_FixedLengthHandler();
281
HttpTestHandler h2_chunkedHandler = new HTTP_ChunkedHandler();
282
283
http2TestServer = HttpTestServer.of(new Http2TestServer("localhost", false, 0));
284
http2TestServer.addHandler(h2_fixedLengthHandler, "/http2/fixed");
285
http2TestServer.addHandler(h2_chunkedHandler, "/http2/chunk");
286
http2URI_fixed = "http://" + http2TestServer.serverAuthority() + "/http2/fixed/x";
287
http2URI_chunk = "http://" + http2TestServer.serverAuthority() + "/http2/chunk/x";
288
289
https2TestServer = HttpTestServer.of(new Http2TestServer("localhost", true, sslContext));
290
https2TestServer.addHandler(h2_fixedLengthHandler, "/https2/fixed");
291
https2TestServer.addHandler(h2_chunkedHandler, "/https2/chunk");
292
https2URI_fixed = "https://" + https2TestServer.serverAuthority() + "/https2/fixed/x";
293
https2URI_chunk = "https://" + https2TestServer.serverAuthority() + "/https2/chunk/x";
294
295
// DummyServer
296
httpDummyServer = DummyServer.create(sa);
297
httpsDummyServer = DummyServer.create(sa, sslContext);
298
httpDummy = "http://" + httpDummyServer.serverAuthority() + "/http1/dummy/x";
299
httpsDummy = "https://" + httpsDummyServer.serverAuthority() + "/https1/dummy/x";
300
301
302
serverCount.addAndGet(6);
303
httpTestServer.start();
304
httpsTestServer.start();
305
http2TestServer.start();
306
https2TestServer.start();
307
httpDummyServer.start();
308
httpsDummyServer.start();
309
}
310
311
@AfterTest
312
public void teardown() throws Exception {
313
sharedClient = null;
314
httpTestServer.stop();
315
httpsTestServer.stop();
316
http2TestServer.stop();
317
https2TestServer.stop();
318
httpDummyServer.stopServer();
319
httpsDummyServer.stopServer();
320
}
321
322
static class HTTP_FixedLengthHandler implements HttpTestHandler {
323
@Override
324
public void handle(HttpTestExchange t) throws IOException {
325
out.println("HTTP_FixedLengthHandler received request to " + t.getRequestURI());
326
byte[] req;
327
try (InputStream is = t.getRequestBody()) {
328
req = is.readAllBytes();
329
}
330
String uri = new String(req, UTF_8);
331
byte[] resp = t.getRequestURI().toString().getBytes(UTF_8);
332
if (!uri.contains(t.getRequestURI().toString())) {
333
t.sendResponseHeaders(404, resp.length);
334
} else {
335
t.sendResponseHeaders(200, resp.length); //fixed content length
336
}
337
try (OutputStream os = t.getResponseBody()) {
338
os.write(resp);
339
}
340
}
341
}
342
343
static class HTTP_ChunkedHandler implements HttpTestHandler {
344
@Override
345
public void handle(HttpTestExchange t) throws IOException {
346
out.println("HTTP_ChunkedHandler received request to " + t.getRequestURI());
347
byte[] resp;
348
try (InputStream is = t.getRequestBody()) {
349
resp = is.readAllBytes();
350
}
351
t.sendResponseHeaders(200, -1); // chunked/variable
352
try (OutputStream os = t.getResponseBody()) {
353
os.write(resp);
354
}
355
}
356
}
357
358
static class DummyServer extends Thread {
359
final ServerSocket ss;
360
final boolean secure;
361
ConcurrentLinkedQueue<Socket> connections = new ConcurrentLinkedQueue<>();
362
volatile boolean stopped;
363
DummyServer(ServerSocket ss, boolean secure) {
364
super("DummyServer[" + ss.getLocalPort()+"]");
365
this.secure = secure;
366
this.ss = ss;
367
}
368
369
// This is a bit shaky. It doesn't handle continuation
370
// lines, but our client shouldn't send any.
371
// Read a line from the input stream, swallowing the final
372
// \r\n sequence. Stops at the first \n, doesn't complain
373
// if it wasn't preceded by '\r'.
374
//
375
String readLine(InputStream r) throws IOException {
376
StringBuilder b = new StringBuilder();
377
int c;
378
while ((c = r.read()) != -1) {
379
if (c == '\n') break;
380
b.appendCodePoint(c);
381
}
382
if (b.codePointAt(b.length() -1) == '\r') {
383
b.delete(b.length() -1, b.length());
384
}
385
return b.toString();
386
}
387
388
@Override
389
public void run() {
390
try {
391
while(!stopped) {
392
Socket clientConnection = ss.accept();
393
connections.add(clientConnection);
394
System.out.println(now() + getName() + ": Client accepted");
395
StringBuilder headers = new StringBuilder();
396
Socket targetConnection = null;
397
InputStream ccis = clientConnection.getInputStream();
398
OutputStream ccos = clientConnection.getOutputStream();
399
System.out.println(now() + getName() + ": Reading request line");
400
String requestLine = readLine(ccis);
401
System.out.println(now() + getName() + ": Request line: " + requestLine);
402
403
StringTokenizer tokenizer = new StringTokenizer(requestLine);
404
String method = tokenizer.nextToken();
405
assert method.equalsIgnoreCase("POST") || method.equalsIgnoreCase("GET");
406
String path = tokenizer.nextToken();
407
URI uri;
408
try {
409
String hostport = serverAuthority();
410
uri = new URI((secure ? "https" : "http") +"://" + hostport + path);
411
} catch (Throwable x) {
412
System.err.printf("Bad target address: \"%s\" in \"%s\"%n",
413
path, requestLine);
414
clientConnection.close();
415
continue;
416
}
417
418
// Read all headers until we find the empty line that
419
// signals the end of all headers.
420
String line = requestLine;
421
while (!line.equals("")) {
422
System.out.println(now() + getName() + ": Reading header: "
423
+ (line = readLine(ccis)));
424
headers.append(line).append("\r\n");
425
}
426
427
StringBuilder response = new StringBuilder();
428
429
int index = headers.toString()
430
.toLowerCase(Locale.US)
431
.indexOf("content-length: ");
432
byte[] b = uri.toString().getBytes(UTF_8);
433
if (index >= 0) {
434
index = index + "content-length: ".length();
435
String cl = headers.toString().substring(index);
436
StringTokenizer tk = new StringTokenizer(cl);
437
int len = Integer.parseInt(tk.nextToken());
438
assert len < b.length * 2;
439
System.out.println(now() + getName()
440
+ ": received body: "
441
+ new String(ccis.readNBytes(len), UTF_8));
442
}
443
System.out.println(now()
444
+ getName() + ": sending back " + uri);
445
446
response.append("HTTP/1.1 200 OK\r\nContent-Length: ")
447
.append(b.length)
448
.append("\r\n\r\n");
449
450
// Then send the 200 OK response to the client
451
System.out.println(now() + getName() + ": Sending "
452
+ response);
453
ccos.write(response.toString().getBytes(UTF_8));
454
ccos.flush();
455
System.out.println(now() + getName() + ": sent response headers");
456
ccos.write(b);
457
ccos.flush();
458
ccos.close();
459
System.out.println(now() + getName() + ": sent " + b.length + " body bytes");
460
connections.remove(clientConnection);
461
clientConnection.close();
462
}
463
} catch (Throwable t) {
464
if (!stopped) {
465
System.out.println(now() + getName() + ": failed: " + t);
466
t.printStackTrace();
467
try {
468
stopServer();
469
} catch (Throwable e) {
470
471
}
472
}
473
} finally {
474
System.out.println(now() + getName() + ": exiting");
475
}
476
}
477
478
void close(Socket s) {
479
try {
480
s.close();
481
} catch(Throwable t) {
482
483
}
484
}
485
public void stopServer() throws IOException {
486
stopped = true;
487
ss.close();
488
connections.forEach(this::close);
489
}
490
491
public String serverAuthority() {
492
return InetAddress.getLoopbackAddress().getHostName() + ":"
493
+ ss.getLocalPort();
494
}
495
496
static DummyServer create(InetSocketAddress sa) throws IOException {
497
ServerSocket ss = ServerSocketFactory.getDefault()
498
.createServerSocket(sa.getPort(), -1, sa.getAddress());
499
return new DummyServer(ss, false);
500
}
501
502
static DummyServer create(InetSocketAddress sa, SSLContext sslContext) throws IOException {
503
ServerSocket ss = sslContext.getServerSocketFactory()
504
.createServerSocket(sa.getPort(), -1, sa.getAddress());
505
return new DummyServer(ss, true);
506
}
507
508
509
}
510
511
}
512
513