Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/jdk/sun/net/www/http/HttpClient/B8209178.java
41154 views
1
/*
2
* Copyright (c) 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 8209178
27
* @modules java.base/sun.net.www java.base/sun.security.x509 java.base/sun.security.tools.keytool
28
* @library /test/lib
29
* @run main/othervm -Dsun.net.http.retryPost=true B8209178
30
* @run main/othervm -Dsun.net.http.retryPost=false B8209178
31
* @summary Proxied HttpsURLConnection doesn't send BODY when retrying POST request
32
*/
33
34
import java.io.*;
35
import java.net.*;
36
import java.nio.charset.StandardCharsets;
37
import java.security.KeyStore;
38
import java.security.NoSuchAlgorithmException;
39
import java.security.cert.X509Certificate;
40
import java.util.HashMap;
41
import javax.net.ssl.*;
42
43
import com.sun.net.httpserver.*;
44
import jdk.test.lib.net.URIBuilder;
45
import sun.security.tools.keytool.CertAndKeyGen;
46
import sun.security.x509.X500Name;
47
48
public class B8209178 {
49
static {
50
try {
51
HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -> true);
52
SSLContext.setDefault(new TestSSLContext().get());
53
} catch (Exception ex) {
54
throw new ExceptionInInitializerError(ex);
55
}
56
}
57
58
static final String RESPONSE = "<html><body><p>Hello World!</body></html>";
59
static final String PATH = "/foo/";
60
static final String RETRYPOST = System.getProperty("sun.net.http.retryPost");
61
62
static HttpServer createHttpsServer() throws IOException, NoSuchAlgorithmException {
63
HttpsServer server = HttpsServer.create();
64
HttpContext context = server.createContext(PATH);
65
context.setHandler(new HttpHandler() {
66
67
boolean simulateError = true;
68
69
@Override
70
public void handle(HttpExchange he) throws IOException {
71
72
System.out.printf("%s - received request on : %s%n",
73
Thread.currentThread().getName(),
74
he.getRequestURI());
75
System.out.printf("%s - received request headers : %s%n",
76
Thread.currentThread().getName(),
77
new HashMap(he.getRequestHeaders()));
78
79
InputStream requestBody = he.getRequestBody();
80
String body = B8209178.toString(requestBody);
81
82
System.out.printf("%s - received request body : %s%n",
83
Thread.currentThread().getName(), body);
84
85
if (simulateError) {
86
simulateError = false;
87
88
System.out.printf("%s - closing connection unexpectedly ... %n",
89
Thread.currentThread().getName(), he.getRequestHeaders());
90
91
he.close(); // try not to respond anything the first time ...
92
return;
93
}
94
95
he.getResponseHeaders().add("encoding", "UTF-8");
96
he.sendResponseHeaders(200, RESPONSE.length());
97
he.getResponseBody().write(RESPONSE.getBytes(StandardCharsets.UTF_8));
98
he.close();
99
}
100
});
101
102
server.setHttpsConfigurator(new Configurator(SSLContext.getDefault()));
103
server.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), 0);
104
return server;
105
}
106
107
public static void main(String[] args) throws IOException, NoSuchAlgorithmException {
108
HttpServer server = createHttpsServer();
109
server.start();
110
try {
111
new B8209178().test(server);
112
113
} finally {
114
server.stop(0);
115
System.out.println("Server stopped");
116
}
117
}
118
119
public void test(HttpServer server /*, HttpClient.Version version*/) throws IOException {
120
System.out.println("System property retryPost: " + RETRYPOST);
121
System.out.println("Server is: " + server.getAddress());
122
System.out.println("Verifying communication with server");
123
URI uri = URIBuilder.newBuilder()
124
.scheme("https")
125
.host(server.getAddress().getAddress())
126
.port(server.getAddress().getPort())
127
.path(PATH + "x")
128
.buildUnchecked();
129
130
TunnelingProxy proxy = new TunnelingProxy(server);
131
proxy.start();
132
133
try {
134
System.out.println("Proxy started");
135
Proxy p = new Proxy(Proxy.Type.HTTP,
136
InetSocketAddress.createUnresolved("localhost", proxy.getAddress().getPort()));
137
System.out.println("Verifying communication with proxy");
138
139
callHttpsServerThroughProxy(uri, p);
140
141
} finally {
142
System.out.println("Stopping proxy");
143
proxy.stop();
144
System.out.println("Proxy stopped");
145
}
146
}
147
148
private void callHttpsServerThroughProxy(URI uri, Proxy p) throws IOException {
149
HttpsURLConnection urlConnection = (HttpsURLConnection) uri.toURL().openConnection(p);
150
151
urlConnection.setConnectTimeout(1000);
152
urlConnection.setReadTimeout(3000);
153
urlConnection.setDoInput(true);
154
urlConnection.setDoOutput(true);
155
urlConnection.setRequestMethod("POST");
156
urlConnection.setUseCaches(false);
157
158
urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
159
urlConnection.setRequestProperty("charset", "utf-8");
160
urlConnection.setRequestProperty("Connection", "keep-alive");
161
162
String urlParameters = "param1=a&param2=b&param3=c";
163
byte[] postData = urlParameters.getBytes(StandardCharsets.UTF_8);
164
165
OutputStream outputStream = urlConnection.getOutputStream();
166
outputStream.write(postData);
167
outputStream.close();
168
169
int responseCode;
170
171
try {
172
responseCode = urlConnection.getResponseCode();
173
System.out.printf(" ResponseCode : %s%n", responseCode);
174
String output;
175
InputStream inputStream = (responseCode < 400) ? urlConnection.getInputStream() : urlConnection.getErrorStream();
176
output = toString(inputStream);
177
inputStream.close();
178
System.out.printf(" Output from server : %s%n", output);
179
180
if (responseCode == 200) { // OK !
181
} else {
182
throw new RuntimeException("Bad response Code : " + responseCode);
183
}
184
} catch (SocketException se) {
185
if (RETRYPOST.equals("true")) { // Should not get here with the fix
186
throw new RuntimeException("Unexpected Socket Exception: " + se);
187
} else {
188
System.out.println("Socket Exception received as expected: " + se);
189
}
190
}
191
}
192
193
static class TunnelingProxy {
194
final Thread accept;
195
final ServerSocket ss;
196
final boolean DEBUG = false;
197
final HttpServer serverImpl;
198
199
TunnelingProxy(HttpServer serverImpl) throws IOException {
200
this.serverImpl = serverImpl;
201
ss = new ServerSocket();
202
accept = new Thread(this::accept);
203
}
204
205
void start() throws IOException {
206
ss.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0));
207
accept.start();
208
}
209
210
// Pipe the input stream to the output stream
211
private synchronized Thread pipe(InputStream is, OutputStream os, char tag) {
212
return new Thread("TunnelPipe(" + tag + ")") {
213
@Override
214
public void run() {
215
try {
216
try {
217
int c;
218
while ((c = is.read()) != -1) {
219
os.write(c);
220
os.flush();
221
// if DEBUG prints a + or a - for each transferred
222
// character.
223
if (DEBUG) System.out.print(tag);
224
}
225
is.close();
226
} finally {
227
os.close();
228
}
229
} catch (IOException ex) {
230
if (DEBUG) ex.printStackTrace(System.out);
231
}
232
}
233
};
234
}
235
236
public InetSocketAddress getAddress() {
237
return new InetSocketAddress(ss.getInetAddress(), ss.getLocalPort());
238
}
239
240
// This is a bit shaky. It doesn't handle continuation
241
// lines, but our client shouldn't send any.
242
// Read a line from the input stream, swallowing the final
243
// \r\n sequence. Stops at the first \n, doesn't complain
244
// if it wasn't preceded by '\r'.
245
//
246
String readLine(InputStream r) throws IOException {
247
StringBuilder b = new StringBuilder();
248
int c;
249
while ((c = r.read()) != -1) {
250
if (c == '\n') {
251
break;
252
}
253
b.appendCodePoint(c);
254
}
255
if (b.codePointAt(b.length() - 1) == '\r') {
256
b.delete(b.length() - 1, b.length());
257
}
258
return b.toString();
259
}
260
261
public void accept() {
262
Socket clientConnection = null;
263
try {
264
while (true) {
265
System.out.println("Tunnel: Waiting for client");
266
Socket previous = clientConnection;
267
try {
268
clientConnection = ss.accept();
269
} catch (IOException io) {
270
if (DEBUG) io.printStackTrace(System.out);
271
break;
272
} finally {
273
// we have only 1 client at a time, so it is safe
274
// to close the previous connection here
275
if (previous != null) previous.close();
276
}
277
System.out.println("Tunnel: Client accepted");
278
Socket targetConnection = null;
279
InputStream ccis = clientConnection.getInputStream();
280
OutputStream ccos = clientConnection.getOutputStream();
281
Writer w = new OutputStreamWriter(ccos, "UTF-8");
282
PrintWriter pw = new PrintWriter(w);
283
System.out.println("Tunnel: Reading request line");
284
String requestLine = readLine(ccis);
285
System.out.println("Tunnel: Request status line: " + requestLine);
286
if (requestLine.startsWith("CONNECT ")) {
287
// We should probably check that the next word following
288
// CONNECT is the host:port of our HTTPS serverImpl.
289
// Some improvement for a followup!
290
291
// Read all headers until we find the empty line that
292
// signals the end of all headers.
293
while (!requestLine.equals("")) {
294
System.out.println("Tunnel: Reading header: "
295
+ (requestLine = readLine(ccis)));
296
}
297
298
// Open target connection
299
targetConnection = new Socket(
300
serverImpl.getAddress().getAddress(),
301
serverImpl.getAddress().getPort());
302
303
// Then send the 200 OK response to the client
304
System.out.println("Tunnel: Sending "
305
+ "HTTP/1.1 200 OK\r\n\r\n");
306
pw.print("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
307
pw.flush();
308
} else {
309
// This should not happen
310
throw new IOException("Tunnel: Unexpected status line: "
311
+ requestLine);
312
}
313
314
// Pipe the input stream of the client connection to the
315
// output stream of the target connection and conversely.
316
// Now the client and target will just talk to each other.
317
System.out.println("Tunnel: Starting tunnel pipes");
318
Thread t1 = pipe(ccis, targetConnection.getOutputStream(), '+');
319
Thread t2 = pipe(targetConnection.getInputStream(), ccos, '-');
320
t1.start();
321
t2.start();
322
323
// We have only 1 client... wait until it has finished before
324
// accepting a new connection request.
325
System.out.println("Tunnel: Waiting for pipes to close");
326
t1.join();
327
t2.join();
328
System.out.println("Tunnel: Done - waiting for next client");
329
}
330
} catch (Throwable ex) {
331
try {
332
ss.close();
333
} catch (IOException ex1) {
334
ex.addSuppressed(ex1);
335
}
336
ex.printStackTrace(System.err);
337
}
338
}
339
340
void stop() throws IOException {
341
ss.close();
342
}
343
}
344
345
static class Configurator extends HttpsConfigurator {
346
public Configurator(SSLContext ctx) {
347
super(ctx);
348
}
349
350
@Override
351
public void configure(HttpsParameters params) {
352
params.setSSLParameters(getSSLContext().getSupportedSSLParameters());
353
}
354
}
355
356
357
static class TestSSLContext {
358
359
SSLContext ssl;
360
361
public TestSSLContext() throws Exception {
362
init();
363
}
364
365
private void init() throws Exception {
366
367
CertAndKeyGen keyGen = new CertAndKeyGen("RSA", "SHA1WithRSA", null);
368
keyGen.generate(1024);
369
370
//Generate self signed certificate
371
X509Certificate[] chain = new X509Certificate[1];
372
chain[0] = keyGen.getSelfCertificate(new X500Name("CN=ROOT"), (long) 365 * 24 * 3600);
373
374
char[] passphrase = "passphrase".toCharArray();
375
376
KeyStore ks = KeyStore.getInstance("JKS");
377
ks.load(null, passphrase); // must be "initialized" ...
378
379
ks.setKeyEntry("server", keyGen.getPrivateKey(), passphrase, chain);
380
381
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
382
kmf.init(ks, passphrase);
383
384
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
385
tmf.init(ks);
386
387
ssl = SSLContext.getInstance("TLS");
388
ssl.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
389
}
390
391
public SSLContext get() {
392
return ssl;
393
}
394
}
395
396
// ###############################################################################################
397
398
private static String toString(InputStream inputStream) throws IOException {
399
StringBuilder sb = new StringBuilder();
400
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
401
int i = bufferedReader.read();
402
while (i != -1) {
403
sb.append((char) i);
404
i = bufferedReader.read();
405
}
406
bufferedReader.close();
407
return sb.toString();
408
}
409
}
410
411