Skip to content

Commit d451f81

Browse files
committedMar 10, 2024
8326381: com.sun.net.httpserver.HttpsParameters and SSLStreams incorrectly handle needClientAuth and wantClientAuth
Reviewed-by: djelinski
1 parent 243cb09 commit d451f81

File tree

3 files changed

+446
-4
lines changed

3 files changed

+446
-4
lines changed
 

‎src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpsParameters.java

+39-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -90,18 +90,27 @@ protected HttpsParameters() {}
9090
* Returns a copy of the array of ciphersuites or {@code null} if none
9191
* have been set.
9292
*
93+
* @deprecated It is recommended that the SSL parameters be configured and
94+
* read through the use of {@link #setSSLParameters(SSLParameters) SSLParameters}.
95+
*
9396
* @return a copy of the array of ciphersuites or {@code null} if none have
9497
* been set
9598
*/
99+
@Deprecated(since = "23")
96100
public String[] getCipherSuites() {
97101
return cipherSuites != null ? cipherSuites.clone() : null;
98102
}
99103

100104
/**
101105
* Sets the array of ciphersuites.
102106
*
107+
* @deprecated It is recommended that the SSL parameters be configured and
108+
* read through the use of {@link #setSSLParameters(SSLParameters) SSLParameters}. Use
109+
* {@link SSLParameters#setCipherSuites(String[])} instead.
110+
*
103111
* @param cipherSuites the array of ciphersuites (or {@code null})
104112
*/
113+
@Deprecated(since = "23")
105114
public void setCipherSuites(String[] cipherSuites) {
106115
this.cipherSuites = cipherSuites != null ? cipherSuites.clone() : null;
107116
}
@@ -110,27 +119,40 @@ public void setCipherSuites(String[] cipherSuites) {
110119
* Returns a copy of the array of protocols or {@code null} if none have been
111120
* set.
112121
*
122+
* @deprecated It is recommended that the SSL parameters be configured and
123+
* read through the use of {@link #setSSLParameters(SSLParameters) SSLParameters}.
124+
*
113125
* @return a copy of the array of protocols or {@code null} if none have been
114126
* set
115127
*/
128+
@Deprecated(since = "23")
116129
public String[] getProtocols() {
117130
return protocols != null ? protocols.clone() : null;
118131
}
119132

120133
/**
121134
* Sets the array of protocols.
122135
*
136+
* @deprecated It is recommended that the SSL parameters be configured and
137+
* read through the use of {@link #setSSLParameters(SSLParameters) SSLParameters}. Use
138+
* {@link SSLParameters#setProtocols(String[])} instead.
139+
*
123140
* @param protocols the array of protocols (or {@code null})
124141
*/
142+
@Deprecated(since = "23")
125143
public void setProtocols(String[] protocols) {
126144
this.protocols = protocols != null ? protocols.clone() : null;
127145
}
128146

129147
/**
130148
* Returns whether client authentication should be requested.
131149
*
150+
* @deprecated It is recommended that the SSL parameters be configured and
151+
* read through the use of {@link #setSSLParameters(SSLParameters) SSLParameters}.
152+
*
132153
* @return whether client authentication should be requested
133154
*/
155+
@Deprecated(since = "23")
134156
public boolean getWantClientAuth() {
135157
return wantClientAuth;
136158
}
@@ -139,17 +161,27 @@ public boolean getWantClientAuth() {
139161
* Sets whether client authentication should be requested. Calling this
140162
* method clears the {@code needClientAuth} flag.
141163
*
164+
* @deprecated It is recommended that the SSL parameters be configured and
165+
* read through the use of {@link #setSSLParameters(SSLParameters) SSLParameters}. Use
166+
* {@link SSLParameters#setWantClientAuth(boolean)} instead.
167+
*
142168
* @param wantClientAuth whether client authentication should be requested
143169
*/
170+
@Deprecated(since = "23")
144171
public void setWantClientAuth(boolean wantClientAuth) {
145172
this.wantClientAuth = wantClientAuth;
173+
this.needClientAuth = false;
146174
}
147175

148176
/**
149177
* Returns whether client authentication should be required.
150178
*
179+
* @deprecated It is recommended that the SSL parameters be configured and
180+
* read through the use of {@link #setSSLParameters(SSLParameters) SSLParameters}.
181+
*
151182
* @return whether client authentication should be required
152183
*/
184+
@Deprecated(since = "23")
153185
public boolean getNeedClientAuth() {
154186
return needClientAuth;
155187
}
@@ -158,9 +190,15 @@ public boolean getNeedClientAuth() {
158190
* Sets whether client authentication should be required. Calling this method
159191
* clears the {@code wantClientAuth} flag.
160192
*
193+
* @deprecated It is recommended that the SSL parameters be configured and
194+
* read through the use of {@link #setSSLParameters(SSLParameters) SSLParameters}. Use
195+
* {@link SSLParameters#setNeedClientAuth(boolean)} instead.
196+
*
161197
* @param needClientAuth whether client authentication should be required
162198
*/
199+
@Deprecated(since = "23")
163200
public void setNeedClientAuth(boolean needClientAuth) {
164201
this.needClientAuth = needClientAuth;
202+
this.wantClientAuth = false;
165203
}
166204
}

‎src/jdk.httpserver/share/classes/sun/net/httpserver/SSLStreams.java

+7-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -66,6 +66,7 @@ class SSLStreams {
6666
wrapper = new EngineWrapper (chan, engine);
6767
}
6868

69+
@SuppressWarnings("deprecation")
6970
private void configureEngine(HttpsConfigurator cfg, InetSocketAddress addr){
7071
if (cfg != null) {
7172
Parameters params = new Parameters (cfg, addr);
@@ -85,8 +86,11 @@ private void configureEngine(HttpsConfigurator cfg, InetSocketAddress addr){
8586
);
8687
} catch (IllegalArgumentException e) { /* LOG */}
8788
}
88-
engine.setNeedClientAuth (params.getNeedClientAuth());
89-
engine.setWantClientAuth (params.getWantClientAuth());
89+
if (params.getNeedClientAuth()) {
90+
engine.setNeedClientAuth(true);
91+
} else if (params.getWantClientAuth()) {
92+
engine.setWantClientAuth(true);
93+
}
9094
if (params.getProtocols() != null) {
9195
try {
9296
engine.setEnabledProtocols (
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,400 @@
1+
/*
2+
* Copyright (c) 2024, 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.FileInputStream;
25+
import java.io.IOException;
26+
import java.net.InetAddress;
27+
import java.net.InetSocketAddress;
28+
import java.net.SocketException;
29+
import java.net.URI;
30+
import java.net.http.HttpClient;
31+
import java.net.http.HttpRequest;
32+
import java.net.http.HttpResponse;
33+
import java.net.http.HttpResponse.BodyHandlers;
34+
import java.security.AccessController;
35+
import java.security.KeyStore;
36+
import java.security.PrivilegedExceptionAction;
37+
import java.util.concurrent.Executor;
38+
import java.util.concurrent.ExecutorService;
39+
import java.util.concurrent.Executors;
40+
import java.util.concurrent.ThreadFactory;
41+
import java.util.concurrent.atomic.AtomicInteger;
42+
43+
import javax.net.ssl.SSLContext;
44+
import javax.net.ssl.SSLHandshakeException;
45+
import javax.net.ssl.SSLParameters;
46+
import javax.net.ssl.TrustManagerFactory;
47+
48+
import com.sun.net.httpserver.HttpExchange;
49+
import com.sun.net.httpserver.HttpHandler;
50+
import com.sun.net.httpserver.HttpsConfigurator;
51+
import com.sun.net.httpserver.HttpsParameters;
52+
import com.sun.net.httpserver.HttpsServer;
53+
import jdk.test.lib.net.SimpleSSLContext;
54+
import jdk.test.lib.net.URIBuilder;
55+
import org.junit.jupiter.api.Test;
56+
import org.junit.jupiter.params.ParameterizedTest;
57+
import org.junit.jupiter.params.provider.ValueSource;
58+
import static java.net.http.HttpClient.Builder.NO_PROXY;
59+
import static java.net.http.HttpClient.Version.HTTP_1_1;
60+
import static org.junit.jupiter.api.Assertions.assertEquals;
61+
import static org.junit.jupiter.api.Assertions.assertFalse;
62+
import static org.junit.jupiter.api.Assertions.assertNotNull;
63+
import static org.junit.jupiter.api.Assertions.assertTrue;
64+
import static org.junit.jupiter.api.Assertions.fail;
65+
66+
/*
67+
* @test
68+
* @bug 8326381
69+
* @summary verifies that the setNeedClientAuth() and setWantClientAuth()
70+
* methods on HttpsParameters class work as expected
71+
* @library /test/lib
72+
* @build jdk.test.lib.net.SimpleSSLContext jdk.test.lib.net.URIBuilder
73+
* @run junit HttpsParametersClientAuthTest
74+
*/
75+
public class HttpsParametersClientAuthTest {
76+
77+
private static final AtomicInteger TID = new AtomicInteger();
78+
private static final ThreadFactory SRV_THREAD_FACTORY = (r) -> {
79+
final Thread t = new Thread(r);
80+
t.setDaemon(true);
81+
t.setName("server-thread-" + TID.incrementAndGet());
82+
return t;
83+
};
84+
85+
/**
86+
* verifies default values of {@link HttpsParameters#setNeedClientAuth(boolean)}
87+
* and {@link HttpsParameters#setWantClientAuth(boolean)} methods
88+
*/
89+
@Test
90+
public void testDefaultClientAuth() throws Exception {
91+
// test default values
92+
HttpsParameters defaultParams = new Params();
93+
assertFalse(defaultParams.getNeedClientAuth(),
94+
"needClientAuth was expected to be false but wasn't");
95+
assertFalse(defaultParams.getWantClientAuth(),
96+
"wantClientAuth was expected to be false but wasn't");
97+
}
98+
99+
/**
100+
* sets {@link HttpsParameters#setNeedClientAuth(boolean)} and verifies
101+
* that subsequent calls to {@link HttpsParameters#getNeedClientAuth()} returns
102+
* the set value and {@link HttpsParameters#getWantClientAuth()} returns false
103+
*/
104+
@ParameterizedTest
105+
@ValueSource(booleans = {true, false})
106+
public void testNeedClientAuth(final boolean initialWantClientAuth) throws Exception {
107+
HttpsParameters needClientAuthParams = new Params();
108+
// first set wantClientAuth to an initial value to verify that it later gets reset
109+
needClientAuthParams.setWantClientAuth(initialWantClientAuth);
110+
// needClientAuth = true and thus wantClientAuth = false
111+
needClientAuthParams.setNeedClientAuth(true);
112+
assertTrue(needClientAuthParams.getNeedClientAuth(),
113+
"needClientAuth was expected to be true but wasn't");
114+
assertFalse(needClientAuthParams.getWantClientAuth(),
115+
"wantClientAuth was expected to be false but wasn't");
116+
// now set needClientAuth = false and verify that both needClientAuth and wantClientAuth
117+
// are now false
118+
needClientAuthParams.setNeedClientAuth(false);
119+
assertFalse(needClientAuthParams.getNeedClientAuth(),
120+
"needClientAuth was expected to be false but wasn't");
121+
assertFalse(needClientAuthParams.getWantClientAuth(),
122+
"wantClientAuth was expected to be false but wasn't");
123+
}
124+
125+
/**
126+
* sets {@link HttpsParameters#setWantClientAuth(boolean)} and verifies
127+
* that subsequent calls to {@link HttpsParameters#getWantClientAuth()} returns
128+
* the set value and {@link HttpsParameters#getNeedClientAuth()} returns false
129+
*/
130+
@ParameterizedTest
131+
@ValueSource(booleans = {true, false})
132+
public void testWantClientAuth(final boolean initialNeedClientAuth) throws Exception {
133+
HttpsParameters wantClientAuthParams = new Params();
134+
// first set needClientAuth to an initial value to verify that it later gets reset
135+
wantClientAuthParams.setNeedClientAuth(initialNeedClientAuth);
136+
// wantClientAuth = true and thus needClientAuth = false
137+
wantClientAuthParams.setWantClientAuth(true);
138+
assertTrue(wantClientAuthParams.getWantClientAuth(),
139+
"wantClientAuth was expected to be true but wasn't");
140+
assertFalse(wantClientAuthParams.getNeedClientAuth(),
141+
"needClientAuth was expected to be false but wasn't");
142+
// now set wantClientAuth = false and verify that both wantClientAuth and needClientAuth
143+
// are now false
144+
wantClientAuthParams.setWantClientAuth(false);
145+
assertFalse(wantClientAuthParams.getWantClientAuth(),
146+
"wantClientAuth was expected to be false but wasn't");
147+
assertFalse(wantClientAuthParams.getNeedClientAuth(),
148+
"needClientAuth was expected to be false but wasn't");
149+
}
150+
151+
/**
152+
* Starts a {@link HttpsServer} by
153+
* {@linkplain HttpsParameters#setNeedClientAuth(boolean) setting needClientAuth} as
154+
* {@code true}. The client is then configured either to present the client certificates
155+
* during the TLS handshake or configured not to present them. In the case where the
156+
* client presents the client certificates, the HTTP request issued by the client is
157+
* expected to pass. In the other case where the client doesn't present the certificates,
158+
* the test verifies that the HTTP request fails due to a connection error
159+
* (caused by TLS handshake failure)
160+
*
161+
* @param presentClientCerts true if the client should present certificates
162+
* during TLS handshake, false otherwise
163+
*/
164+
@ParameterizedTest
165+
@ValueSource(booleans = {true, false})
166+
public void testServerNeedClientAuth(final boolean presentClientCerts) throws Exception {
167+
// SSLContext which contains both the key and the trust material and will be used
168+
// by the server
169+
final SSLContext serverSSLCtx = new SimpleSSLContext().get();
170+
assertNotNull(serverSSLCtx, "could not create SSLContext");
171+
final HttpsConfigurator configurator = new HttpsConfigurator(serverSSLCtx) {
172+
@Override
173+
public void configure(final HttpsParameters params) {
174+
// we intentionally don't call params.setSSLParameters()
175+
// and instead call params.setNeedClientAuth()
176+
params.setNeedClientAuth(true); // "require" the client to present certs
177+
}
178+
};
179+
try (final ExecutorService executor = Executors.newCachedThreadPool(SRV_THREAD_FACTORY)) {
180+
final HttpsServer server = createHttpsServer(executor, configurator);
181+
server.start();
182+
System.out.println("started server at " + server.getAddress());
183+
try {
184+
final HttpClient.Builder builder = createClientBuilder();
185+
// if the client is expected to present client certificates, then
186+
// we construct a SSLContext which has both key and trust material.
187+
// otherwise we construct a SSLContext that only has trust material
188+
// and thus won't present certificates during TLS handshake
189+
final SSLContext clientSSLCtx = presentClientCerts
190+
? serverSSLCtx : onlyTrustStoreContext();
191+
// construct the client using the SSLContext
192+
try (final HttpClient client = builder.sslContext(clientSSLCtx)
193+
.build()) {
194+
// issue a request
195+
final URI reqURI = URIBuilder.newBuilder()
196+
.scheme("https")
197+
.host(server.getAddress().getAddress())
198+
.port(server.getAddress().getPort())
199+
.path("/")
200+
.build();
201+
System.out.println("issuing request to " + reqURI);
202+
final HttpResponse<Void> resp;
203+
try {
204+
resp = client.send(HttpRequest.newBuilder(reqURI).build(),
205+
BodyHandlers.discarding());
206+
if (!presentClientCerts) {
207+
// request was expected to fail since the server was configured to force
208+
// the client to present the client cert, but the client didn't
209+
// present any
210+
fail("request was expected to fail, but didn't");
211+
}
212+
assertEquals(200, resp.statusCode(), "unexpected response code");
213+
// verify the client did present the certs
214+
assertTrue(resp.sslSession().isPresent(), "missing SSLSession on response");
215+
assertNotNull(resp.sslSession().get().getLocalCertificates(),
216+
"client was expected to present certs to the server, but didn't");
217+
} catch (IOException ioe) {
218+
if (presentClientCerts) {
219+
// wasn't expected to fail, just let the exception propagate
220+
throw ioe;
221+
}
222+
// verify it failed due to right reason
223+
Throwable cause = ioe;
224+
while (cause != null) {
225+
// either of SocketException or SSLHandshakeException are OK
226+
if (cause instanceof SocketException se) {
227+
final String msg = se.getMessage();
228+
assertTrue(msg != null && msg.contains("Connection reset"),
229+
"unexpected message in SocketException: " + msg);
230+
System.out.println("received the expected exception: " + se);
231+
break;
232+
} else if (cause instanceof SSLHandshakeException she) {
233+
final String msg = she.getMessage();
234+
assertTrue(msg != null && msg.contains("certificate_required"),
235+
"unexpected message in SSLHandshakeException: " + msg);
236+
System.out.println("received the expected exception: " + she);
237+
break;
238+
}
239+
cause = cause.getCause();
240+
}
241+
if (cause == null) {
242+
// didn't find expected exception, rethrow original exception
243+
throw ioe;
244+
}
245+
}
246+
}
247+
} finally {
248+
System.out.println("Stopping server at " + server.getAddress());
249+
server.stop(0 /* delay */);
250+
}
251+
}
252+
}
253+
254+
/**
255+
* Starts a {@link HttpsServer} by
256+
* {@linkplain HttpsParameters#setWantClientAuth(boolean) setting wantClientAuth} as
257+
* {@code true}. The client is then configured to either present the client certificates
258+
* during the TLS handshake or configured not to present them. In both these cases the
259+
* HTTP request issued by the client is expected to pass.
260+
*
261+
* @param presentClientCerts true if the client should present certificates
262+
* during TLS handshake, false otherwise
263+
*/
264+
@ParameterizedTest
265+
@ValueSource(booleans = {true, false})
266+
public void testServerWantClientAuth(final boolean presentClientCerts) throws Exception {
267+
// SSLContext which contains both the key and the trust material and will be used
268+
// by the server
269+
final SSLContext serverSSLCtx = new SimpleSSLContext().get();
270+
assertNotNull(serverSSLCtx, "could not create SSLContext");
271+
final HttpsConfigurator configurator = new HttpsConfigurator(serverSSLCtx) {
272+
@Override
273+
public void configure(final HttpsParameters params) {
274+
// we intentionally don't call params.setSSLParameters()
275+
// and instead call params.setWantClientAuth()
276+
params.setWantClientAuth(true); // "request" the client to present certs
277+
}
278+
};
279+
try (final ExecutorService executor = Executors.newCachedThreadPool(SRV_THREAD_FACTORY)) {
280+
final HttpsServer server = createHttpsServer(executor, configurator);
281+
server.start();
282+
System.out.println("started server at " + server.getAddress());
283+
try {
284+
final HttpClient.Builder builder = createClientBuilder();
285+
// if the client is expected to present client certificates, then
286+
// we construct a SSLContext which has both key and trust material.
287+
// otherwise we construct a SSLContext that only has trust material
288+
// and thus won't present certificates during TLS handshake
289+
final SSLContext clientSSLCtx = presentClientCerts
290+
? serverSSLCtx : onlyTrustStoreContext();
291+
// construct the client using the SSLContext
292+
try (final HttpClient client = builder.sslContext(clientSSLCtx)
293+
.build()) {
294+
// issue a request
295+
final URI reqURI = URIBuilder.newBuilder()
296+
.scheme("https")
297+
.host(server.getAddress().getAddress())
298+
.port(server.getAddress().getPort())
299+
.path("/")
300+
.build();
301+
System.out.println("issuing request to " + reqURI);
302+
final HttpResponse<Void> resp = client.send(
303+
HttpRequest.newBuilder(reqURI).build(), BodyHandlers.discarding());
304+
assertEquals(200, resp.statusCode(), "unexpected response code");
305+
if (presentClientCerts) {
306+
// verify the client did present the certs
307+
assertTrue(resp.sslSession().isPresent(), "missing SSLSession on response");
308+
assertNotNull(resp.sslSession().get().getLocalCertificates(),
309+
"client was expected to present certs to the server, but didn't");
310+
}
311+
}
312+
} finally {
313+
System.out.println("Stopping server at " + server.getAddress());
314+
server.stop(0 /* delay */);
315+
}
316+
}
317+
}
318+
319+
private static HttpsServer createHttpsServer(final Executor executor,
320+
final HttpsConfigurator configurator)
321+
throws IOException {
322+
final InetAddress loopback = InetAddress.getLoopbackAddress();
323+
final HttpsServer server = HttpsServer.create(
324+
new InetSocketAddress(loopback, 0), 0 /* backlog */);
325+
server.setExecutor(executor);
326+
server.setHttpsConfigurator(configurator);
327+
server.createContext("/", new AllOKHandler());
328+
return server;
329+
}
330+
331+
private static HttpClient.Builder createClientBuilder() {
332+
return HttpClient.newBuilder().version(HTTP_1_1)
333+
.proxy(NO_PROXY);
334+
}
335+
336+
/**
337+
* Creates and returns a {@link SSLContext} which only has trust material
338+
* and doesn't have any test specific keys.
339+
*/
340+
private static SSLContext onlyTrustStoreContext() throws Exception {
341+
final KeyStore keyStore = loadTestKeyStore();
342+
final TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
343+
tmf.init(keyStore);
344+
final SSLContext ctx = SSLContext.getInstance("TLS");
345+
// initialize with only trust managers
346+
ctx.init(null, tmf.getTrustManagers(), null);
347+
return ctx;
348+
}
349+
350+
private static KeyStore loadTestKeyStore() throws Exception {
351+
return AccessController.doPrivileged(
352+
new PrivilegedExceptionAction<KeyStore>() {
353+
@Override
354+
public KeyStore run() throws Exception {
355+
final String testKeys = System.getProperty("test.src")
356+
+ "/"
357+
+ "../../../../../../test/lib/jdk/test/lib/net/testkeys";
358+
try (final FileInputStream fis = new FileInputStream(testKeys)) {
359+
final char[] passphrase = "passphrase".toCharArray();
360+
final KeyStore ks = KeyStore.getInstance("PKCS12");
361+
ks.load(fis, passphrase);
362+
return ks;
363+
}
364+
}
365+
});
366+
}
367+
368+
// no-op implementations of the abstract methods of HttpsParameters
369+
private static final class Params extends HttpsParameters {
370+
371+
@Override
372+
public HttpsConfigurator getHttpsConfigurator() {
373+
// no-op
374+
return null;
375+
}
376+
377+
@Override
378+
public InetSocketAddress getClientAddress() {
379+
// no-op
380+
return null;
381+
}
382+
383+
@Override
384+
public void setSSLParameters(SSLParameters params) {
385+
// no-op
386+
}
387+
}
388+
389+
// A HttpHandler which just returns 200 response code
390+
private static final class AllOKHandler implements HttpHandler {
391+
392+
private static final int NO_RESPONSE_BODY = -1;
393+
394+
@Override
395+
public void handle(final HttpExchange exchange) throws IOException {
396+
System.out.println("responding to request: " + exchange.getRequestURI());
397+
exchange.sendResponseHeaders(200, NO_RESPONSE_BODY);
398+
}
399+
}
400+
}

1 commit comments

Comments
 (1)

openjdk-notifier[bot] commented on Mar 10, 2024

@openjdk-notifier[bot]
Please sign in to comment.