New convenience HttpHandler
Pavel Rappo
pavel.rappo at gmail.com
Sun Apr 27 15:11:06 UTC 2025
I'm using HttpServer to implement an HTTP probe [^1] that provides
application state at the time of probing. I find that convenience
handlers provided by HttpHandlers are insufficient for my use case. I
also find that implementing a custom HttpHandler is tricky without the
help of documentation.
Perhaps my use case is typical enough so that HttpHandlers could
provide a new convenience handler. That handler would send a
dynamically supplied string, rather than a static string. If you also
find it useful, I'd appreciate it if we could discuss it. Before I
create a JBS issue, please have a look at this crude patch to see if
it makes sense to you in principle. Thanks.
[^1]: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/
diff --git a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpHandlers.java
b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpHandlers.java
index 03642033914..987de0ede5d 100644
--- a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpHandlers.java
+++ b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpHandlers.java
@@ -25,9 +25,11 @@
package com.sun.net.httpserver;
+import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
import java.util.function.Predicate;
+import java.util.function.Supplier;
/**
* Implementations of {@link com.sun.net.httpserver.HttpHandler HttpHandler}
@@ -140,28 +142,60 @@ public static HttpHandler
handleOrElse(Predicate<Request> handlerTest,
* @throws NullPointerException if headers or body are null
*/
public static HttpHandler of(int statusCode, Headers headers,
String body) {
+ Objects.requireNonNull(body);
+ return of(statusCode, headers, () -> body);
+ }
+
+ /**
+ * Returns an {@code HttpHandler} that sends a response
comprising the given
+ * {@code statusCode}, {@code headers}, and {@code body}.
+ *
+ * <p> This method creates a handler that reads and discards the request
+ * body before it sets the response state and sends the response.
+ *
+ * <p> {@code headers} are the effective headers of the response. The
+ * response <i>body bytes</i> are a {@code UTF-8} encoded byte sequence of
+ * a string, which is supplied by {@code bodySupplier}
immediately after the request body is read. The response headers
+ * {@linkplain HttpExchange#sendResponseHeaders(int, long) are sent} with
+ * the given {@code statusCode} and the body bytes' length (or {@code -1}
+ * if the body is empty). The body bytes are then sent as response body,
+ * unless the body is empty, in which case no response body is sent.
+ *
+ * @param statusCode a response status code
+ * @param headers a headers
+ * @param bodySupplier a supplier for the response body string
+ * @return a handler
+ * @throws IllegalArgumentException if statusCode is not a positive 3-digit
+ * integer, as per rfc2616, section 6.1.1
+ * @throws NullPointerException if headers or body are null
+ */
+ public static HttpHandler of(int statusCode, Headers headers,
Supplier<String> bodySupplier) {
if (statusCode < 100 || statusCode > 999)
throw new IllegalArgumentException("statusCode must be 3-digit: "
+ statusCode);
Objects.requireNonNull(headers);
- Objects.requireNonNull(body);
+ Objects.requireNonNull(bodySupplier);
final var headersCopy = Headers.of(headers);
- final var bytes = body.getBytes(StandardCharsets.UTF_8);
return exchange -> {
try (exchange) {
- exchange.getRequestBody().readAllBytes();
+
exchange.getRequestBody().transferTo(OutputStream.nullOutputStream());
// discard
exchange.getResponseHeaders().putAll(headersCopy);
- if (exchange.getRequestMethod().equals("HEAD")) {
-
exchange.getResponseHeaders().set("Content-Length",
Integer.toString(bytes.length));
- exchange.sendResponseHeaders(statusCode, -1);
- }
- else if (bytes.length == 0) {
- exchange.sendResponseHeaders(statusCode, -1);
+ var body = bodySupplier.get();
+ if (body == null) {
+ exchange.sendResponseHeaders(500, -1); //
Internal Server Error
} else {
- exchange.sendResponseHeaders(statusCode, bytes.length);
- exchange.getResponseBody().write(bytes);
+ final var bytes = body.getBytes(StandardCharsets.UTF_8);
+ if (exchange.getRequestMethod().equals("HEAD")) {
+
exchange.getResponseHeaders().set("Content-Length",
Integer.toString(bytes.length));
+ exchange.sendResponseHeaders(statusCode, -1);
+ } else if (bytes.length == 0) {
+ exchange.sendResponseHeaders(statusCode, -1);
+ } else {
+ exchange.sendResponseHeaders(statusCode, bytes.length);
+ exchange.getResponseBody().write(bytes);
+ }
}
}
};
diff --git a/test/jdk/com/sun/net/httpserver/simpleserver/HttpHandlersTest.java
b/test/jdk/com/sun/net/httpserver/simpleserver/HttpHandlersTest.java
index 85d271e44fa..d64fa03740f 100644
--- a/test/jdk/com/sun/net/httpserver/simpleserver/HttpHandlersTest.java
+++ b/test/jdk/com/sun/net/httpserver/simpleserver/HttpHandlersTest.java
@@ -81,7 +81,7 @@ public void testNull() {
final var headers = new Headers();
final var body = "";
assertThrows(NPE, () -> HttpHandlers.of(200, null, body));
- assertThrows(NPE, () -> HttpHandlers.of(200, headers, null));
+ assertThrows(NPE, () -> HttpHandlers.of(200, headers, (String) null));
}
@Test
More information about the net-dev
mailing list