diff --git a/examples/nima/media/src/main/java/io/helidon/examples/nima/media/MediaMain.java b/examples/nima/media/src/main/java/io/helidon/examples/nima/media/MediaMain.java index e7967d5ee71..bde50587eb5 100644 --- a/examples/nima/media/src/main/java/io/helidon/examples/nima/media/MediaMain.java +++ b/examples/nima/media/src/main/java/io/helidon/examples/nima/media/MediaMain.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Oracle and/or its affiliates. + * Copyright (c) 2022, 2023 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +20,7 @@ import io.helidon.common.http.Http.Header; import io.helidon.nima.webserver.WebServer; import io.helidon.nima.webserver.http.HttpRules; -import io.helidon.nima.webserver.staticcontent.StaticContentSupport; +import io.helidon.nima.webserver.staticcontent.StaticContentService; /** * This application provides a simple file upload service with a UI to exercise multipart. @@ -56,7 +56,7 @@ static void routing(HttpRules rules) { res.header(UI_LOCATION); res.send(); }) - .register("/ui", StaticContentSupport.builder("WEB") + .register("/ui", StaticContentService.builder("WEB") .welcomeFileName("index.html") .build()) .register("/api", new FileService()); diff --git a/examples/nima/static-content/src/main/java/io/helidon/examples/nima/staticcontent/StaticContentMain.java b/examples/nima/static-content/src/main/java/io/helidon/examples/nima/staticcontent/StaticContentMain.java index 9370cb5df14..7a011f17d6f 100644 --- a/examples/nima/static-content/src/main/java/io/helidon/examples/nima/staticcontent/StaticContentMain.java +++ b/examples/nima/static-content/src/main/java/io/helidon/examples/nima/staticcontent/StaticContentMain.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Oracle and/or its affiliates. + * Copyright (c) 2022, 2023 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,7 +18,7 @@ import io.helidon.nima.webserver.WebServer; import io.helidon.nima.webserver.http.HttpRouting; -import io.helidon.nima.webserver.staticcontent.StaticContentSupport; +import io.helidon.nima.webserver.staticcontent.StaticContentService; /** * Static content example. @@ -45,7 +45,7 @@ public static void main(String[] args) { static void routing(HttpRouting.Builder routing) { // register static content on root path of the server // use classpath /web to look for resources - routing.register("/", StaticContentSupport.builder("web")) + routing.register("/", StaticContentService.builder("web")) .get("/api/greet", (req, res) -> res.send("Hello World!")); } } diff --git a/microprofile/server/src/main/java/io/helidon/microprofile/server/ServerCdiExtension.java b/microprofile/server/src/main/java/io/helidon/microprofile/server/ServerCdiExtension.java index 99083f89956..4aa7d73f1ef 100644 --- a/microprofile/server/src/main/java/io/helidon/microprofile/server/ServerCdiExtension.java +++ b/microprofile/server/src/main/java/io/helidon/microprofile/server/ServerCdiExtension.java @@ -43,7 +43,7 @@ import io.helidon.nima.webserver.context.ContextFeature; import io.helidon.nima.webserver.http.HttpRouting; import io.helidon.nima.webserver.http.HttpService; -import io.helidon.nima.webserver.staticcontent.StaticContentSupport; +import io.helidon.nima.webserver.staticcontent.StaticContentService; import jakarta.annotation.Priority; import jakarta.enterprise.context.ApplicationScoped; @@ -421,14 +421,14 @@ private void registerStaticContent() { private void registerPathStaticContent(Config config) { Config context = config.get("context"); - StaticContentSupport.FileSystemBuilder pBuilder = StaticContentSupport.builder(config.get("location") + StaticContentService.FileSystemBuilder pBuilder = StaticContentService.builder(config.get("location") .as(Path.class) .get()); pBuilder.welcomeFileName(config.get("welcome") .asString() .orElse("index.html")); - StaticContentSupport staticContent = pBuilder.build(); + StaticContentService staticContent = pBuilder.build(); if (context.exists()) { routingBuilder.register(context.asString().get(), staticContent); @@ -441,7 +441,7 @@ private void registerPathStaticContent(Config config) { private void registerClasspathStaticContent(Config config) { Config context = config.get("context"); - StaticContentSupport.ClassPathBuilder cpBuilder = StaticContentSupport.builder(config.get("location").asString().get()); + StaticContentService.ClassPathBuilder cpBuilder = StaticContentService.builder(config.get("location").asString().get()); cpBuilder.welcomeFileName(config.get("welcome") .asString() .orElse("index.html")); @@ -455,7 +455,7 @@ private void registerClasspathStaticContent(Config config) { .flatMap(List::stream) .forEach(cpBuilder::addCacheInMemory); - StaticContentSupport staticContent = cpBuilder.build(); + StaticContentService staticContent = cpBuilder.build(); if (context.exists()) { routingBuilder.register(context.asString().get(), staticContent); diff --git a/nima/tests/integration/webserver/static-content/src/test/java/io/helidon/nima/tests/integration/server/staticcontent/StaticContentTest.java b/nima/tests/integration/webserver/static-content/src/test/java/io/helidon/nima/tests/integration/server/staticcontent/StaticContentTest.java index 3d307d9e014..4f72bf35d64 100644 --- a/nima/tests/integration/webserver/static-content/src/test/java/io/helidon/nima/tests/integration/server/staticcontent/StaticContentTest.java +++ b/nima/tests/integration/webserver/static-content/src/test/java/io/helidon/nima/tests/integration/server/staticcontent/StaticContentTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Oracle and/or its affiliates. + * Copyright (c) 2022, 2023 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,7 +22,7 @@ import io.helidon.nima.webclient.http1.Http1Client; import io.helidon.nima.webclient.http1.Http1ClientResponse; import io.helidon.nima.webserver.http.HttpRouting; -import io.helidon.nima.webserver.staticcontent.StaticContentSupport; +import io.helidon.nima.webserver.staticcontent.StaticContentService; import org.junit.jupiter.api.Test; @@ -39,7 +39,7 @@ class StaticContentTest { @SetUpRoute static void routing(HttpRouting.Builder routing) { - routing.register("/files", StaticContentSupport.builder("static") + routing.register("/files", StaticContentService.builder("static") .welcomeFileName("welcome.txt") .build()) .get("/files/default", (req, res) -> res.send("Nexted")); diff --git a/nima/webserver/static-content/src/main/java/io/helidon/nima/webserver/staticcontent/ClassPathContentHandler.java b/nima/webserver/static-content/src/main/java/io/helidon/nima/webserver/staticcontent/ClassPathContentHandler.java index e2c04769638..6e53d5ee56b 100644 --- a/nima/webserver/static-content/src/main/java/io/helidon/nima/webserver/staticcontent/ClassPathContentHandler.java +++ b/nima/webserver/static-content/src/main/java/io/helidon/nima/webserver/staticcontent/ClassPathContentHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022 Oracle and/or its affiliates. + * Copyright (c) 2017, 2023 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -61,7 +61,7 @@ class ClassPathContentHandler extends FileBasedContentHandler { // URL's hash code and equal are not suitable for map or set private final Map extracted = new ConcurrentHashMap<>(); - ClassPathContentHandler(StaticContentSupport.ClassPathBuilder builder) { + ClassPathContentHandler(StaticContentService.ClassPathBuilder builder) { super(builder); this.classLoader = builder.classLoader(); diff --git a/nima/webserver/static-content/src/main/java/io/helidon/nima/webserver/staticcontent/FileBasedContentHandler.java b/nima/webserver/static-content/src/main/java/io/helidon/nima/webserver/staticcontent/FileBasedContentHandler.java index 2f98b22dfe4..8043598fcd2 100644 --- a/nima/webserver/static-content/src/main/java/io/helidon/nima/webserver/staticcontent/FileBasedContentHandler.java +++ b/nima/webserver/static-content/src/main/java/io/helidon/nima/webserver/staticcontent/FileBasedContentHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2022 Oracle and/or its affiliates. + * Copyright (c) 2021, 2023 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -43,7 +43,7 @@ abstract class FileBasedContentHandler extends StaticContentHandler { private final Map customMediaTypes; - FileBasedContentHandler(StaticContentSupport.FileBasedBuilder builder) { + FileBasedContentHandler(StaticContentService.FileBasedBuilder builder) { super(builder); this.customMediaTypes = builder.specificContentTypes(); diff --git a/nima/webserver/static-content/src/main/java/io/helidon/nima/webserver/staticcontent/FileSystemContentHandler.java b/nima/webserver/static-content/src/main/java/io/helidon/nima/webserver/staticcontent/FileSystemContentHandler.java index d1ab42bb424..e95adcf5a8f 100644 --- a/nima/webserver/static-content/src/main/java/io/helidon/nima/webserver/staticcontent/FileSystemContentHandler.java +++ b/nima/webserver/static-content/src/main/java/io/helidon/nima/webserver/staticcontent/FileSystemContentHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022 Oracle and/or its affiliates. + * Copyright (c) 2017, 2023 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,7 +18,6 @@ import java.io.IOException; import java.lang.System.Logger.Level; -import java.net.URISyntaxException; import java.nio.file.Files; import java.nio.file.Path; import java.util.HashSet; @@ -41,7 +40,7 @@ class FileSystemContentHandler extends FileBasedContentHandler { private final Path root; private final Set cacheInMemory; - FileSystemContentHandler(StaticContentSupport.FileSystemBuilder builder) { + FileSystemContentHandler(StaticContentService.FileSystemBuilder builder) { super(builder); this.root = builder.root().toAbsolutePath().normalize(); @@ -148,7 +147,7 @@ boolean doHandle(Http.Method method, return handler.handle(handlerCache(), method, req, res, requestedResource); } - private void addToInMemoryCache(String resource) throws IOException, URISyntaxException { + private void addToInMemoryCache(String resource) throws IOException { /* we need to know: - content size diff --git a/nima/webserver/static-content/src/main/java/io/helidon/nima/webserver/staticcontent/SingleFileContentHandler.java b/nima/webserver/static-content/src/main/java/io/helidon/nima/webserver/staticcontent/SingleFileContentHandler.java new file mode 100644 index 00000000000..5439090d9a2 --- /dev/null +++ b/nima/webserver/static-content/src/main/java/io/helidon/nima/webserver/staticcontent/SingleFileContentHandler.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2023 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.helidon.nima.webserver.staticcontent; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Optional; + +import io.helidon.common.http.Http; +import io.helidon.common.http.ServerResponseHeaders; +import io.helidon.nima.webserver.http.ServerRequest; +import io.helidon.nima.webserver.http.ServerResponse; + +class SingleFileContentHandler extends FileBasedContentHandler { + private static final System.Logger LOGGER = System.getLogger(SingleFileContentHandler.class.getName()); + + private final boolean cacheInMemory; + private final Path path; + + SingleFileContentHandler(FileSystemBuilder builder) { + super(builder); + + this.cacheInMemory = builder.cacheInMemory().contains(".") || builder.cacheInMemory().contains("/"); + this.path = builder.root().toAbsolutePath().normalize(); + } + + @Override + public void beforeStart() { + try { + if (cacheInMemory) { + // directly cache in memory + byte[] fileBytes = Files.readAllBytes(path); + cacheInMemory(".", detectType(fileName(path)), fileBytes, lastModified(path)); + } else { + // cache a handler that loads it from file system + cacheFileHandler(); + } + } catch (IOException e) { + LOGGER.log(System.Logger.Level.WARNING, "Failed to add file to in-memory cache, path: " + path, e); + } + super.beforeStart(); + } + + @Override + boolean doHandle(Http.Method method, String requestedPath, ServerRequest req, ServerResponse res) throws IOException { + if ("".equals(requestedPath) || "/".equals(requestedPath)) { + Optional cachedHandler = cacheHandler("."); + if (cachedHandler.isPresent()) { + return cachedHandler.get().handle(handlerCache(), method, req, res, requestedPath); + } + return doHandle(method, req, res); + } + + if (LOGGER.isLoggable(System.Logger.Level.DEBUG)) { + LOGGER.log(System.Logger.Level.DEBUG, "Requested sub-path for a single file static content: " + requestedPath); + } + return false; + } + + private boolean doHandle(Http.Method method, ServerRequest req, ServerResponse res) throws IOException { + return cacheFileHandler().handle(handlerCache(), method, req, res, "."); + } + + private CachedHandler cacheFileHandler() { + CachedHandler handler = new CachedHandlerPath(path, + detectType(fileName(path)), + FileBasedContentHandler::lastModified, + ServerResponseHeaders::lastModified); + cacheHandler(".", handler); + + return handler; + } +} diff --git a/nima/webserver/static-content/src/main/java/io/helidon/nima/webserver/staticcontent/StaticContentHandler.java b/nima/webserver/static-content/src/main/java/io/helidon/nima/webserver/staticcontent/StaticContentHandler.java index ba11bceb33f..05814a8197d 100644 --- a/nima/webserver/static-content/src/main/java/io/helidon/nima/webserver/staticcontent/StaticContentHandler.java +++ b/nima/webserver/static-content/src/main/java/io/helidon/nima/webserver/staticcontent/StaticContentHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022 Oracle and/or its affiliates. + * Copyright (c) 2017, 2023 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -48,7 +48,7 @@ /** * Base implementation of static content support. */ -abstract class StaticContentHandler implements StaticContentSupport { +abstract class StaticContentHandler implements StaticContentService { private static final System.Logger LOGGER = System.getLogger(StaticContentHandler.class.getName()); private final Map inMemoryCache = new ConcurrentHashMap<>(); @@ -57,7 +57,7 @@ abstract class StaticContentHandler implements StaticContentSupport { private final Function resolvePathFunction; private final AtomicInteger webServerCounter = new AtomicInteger(); - StaticContentHandler(StaticContentSupport.Builder builder) { + StaticContentHandler(StaticContentService.Builder builder) { this.welcomeFilename = builder.welcomeFileName(); this.resolvePathFunction = builder.resolvePathFunction(); this.handlerCache = builder.handlerCache(); diff --git a/nima/webserver/static-content/src/main/java/io/helidon/nima/webserver/staticcontent/StaticContentSupport.java b/nima/webserver/static-content/src/main/java/io/helidon/nima/webserver/staticcontent/StaticContentService.java similarity index 94% rename from nima/webserver/static-content/src/main/java/io/helidon/nima/webserver/staticcontent/StaticContentSupport.java rename to nima/webserver/static-content/src/main/java/io/helidon/nima/webserver/staticcontent/StaticContentService.java index ef60ba614b8..7819c127ab4 100644 --- a/nima/webserver/static-content/src/main/java/io/helidon/nima/webserver/staticcontent/StaticContentSupport.java +++ b/nima/webserver/static-content/src/main/java/io/helidon/nima/webserver/staticcontent/StaticContentService.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022 Oracle and/or its affiliates. + * Copyright (c) 2017, 2023 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -43,7 +43,7 @@ *

* Content is served ONLY on HTTP {@code GET} method. */ -public interface StaticContentSupport extends HttpService { +public interface StaticContentService extends HttpService { /** * Creates new builder with defined static content root as a class-loader resource. Builder provides ability to define * more advanced configuration. @@ -98,7 +98,7 @@ static FileSystemBuilder builder(Path root) { * @return created instance * @throws NullPointerException if {@code resourceRoot} attribute is {@code null} */ - static StaticContentSupport create(String resourceRoot) { + static StaticContentService create(String resourceRoot) { return create(resourceRoot, Thread.currentThread().getContextClassLoader()); } @@ -110,7 +110,7 @@ static StaticContentSupport create(String resourceRoot) { * @return created instance * @throws NullPointerException if {@code resourceRoot} attribute is {@code null} */ - static StaticContentSupport create(String resourceRoot, ClassLoader classLoader) { + static StaticContentService create(String resourceRoot, ClassLoader classLoader) { return builder(resourceRoot, classLoader).build(); } @@ -121,7 +121,7 @@ static StaticContentSupport create(String resourceRoot, ClassLoader classLoader) * @return created instance * @throws NullPointerException if {@code root} attribute is {@code null} */ - static StaticContentSupport create(Path root) { + static StaticContentService create(Path root) { return builder(root).build(); } @@ -130,8 +130,7 @@ static StaticContentSupport create(Path root) { * * @param type of a subclass of a concrete builder */ - @SuppressWarnings("unchecked") - abstract class Builder> implements io.helidon.common.Builder { + abstract class Builder> implements io.helidon.common.Builder { private String welcomeFileName; private Function resolvePathFunction = Function.identity(); private Set cacheInMemory = new HashSet<>(); @@ -145,7 +144,7 @@ protected Builder() { } @Override - public final StaticContentSupport build() { + public final StaticContentService build() { return doBuild(); } @@ -218,7 +217,7 @@ public B recordCacheCapacity(int capacity) { * * @return static content support */ - protected abstract StaticContentSupport doBuild(); + protected abstract StaticContentService doBuild(); String welcomeFileName() { return welcomeFileName; @@ -311,7 +310,7 @@ public ClassPathBuilder tmpDir(Path tmpDir) { } @Override - protected StaticContentSupport doBuild() { + protected StaticContentService doBuild() { return new ClassPathContentHandler(this); } @@ -365,21 +364,25 @@ protected FileSystemBuilder() { } @Override - protected StaticContentSupport doBuild() { + protected StaticContentService doBuild() { if (root == null) { throw new NullPointerException("Root path must be defined"); } - return new FileSystemContentHandler(this); + if (Files.isDirectory(root)) { + return new FileSystemContentHandler(this); + } else { + return new SingleFileContentHandler(this); + } } FileSystemBuilder root(Path root) { Objects.requireNonNull(root, "Attribute root is null!"); this.root = root.toAbsolutePath().normalize(); - if (!(Files.exists(this.root) && Files.isDirectory(this.root))) { + if (!(Files.exists(this.root))) { throw new IllegalArgumentException("Cannot create file system static content, path " + this.root - + " does not exist or is not a directory"); + + " does not exist."); } return this; } diff --git a/nima/webserver/static-content/src/main/java/io/helidon/nima/webserver/staticcontent/package-info.java b/nima/webserver/static-content/src/main/java/io/helidon/nima/webserver/staticcontent/package-info.java index d49e77045a7..c505d3a438a 100644 --- a/nima/webserver/static-content/src/main/java/io/helidon/nima/webserver/staticcontent/package-info.java +++ b/nima/webserver/static-content/src/main/java/io/helidon/nima/webserver/staticcontent/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2022 Oracle and/or its affiliates. + * Copyright (c) 2021, 2023 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +17,6 @@ /** * Static content support for Helidon Níma {@link io.helidon.nima.webserver.WebServer}. *

- * The starting point is {@link io.helidon.nima.webserver.staticcontent.StaticContentSupport}. + * The starting point is {@link io.helidon.nima.webserver.staticcontent.StaticContentService}. */ package io.helidon.nima.webserver.staticcontent; diff --git a/nima/webserver/static-content/src/main/java/module-info.java b/nima/webserver/static-content/src/main/java/module-info.java index b78c0e7afa8..8a638345fff 100644 --- a/nima/webserver/static-content/src/main/java/module-info.java +++ b/nima/webserver/static-content/src/main/java/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Oracle and/or its affiliates. + * Copyright (c) 2022, 2023 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,16 +21,14 @@ * Helidon Níma WebServer static content support. */ @Feature(value = "Nima Static Content", - description = "Static content support for WebServer", - in = HelidonFlavor.NIMA, - invalidIn = HelidonFlavor.SE, - path = {"WebServer", "Static Content"} + description = "Static content support for WebServer", + in = HelidonFlavor.NIMA, + invalidIn = HelidonFlavor.SE, + path = {"WebServer", "Static Content"} ) module io.helidon.nima.webserver.staticcontent { requires static io.helidon.common.features.api; - requires java.logging; - requires transitive io.helidon.nima.webserver; requires transitive io.helidon.common.configurable; diff --git a/nima/webserver/static-content/src/test/java/io/helidon/nima/webserver/staticcontent/CachedHandlerTest.java b/nima/webserver/static-content/src/test/java/io/helidon/nima/webserver/staticcontent/CachedHandlerTest.java index e28bd55739e..01dc534d36c 100644 --- a/nima/webserver/static-content/src/test/java/io/helidon/nima/webserver/staticcontent/CachedHandlerTest.java +++ b/nima/webserver/static-content/src/test/java/io/helidon/nima/webserver/staticcontent/CachedHandlerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Oracle and/or its affiliates. + * Copyright (c) 2022, 2023 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -56,13 +56,13 @@ class CachedHandlerTest { @BeforeAll static void initTestClass() { - classpathHandler = (ClassPathContentHandler) StaticContentSupport.builder("/web") + classpathHandler = (ClassPathContentHandler) StaticContentService.builder("/web") .addCacheInMemory("favicon.ico") .welcomeFileName("resource.txt") .build(); classpathHandler.beforeStart(); - fsHandler = (FileSystemContentHandler) StaticContentSupport.builder(Paths.get("./src/test/resources/web")) + fsHandler = (FileSystemContentHandler) StaticContentService.builder(Paths.get("./src/test/resources/web")) .addCacheInMemory("nested") .welcomeFileName("resource.txt") .build(); @@ -171,7 +171,8 @@ void testFsInMemoryCache() { CachedHandlerInMemory cached = cachedHandlerInMemory.get(); assertThat("Cached bytes must not be null", cached.bytes(), notNullValue()); assertThat("Cached bytes must not be empty", cached.bytes(), not(BufferData.EMPTY_BYTES)); - assertThat("Content length", cached.contentLength(), is(7)); + // content is: "Nested content" + assertThat("Content length", cached.contentLength(), is(14)); assertThat("Last modified", cached.lastModified(), notNullValue()); assertThat("Media type", cached.mediaType(), is(MediaTypes.TEXT_PLAIN)); } diff --git a/nima/webserver/static-content/src/test/java/io/helidon/nima/webserver/staticcontent/StaticContentHandlerTest.java b/nima/webserver/static-content/src/test/java/io/helidon/nima/webserver/staticcontent/StaticContentHandlerTest.java index 2c7f7b7aae2..e9497a40b3f 100644 --- a/nima/webserver/static-content/src/test/java/io/helidon/nima/webserver/staticcontent/StaticContentHandlerTest.java +++ b/nima/webserver/static-content/src/test/java/io/helidon/nima/webserver/staticcontent/StaticContentHandlerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022 Oracle and/or its affiliates. + * Copyright (c) 2018, 2023 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,7 +33,6 @@ import io.helidon.common.http.ServerRequestHeaders; import io.helidon.common.http.ServerResponseHeaders; import io.helidon.common.parameters.Parameters; -import io.helidon.common.testing.http.junit5.HttpHeaderMatcher; import io.helidon.common.uri.UriFragment; import io.helidon.common.uri.UriPath; import io.helidon.common.uri.UriQuery; @@ -279,13 +278,13 @@ static class TestContentHandler extends FileSystemContentHandler { final boolean returnValue; Path path; - TestContentHandler(StaticContentSupport.FileSystemBuilder builder, boolean returnValue) { + TestContentHandler(StaticContentService.FileSystemBuilder builder, boolean returnValue) { super(builder); this.returnValue = returnValue; } static TestContentHandler create(boolean returnValue) { - return new TestContentHandler(StaticContentSupport.builder(Paths.get(".")), returnValue); + return new TestContentHandler(StaticContentService.builder(Paths.get(".")), returnValue); } @Override @@ -307,13 +306,13 @@ static class TestClassPathContentHandler extends ClassPathContentHandler { final AtomicInteger counter = new AtomicInteger(0); final boolean returnValue; - TestClassPathContentHandler(StaticContentSupport.ClassPathBuilder builder, boolean returnValue) { + TestClassPathContentHandler(StaticContentService.ClassPathBuilder builder, boolean returnValue) { super(builder); this.returnValue = returnValue; } static TestClassPathContentHandler create() { - return new TestClassPathContentHandler(StaticContentSupport.builder("/root"), true); + return new TestClassPathContentHandler(StaticContentService.builder("/root"), true); } @Override diff --git a/nima/webserver/static-content/src/test/java/io/helidon/nima/webserver/staticcontent/StaticContentTest.java b/nima/webserver/static-content/src/test/java/io/helidon/nima/webserver/staticcontent/StaticContentTest.java index 5e66959c975..4accd60276f 100644 --- a/nima/webserver/static-content/src/test/java/io/helidon/nima/webserver/staticcontent/StaticContentTest.java +++ b/nima/webserver/static-content/src/test/java/io/helidon/nima/webserver/staticcontent/StaticContentTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2022 Oracle and/or its affiliates. + * Copyright (c) 2021, 2023 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,9 @@ package io.helidon.nima.webserver.staticcontent; +import java.nio.file.Files; +import java.nio.file.Path; + import io.helidon.common.http.Http; import io.helidon.common.http.Http.Header; import io.helidon.common.testing.http.junit5.HttpHeaderMatcher; @@ -26,12 +29,16 @@ import io.helidon.nima.webserver.http.HttpRouting; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; @RoutingTest class StaticContentTest { + @TempDir + static Path tempDir; + private final DirectClient testClient; StaticContentTest(DirectClient testClient) { @@ -39,12 +46,25 @@ class StaticContentTest { } @SetUpRoute - static void setupRouting(HttpRouting.Builder builder) { - builder.register("/classpath", StaticContentSupport.builder("web")); + static void setupRouting(HttpRouting.Builder builder) throws Exception { + Path nested = tempDir.resolve("nested"); + Files.createDirectories(nested); + + Path resource = tempDir.resolve("resource.txt"); + Path favicon = tempDir.resolve("favicon.ico"); + + Files.writeString(resource, "Content"); + Files.writeString(favicon, "Wrong icon text"); + Files.writeString(nested.resolve("resource.txt"), "Nested content"); + + builder.register("/classpath", StaticContentService.builder("web")) + .register("/singleclasspath", StaticContentService.builder("web/resource.txt")) + .register("/path", StaticContentService.builder(tempDir)) + .register("/singlepath", StaticContentService.builder(resource)); } @Test - void testFavicon() { + void testClasspathFavicon() { try (Http1ClientResponse response = testClient.get("/classpath/favicon.ico") .request()) { @@ -52,4 +72,58 @@ void testFavicon() { assertThat(response.headers(), HttpHeaderMatcher.hasHeader(Header.CONTENT_TYPE, "image/x-icon")); } } + + @Test + void testClasspathNested() { + try (Http1ClientResponse response = testClient.get("/classpath/nested/resource.txt") + .request()) { + + assertThat(response.status(), is(Http.Status.OK_200)); + assertThat(response.headers(), HttpHeaderMatcher.hasHeader(Header.CONTENT_TYPE, "text/plain")); + assertThat(response.as(String.class), is("Nested content")); + } + } + + @Test + void testClasspathSingleFile() { + try (Http1ClientResponse response = testClient.get("/singleclasspath") + .request()) { + + assertThat(response.status(), is(Http.Status.OK_200)); + assertThat(response.headers(), HttpHeaderMatcher.hasHeader(Header.CONTENT_TYPE, "text/plain")); + assertThat(response.as(String.class), is("Content")); + } + } + + @Test + void testFileSystemFavicon() { + try (Http1ClientResponse response = testClient.get("/path/favicon.ico") + .request()) { + + assertThat(response.status(), is(Http.Status.OK_200)); + assertThat(response.headers(), HttpHeaderMatcher.hasHeader(Header.CONTENT_TYPE, "image/x-icon")); + } + } + + @Test + void testFileSystemNested() { + try (Http1ClientResponse response = testClient.get("/path/nested/resource.txt") + .request()) { + + assertThat(response.status(), is(Http.Status.OK_200)); + assertThat(response.headers(), HttpHeaderMatcher.hasHeader(Header.CONTENT_TYPE, "text/plain")); + assertThat(response.as(String.class), is("Nested content")); + } + } + + @Test + void testFileSystemSingleFile() { + try (Http1ClientResponse response = testClient.get("/singlepath") + .request()) { + + assertThat(response.status(), is(Http.Status.OK_200)); + assertThat(response.headers(), HttpHeaderMatcher.hasHeader(Header.CONTENT_TYPE, "text/plain")); + assertThat(response.as(String.class), is("Content")); + } + } } diff --git a/nima/webserver/static-content/src/test/resources/web/nested/resource.txt b/nima/webserver/static-content/src/test/resources/web/nested/resource.txt index 24a90d89d47..43cf4ab6ffc 100644 --- a/nima/webserver/static-content/src/test/resources/web/nested/resource.txt +++ b/nima/webserver/static-content/src/test/resources/web/nested/resource.txt @@ -1 +1 @@ -Content \ No newline at end of file +Nested content \ No newline at end of file diff --git a/tests/integration/native-image/nima-1/src/main/java/io/helidon/tests/integration/nativeimage/nima1/Nima1Main.java b/tests/integration/native-image/nima-1/src/main/java/io/helidon/tests/integration/nativeimage/nima1/Nima1Main.java index 0e6b67e4659..0f6b5ca7401 100644 --- a/tests/integration/native-image/nima-1/src/main/java/io/helidon/tests/integration/nativeimage/nima1/Nima1Main.java +++ b/tests/integration/native-image/nima-1/src/main/java/io/helidon/tests/integration/nativeimage/nima1/Nima1Main.java @@ -28,7 +28,7 @@ import io.helidon.nima.observe.health.HealthObserveProvider; import io.helidon.nima.webserver.WebServer; import io.helidon.nima.webserver.http.HttpRouting; -import io.helidon.nima.webserver.staticcontent.StaticContentSupport; +import io.helidon.nima.webserver.staticcontent.StaticContentService; import io.helidon.nima.websocket.webserver.WsRouting; import static io.helidon.config.ConfigSources.classpath; @@ -111,9 +111,9 @@ private static HttpRouting createRouting(Config config) { return HttpRouting.builder() .addFeature(observe) - .register("/static/path", StaticContentSupport.create(Paths.get("web"))) - .register("/static/classpath", StaticContentSupport.create("web")) - .register("/static/jar", StaticContentSupport.create("web-jar")) + .register("/static/path", StaticContentService.create(Paths.get("web"))) + .register("/static/classpath", StaticContentService.create("web")) + .register("/static/jar", StaticContentService.create("web-jar")) .register("/greet", greetService) .register("/wc", webClientService) .register("/zipkin", zipkinService)