From 09730485db75f238869b28b621d681d9f8809df8 Mon Sep 17 00:00:00 2001 From: Andrus Adamchik Date: Fri, 24 May 2024 20:24:00 -0400 Subject: [PATCH] Unified API for mapping static servlets #125 docs --- .../_chapters/_02_programming_jetty_apps.adoc | 58 +++++++++---------- .../io/bootique/jetty/docs/StaticServlet.java | 41 +++++++++++++ ...rvlets.java => StaticServletPathInfo.java} | 20 ++++--- 3 files changed, 81 insertions(+), 38 deletions(-) create mode 100644 bootique-jetty-docs/src/test/java/io/bootique/jetty/docs/StaticServlet.java rename bootique-jetty-docs/src/test/java/io/bootique/jetty/docs/{ModuleWithStaticServlets.java => StaticServletPathInfo.java} (72%) diff --git a/bootique-jetty-docs/src/main/asciidoc/_chapters/_02_programming_jetty_apps.adoc b/bootique-jetty-docs/src/main/asciidoc/_chapters/_02_programming_jetty_apps.adoc index c0b1d7a0..f198fba5 100644 --- a/bootique-jetty-docs/src/main/asciidoc/_chapters/_02_programming_jetty_apps.adoc +++ b/bootique-jetty-docs/src/main/asciidoc/_chapters/_02_programming_jetty_apps.adoc @@ -89,52 +89,36 @@ Listeners can rely on injection to obtain dependencies, just like servlets and f === Serving Static Files Jetty is not limited to just servlets. It can also act as a webserver for static files stored on the filesystem or even -on the application classpath. By default this behavior is disabled to prevent unintended security risks. To enable the -"webserver" feature use extender's `useDefaultServlet()` method: +on the application classpath. To "publish" files in a given folder on Jetty, use the following API: [source,java,indent=0] ---- -include::../../../test/java/io/bootique/jetty/docs/ModuleWithDefaultServlet.java[tags=bindDefaultServlet] +include::../../../test/java/io/bootique/jetty/docs/StaticServlet.java[tags=staticServlet] ---- -This enables a special internal servlet at "/" path, that will act as a static webserver. It requires an additional -configuration parameter though - the base directory where the files are stored. This is configured in YAML, and the path -can be either a directory on the filesystem or a classpath: +You can publish as many locations as needed. If a location is not known at compile time, it can alternatively +be defined in the app configuration with `resourceBase` servlet parameter: + [source,yaml] ---- jetty: - context: "/myapp" - staticResourceBase: "classpath:com/example/docroot" + servlets: + docroot: + params: + # This follows Bootique resource URL format + # and can be a "classpath:" URL or a filesystem path + resourceBase: "classpath:com/example/docroot" ---- -"Default" servlet always has a base URL of "/" (relative to the application context). If you want a different path (or -need to serve more then one file directory under different base URLs), you can define more of those "webserver" servlets, -each with its own parameters: +Another potentially relevant (and rather confusing) setting is `pathInfoOnly`. It controls URL-to-file resolving +behavior and is available as a part of the location publishing API, or as a servlet parameter. E.g.: [source,java,indent=0] ---- -include::../../../test/java/io/bootique/jetty/docs/ModuleWithStaticServlets.java[tags=bindStaticServlets] +include::../../../test/java/io/bootique/jetty/docs/StaticServletPathInfo.java[tags=pathInfo] ---- -By default each "static servlet" shares the common `staticResourceBase`, but it can also define its own base and -URL-to-file mapping approach using a -few https://www.eclipse.org/jetty/javadoc/9.4.19.v20190610/org/eclipse/jetty/servlet/DefaultServlet.html[servlet parameters], -namely `resourceBase` and `pathInfoOnly`: -[source,yaml] ----- -jetty: - context: "/myapp" - servlets: - abc: - params: - # Note that "resourceBase" follows Bootique resource URL format - # and hence can be a "classpath:" URL or a filesystem path - resourceBase: "classpath:com/example/abcdocroot" - pathInfoOnly: true ----- - -`resourceBase` simply overrides `staticResourceBase` for a given servlet, while `pathInfoOnly` controls static resource -URL resolution as follows: +It behaves as follows: |=== |URL|pathInfoOnly|File Path @@ -147,6 +131,18 @@ URL resolution as follows: |/dir1/f1.html |=== +Jetty `DefaultServlet` (the one serving the static files under the hood) supports a number of other +parameters https://eclipse.dev/jetty/javadoc/jetty-11/org/eclipse/jetty/servlet/DefaultServlet.html[described here]. +Some of them, such as `relativeResourceBase`, require the app-wide resource base to be set: + +[source,yaml] +---- +jetty: + staticResourceBase: "classpath:com/example/docroot" +---- + +NOTE: `staticResourceBase` is really redundant in most (all?) situations, so hopefully you will never need to use it. + === ServletEnvironment Some application classes have direct access to the current servlet request and context (e.g. servlets, filters, diff --git a/bootique-jetty-docs/src/test/java/io/bootique/jetty/docs/StaticServlet.java b/bootique-jetty-docs/src/test/java/io/bootique/jetty/docs/StaticServlet.java new file mode 100644 index 00000000..f2969741 --- /dev/null +++ b/bootique-jetty-docs/src/test/java/io/bootique/jetty/docs/StaticServlet.java @@ -0,0 +1,41 @@ +/* + * Licensed to ObjectStyle LLC under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ObjectStyle LLC licenses + * this file to you 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.bootique.jetty.docs; + +import io.bootique.di.BQModule; +import io.bootique.di.Binder; +import io.bootique.jetty.JettyModule; +import io.bootique.jetty.MappedServlet; + + +public class StaticServlet implements BQModule { + + // tag::staticServlet[] + @Override + public void configure(Binder binder) { + MappedServlet s = MappedServlet + .ofStatic("docroot") + .urlPatterns("/") + .resourceBase("classpath:docroot") + .build(); + + JettyModule.extend(binder).addMappedServlet(s); + } + // end::staticServlet[] +} diff --git a/bootique-jetty-docs/src/test/java/io/bootique/jetty/docs/ModuleWithStaticServlets.java b/bootique-jetty-docs/src/test/java/io/bootique/jetty/docs/StaticServletPathInfo.java similarity index 72% rename from bootique-jetty-docs/src/test/java/io/bootique/jetty/docs/ModuleWithStaticServlets.java rename to bootique-jetty-docs/src/test/java/io/bootique/jetty/docs/StaticServletPathInfo.java index 8325b4a1..27d09817 100644 --- a/bootique-jetty-docs/src/test/java/io/bootique/jetty/docs/ModuleWithStaticServlets.java +++ b/bootique-jetty-docs/src/test/java/io/bootique/jetty/docs/StaticServletPathInfo.java @@ -21,16 +21,22 @@ import io.bootique.di.BQModule; import io.bootique.di.Binder; import io.bootique.jetty.JettyModule; +import io.bootique.jetty.MappedServlet; -public class ModuleWithStaticServlets implements BQModule { - // tag::bindStaticServlets[] +public class StaticServletPathInfo implements BQModule { + @Override public void configure(Binder binder) { - JettyModule.extend(binder) - .addStaticServlet("abc", "/abc/*") - .addStaticServlet("xyz", "/xyz/*"); + + // tag::pathInfo[] + MappedServlet s = MappedServlet + .ofStatic("docroot") + .urlPatterns("/abc/*") + .pathInfoOnly() + .build(); +// end::pathInfo[] + + JettyModule.extend(binder).addMappedServlet(s); } - // end::bindStaticServlets[] } -