8278353: Provide Duke as default favicon in Simple Web Server

Reviewed-by: dfuchs
This commit is contained in:
Christian Stein 2024-05-08 05:48:07 +00:00
parent 466a21d864
commit 7b79426a1d
4 changed files with 104 additions and 4 deletions

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@ -24,3 +24,5 @@
#
DISABLED_WARNINGS_java += missing-explicit-ctor this-escape
COPY += .ico

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -57,6 +57,9 @@ public final class FileServerHandler implements HttpHandler {
private static final List<String> SUPPORTED_METHODS = List.of("HEAD", "GET");
private static final List<String> UNSUPPORTED_METHODS =
List.of("CONNECT", "DELETE", "OPTIONS", "PATCH", "POST", "PUT", "TRACE");
private static final String FAVICON_RESOURCE_PATH =
"/sun/net/httpserver/simpleserver/resources/favicon.ico";
private static final String FAVICON_LAST_MODIFIED = "Mon, 23 May 1995 11:11:11 GMT";
private final Path root;
private final UnaryOperator<String> mimeTable;
@ -250,6 +253,31 @@ public final class FileServerHandler implements HttpHandler {
return Files.exists(html) ? html : Files.exists(htm) ? htm : null;
}
private static boolean isFavIconRequest(HttpExchange exchange) {
return "/favicon.ico".equals(exchange.getRequestURI().getPath());
}
private void serveDefaultFavIcon(HttpExchange exchange, boolean writeBody)
throws IOException
{
var respHdrs = exchange.getResponseHeaders();
try (var stream = getClass().getModule().getResourceAsStream(FAVICON_RESOURCE_PATH)) {
var bytes = stream.readAllBytes();
respHdrs.set("Content-Type", "image/x-icon");
respHdrs.set("Last-Modified", FAVICON_LAST_MODIFIED);
if (writeBody) {
exchange.sendResponseHeaders(200, bytes.length);
try (OutputStream os = exchange.getResponseBody()) {
os.write(bytes);
}
} else {
respHdrs.set("Content-Length", Integer.toString(bytes.length));
exchange.sendResponseHeaders(200, -1);
}
}
}
private void serveFile(HttpExchange exchange, Path path, boolean writeBody)
throws IOException
{
@ -371,17 +399,26 @@ public final class FileServerHandler implements HttpHandler {
assert List.of("GET", "HEAD").contains(exchange.getRequestMethod());
try (exchange) {
discardRequestBody(exchange);
boolean isHeadRequest = exchange.getRequestMethod().equals("HEAD");
Path path = mapToPath(exchange, root);
if (path != null) {
exchange.setAttribute("request-path", path.toString()); // store for OutputFilter
if (!Files.exists(path) || !Files.isReadable(path) || isHiddenOrSymLink(path)) {
handleNotFound(exchange);
} else if (exchange.getRequestMethod().equals("HEAD")) {
} else if (isHeadRequest) {
handleHEAD(exchange, path);
} else {
handleGET(exchange, path);
}
} else {
if (isFavIconRequest(exchange)) {
try {
serveDefaultFavIcon(exchange, !isHeadRequest);
return;
} catch (IOException ignore) {
// fall through to send the not-found response
}
}
exchange.setAttribute("request-path", "could not resolve request URI path");
handleNotFound(exchange);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -76,6 +76,8 @@ public class SimpleFileServerTest {
static final boolean ENABLE_LOGGING = true;
static final Logger LOGGER = Logger.getLogger("com.sun.net.httpserver");
static final String EXPECTED_LAST_MODIFIED_OF_FAVICON = "Mon, 23 May 1995 11:11:11 GMT";
@BeforeTest
public void setup() throws IOException {
if (ENABLE_LOGGING) {
@ -142,6 +144,65 @@ public class SimpleFileServerTest {
}
}
@Test
public void testFavIconGET() throws Exception {
var root = Files.createDirectory(TEST_DIR.resolve("testFavIconGET"));
var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, OutputLevel.VERBOSE);
server.start();
try {
// expect built-in icon
var client = HttpClient.newBuilder().proxy(NO_PROXY).build();
var request = HttpRequest.newBuilder(uri(server, "favicon.ico")).build();
var response = client.send(request, BodyHandlers.ofString());
assertEquals(response.statusCode(), 200);
assertEquals(response.headers().firstValue("content-type").get(), "image/x-icon");
assertEquals(response.headers().firstValue("last-modified").get(), EXPECTED_LAST_MODIFIED_OF_FAVICON);
// expect custom (and broken) icon
var file = Files.writeString(root.resolve("favicon.ico"), "broken icon", CREATE);
try {
var lastModified = getLastModified(file);
var expectedLength = Long.toString(Files.size(file));
response = client.send(request, BodyHandlers.ofString());
assertEquals(response.statusCode(), 200);
assertEquals(response.headers().firstValue("content-type").get(), "application/octet-stream");
assertEquals(response.headers().firstValue("content-length").get(), expectedLength);
assertEquals(response.headers().firstValue("last-modified").get(), lastModified);
} finally {
Files.delete(file);
}
// expect built-in icon
response = client.send(request, BodyHandlers.ofString());
assertEquals(response.statusCode(), 200);
assertEquals(response.headers().firstValue("content-type").get(), "image/x-icon");
assertEquals(response.headers().firstValue("last-modified").get(), EXPECTED_LAST_MODIFIED_OF_FAVICON);
} finally {
server.stop(0);
}
}
@Test
public void testFavIconHEAD() throws Exception {
var root = Files.createDirectory(TEST_DIR.resolve("testFavIconHEAD"));
var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, OutputLevel.VERBOSE);
server.start();
try {
var client = HttpClient.newBuilder().proxy(NO_PROXY).build();
var request = HttpRequest.newBuilder(uri(server, "favicon.ico"))
.method("HEAD", BodyPublishers.noBody()).build();
var response = client.send(request, BodyHandlers.ofString());
assertEquals(response.statusCode(), 200);
assertEquals(response.headers().firstValue("content-type").get(), "image/x-icon");
assertEquals(response.headers().firstValue("last-modified").get(), EXPECTED_LAST_MODIFIED_OF_FAVICON);
assertEquals(response.body(), "");
} finally {
server.stop(0);
}
}
@Test
public void testFileHEAD() throws Exception {
var root = Files.createDirectory(TEST_DIR.resolve("testFileHEAD"));