My first thought is that if you are computing the string maybe you'd want to look at the request. Or set a header for content type.
I'm not going to push hard until valhalla is at least in preview (+ we've already talked it to death) but a Body abstraction would probably solve your use-case more robustly than yet another method there. exchange -> exchange.sendResponse(200, Body.of("example")); On Mon, Apr 28, 2025 at 5:28 AM Pavel Rappo <pavel.ra...@gmail.com> wrote: > 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 >