Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/jdk/sun/net/www/http/HttpClient/B8025710.java
41154 views
1
/*
2
* Copyright (c) 2014, 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.io.*;
25
import java.net.*;
26
import java.security.*;
27
import java.security.cert.X509Certificate;
28
import java.util.ArrayList;
29
import java.util.concurrent.atomic.AtomicBoolean;
30
import java.util.regex.Matcher;
31
import java.util.regex.Pattern;
32
import javax.net.ServerSocketFactory;
33
import javax.net.SocketFactory;
34
import javax.net.ssl.*;
35
36
/**
37
* @test
38
* @bug 8025710
39
* @summary Proxied https connection reuse by HttpClient can send CONNECT to the server
40
* @run main/othervm B8025710
41
*/
42
public class B8025710 {
43
44
private final static AtomicBoolean connectInServer = new AtomicBoolean();
45
private static final String keystorefile =
46
System.getProperty("test.src", "./")
47
+ "/../../../../../javax/net/ssl/etc/keystore";
48
private static final String passphrase = "passphrase";
49
50
public static void main(String[] args) throws Exception {
51
new B8025710().runTest();
52
53
if (connectInServer.get())
54
throw new RuntimeException("TEST FAILED: server got proxy header");
55
else
56
System.out.println("TEST PASSED");
57
}
58
59
private void runTest() throws Exception {
60
ProxyServer proxyServer = new ProxyServer();
61
HttpServer httpServer = new HttpServer();
62
httpServer.start();
63
proxyServer.start();
64
65
URL url = new URL("https", InetAddress.getLocalHost().getHostName(),
66
httpServer.getPort(), "/");
67
68
Proxy proxy = new Proxy(Proxy.Type.HTTP, proxyServer.getAddress());
69
70
HttpsURLConnection.setDefaultSSLSocketFactory(createTestSSLSocketFactory());
71
72
// Make two connections. The bug occurs when the second request is made
73
for (int i = 0; i < 2; i++) {
74
System.out.println("Client: Requesting " + url.toExternalForm()
75
+ " via " + proxy.toString()
76
+ " (attempt " + (i + 1) + " of 2)");
77
78
HttpsURLConnection connection =
79
(HttpsURLConnection) url.openConnection(proxy);
80
81
connection.setRequestMethod("POST");
82
connection.setDoInput(true);
83
connection.setDoOutput(true);
84
connection.setRequestProperty("User-Agent", "Test/1.0");
85
connection.getOutputStream().write("Hello, world!".getBytes("UTF-8"));
86
87
if (connection.getResponseCode() != 200) {
88
System.err.println("Client: Unexpected response code "
89
+ connection.getResponseCode());
90
break;
91
}
92
93
String response = readLine(connection.getInputStream());
94
if (!"Hi!".equals(response)) {
95
System.err.println("Client: Unexpected response body: "
96
+ response);
97
}
98
}
99
httpServer.close();
100
proxyServer.close();
101
httpServer.join();
102
proxyServer.join();
103
}
104
105
class ProxyServer extends Thread implements Closeable {
106
107
private final ServerSocket proxySocket;
108
private final Pattern connectLinePattern =
109
Pattern.compile("^CONNECT ([^: ]+):([0-9]+) HTTP/[0-9.]+$");
110
private final String PROXY_RESPONSE =
111
"HTTP/1.0 200 Connection Established\r\n"
112
+ "Proxy-Agent: TestProxy/1.0\r\n"
113
+ "\r\n";
114
115
ProxyServer() throws Exception {
116
super("ProxyServer Thread");
117
118
// Create the http proxy server socket
119
proxySocket = ServerSocketFactory.getDefault().createServerSocket();
120
proxySocket.bind(new InetSocketAddress(InetAddress.getLocalHost(), 0));
121
}
122
123
public SocketAddress getAddress() { return proxySocket.getLocalSocketAddress(); }
124
125
@Override
126
public void close() throws IOException {
127
proxySocket.close();
128
}
129
130
@Override
131
public void run() {
132
ArrayList<Thread> threads = new ArrayList<>();
133
int connectionCount = 0;
134
try {
135
while (connectionCount++ < 2) {
136
final Socket clientSocket = proxySocket.accept();
137
final int proxyConnectionCount = connectionCount;
138
System.out.println("Proxy: NEW CONNECTION "
139
+ proxyConnectionCount);
140
141
Thread t = new Thread("ProxySocket" + proxyConnectionCount) {
142
@Override
143
public void run() {
144
try {
145
String firstLine =
146
readHeader(clientSocket.getInputStream());
147
148
Matcher connectLineMatcher =
149
connectLinePattern.matcher(firstLine);
150
if (!connectLineMatcher.matches()) {
151
System.out.println("Proxy: Unexpected"
152
+ " request to the proxy: "
153
+ firstLine);
154
return;
155
}
156
157
String host = connectLineMatcher.group(1);
158
String portStr = connectLineMatcher.group(2);
159
int port = Integer.parseInt(portStr);
160
161
Socket serverSocket = SocketFactory.getDefault()
162
.createSocket(host, port);
163
164
clientSocket.getOutputStream()
165
.write(PROXY_RESPONSE.getBytes("UTF-8"));
166
167
ProxyTunnel copyToClient =
168
new ProxyTunnel(serverSocket, clientSocket);
169
ProxyTunnel copyToServer =
170
new ProxyTunnel(clientSocket, serverSocket);
171
172
copyToClient.start();
173
copyToServer.start();
174
175
copyToClient.join();
176
// here copyToClient.close() would not provoke the
177
// bug ( since it would trigger the retry logic in
178
// HttpURLConnction.writeRequests ), so close only
179
// the output to get the connection in this state.
180
clientSocket.shutdownOutput();
181
182
try {
183
Thread.sleep(3000);
184
} catch (InterruptedException ignored) { }
185
186
// now close all connections to finish the test
187
copyToServer.close();
188
copyToClient.close();
189
} catch (IOException | NumberFormatException
190
| InterruptedException e) {
191
e.printStackTrace();
192
}
193
}
194
};
195
threads.add(t);
196
t.start();
197
}
198
for (Thread t: threads)
199
t.join();
200
} catch (IOException | InterruptedException e) {
201
e.printStackTrace();
202
}
203
}
204
}
205
206
/**
207
* This inner class provides unidirectional data flow through the sockets
208
* by continuously copying bytes from the input socket onto the output
209
* socket, until both sockets are open and EOF has not been received.
210
*/
211
class ProxyTunnel extends Thread {
212
private final Socket sockIn;
213
private final Socket sockOut;
214
private final InputStream input;
215
private final OutputStream output;
216
217
public ProxyTunnel(Socket sockIn, Socket sockOut) throws IOException {
218
super("ProxyTunnel");
219
this.sockIn = sockIn;
220
this.sockOut = sockOut;
221
input = sockIn.getInputStream();
222
output = sockOut.getOutputStream();
223
}
224
225
public void run() {
226
byte[] buf = new byte[8192];
227
int bytesRead;
228
229
try {
230
while ((bytesRead = input.read(buf)) >= 0) {
231
output.write(buf, 0, bytesRead);
232
output.flush();
233
}
234
} catch (IOException ignored) {
235
close();
236
}
237
}
238
239
public void close() {
240
try {
241
if (!sockIn.isClosed())
242
sockIn.close();
243
if (!sockOut.isClosed())
244
sockOut.close();
245
} catch (IOException ignored) { }
246
}
247
}
248
249
/**
250
* the server thread
251
*/
252
class HttpServer extends Thread implements Closeable {
253
254
private final ServerSocket serverSocket;
255
private final SSLSocketFactory sslSocketFactory;
256
private final String serverResponse =
257
"HTTP/1.1 200 OK\r\n"
258
+ "Content-Type: text/plain\r\n"
259
+ "Content-Length: 3\r\n"
260
+ "\r\n"
261
+ "Hi!";
262
private int connectionCount = 0;
263
264
HttpServer() throws Exception {
265
super("HttpServer Thread");
266
267
KeyStore ks = KeyStore.getInstance("JKS");
268
ks.load(new FileInputStream(keystorefile), passphrase.toCharArray());
269
KeyManagerFactory factory = KeyManagerFactory.getInstance("SunX509");
270
factory.init(ks, passphrase.toCharArray());
271
SSLContext ctx = SSLContext.getInstance("TLS");
272
ctx.init(factory.getKeyManagers(), null, null);
273
274
sslSocketFactory = ctx.getSocketFactory();
275
276
// Create the server that the test wants to connect to via the proxy
277
serverSocket = ServerSocketFactory.getDefault().createServerSocket();
278
serverSocket.bind(new InetSocketAddress(InetAddress.getLocalHost(), 0));
279
}
280
281
public int getPort() { return serverSocket.getLocalPort(); }
282
283
@Override
284
public void close() throws IOException { serverSocket.close(); }
285
286
@Override
287
public void run() {
288
try {
289
while (connectionCount++ < 2) {
290
Socket socket = serverSocket.accept();
291
System.out.println("Server: NEW CONNECTION "
292
+ connectionCount);
293
294
SSLSocket sslSocket = (SSLSocket) sslSocketFactory
295
.createSocket(socket,null, getPort(), false);
296
sslSocket.setUseClientMode(false);
297
sslSocket.startHandshake();
298
299
String firstLine = readHeader(sslSocket.getInputStream());
300
if (firstLine != null && firstLine.contains("CONNECT")) {
301
System.out.println("Server: BUG! HTTP CONNECT"
302
+ " encountered: " + firstLine);
303
connectInServer.set(true);
304
}
305
306
// write the success response, the request body is not read.
307
// close only output and keep input open.
308
OutputStream out = sslSocket.getOutputStream();
309
out.write(serverResponse.getBytes("UTF-8"));
310
socket.shutdownOutput();
311
}
312
} catch (IOException e) {
313
e.printStackTrace();
314
}
315
}
316
}
317
318
/**
319
* read the header and return only the first line.
320
*
321
* @param inputStream the stream to read from
322
* @return the first line of the stream
323
* @throws IOException if reading failed
324
*/
325
private static String readHeader(InputStream inputStream)
326
throws IOException {
327
String line;
328
String firstLine = null;
329
while ((line = readLine(inputStream)) != null && line.length() > 0) {
330
if (firstLine == null) {
331
firstLine = line;
332
}
333
}
334
335
return firstLine;
336
}
337
338
/**
339
* read a line from stream.
340
*
341
* @param inputStream the stream to read from
342
* @return the line
343
* @throws IOException if reading failed
344
*/
345
private static String readLine(InputStream inputStream)
346
throws IOException {
347
final StringBuilder line = new StringBuilder();
348
int ch;
349
while ((ch = inputStream.read()) != -1) {
350
if (ch == '\r') {
351
continue;
352
}
353
354
if (ch == '\n') {
355
break;
356
}
357
358
line.append((char) ch);
359
}
360
361
return line.toString();
362
}
363
364
private SSLSocketFactory createTestSSLSocketFactory() {
365
366
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
367
@Override
368
public boolean verify(String hostname, SSLSession sslSession) {
369
// ignore the cert's CN; it's not important to this test
370
return true;
371
}
372
});
373
374
// Set up the socket factory to use a trust manager that trusts all
375
// certs, since trust validation isn't important to this test
376
final TrustManager[] trustAllCertChains = new TrustManager[] {
377
new X509TrustManager() {
378
@Override
379
public X509Certificate[] getAcceptedIssuers() {
380
return null;
381
}
382
383
@Override
384
public void checkClientTrusted(X509Certificate[] certs,
385
String authType) {
386
}
387
388
@Override
389
public void checkServerTrusted(X509Certificate[] certs,
390
String authType) {
391
}
392
}
393
};
394
395
final SSLContext sc;
396
try {
397
sc = SSLContext.getInstance("TLS");
398
} catch (NoSuchAlgorithmException e) {
399
throw new RuntimeException(e);
400
}
401
402
try {
403
sc.init(null, trustAllCertChains, new java.security.SecureRandom());
404
} catch (KeyManagementException e) {
405
throw new RuntimeException(e);
406
}
407
408
return sc.getSocketFactory();
409
}
410
}
411
412