jetty.project
jetty.project copied to clipboard
Issue with Configuring Specific Static Resources in the same base directory ee10 jetty 12.0.10
Jetty version(s) 12.0.10
Jetty Environment ee10
Java version/vendor 17
Description I am encountering an issue while configuring specific static resources in the same base directory. When I try to access these resources, I receive a HTTP ERROR 404 Not Found
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/");
ResourceFactory resourceFactory = ResourceFactory.of(context);
context.setBaseResource(resourceFactory.newResource(mainResourceBase));
ServletHolder holderAlt = new ServletHolder("static", DefaultServlet.class);
holderAlt.setInitParameter("dirAllowed", "true");
holderAlt.setInitParameter("acceptRanges", "true");
context.addServlet(holderAlt, "/index.html");
ServletHolder holderDef = new ServletHolder("default", DefaultServlet.class);
holderDef.setInitParameter("dirAllowed", "true");
context.addServlet(holderDef, "/")
Can you show examples of resource requests that fail?
The issue only serving the /index.html
Call server.setDumpAfterStart(true); before server.start(); and verify that there is a Base Resource.
I say this, because you are not checking that the line resourceFactory.newResource(mainResourceBase) is returning null (such as if it cannot find that resource).
What is mainResourceBase btw?
resourceFactory.newResource(mainResourceBase) is not returning null. I tested the same code in Jetty EE9, and it works correctly; I can access the request /index.html. Therefore, I think the problem is in the class DefaultServlet.java EE10.
You are using Windows (and important thing to note when working with File System issues on Java).
Can you access some of the static resources? or none of them?
If you enable DEBUG logging do you see any mentions of "alias" issues?
In the path D:\eclipse-workspace\Jetty12authEE10\bin\main\static-root\ are any of those path sub-entries a link? (hard / soft / fs / etc)
Is the path D:\eclipse-workspace\Jetty12authEE10\bin\main\static-root\ using the exact case (as stored on disk) of each sub-entry in that path? (if you are being lazy and using C:\foo\bar when the actual directories are C:\Foo\Bar then this would trigger all sorts of security features and alias checking behaviors as the paths are not exactly the same. (This also goes for the requested resources within that base resource. eg: don't request /index.html if the stored on disk file is Index.Html)
I can access to all the static resources except index.html. For example, I can access to static resources that end with .js. However, I can't access the static resource index.html. Here is my configuration:
Server server = new Server();
ServerConnector connector = new ServerConnector(server);
connector.setPort(8080);
server.addConnector(connector);
URI webRootUri = findDefaultBaseResource();
System.err.println("Default Base Resource is " + webRootUri);
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS |
ServletContextHandler.SECURITY);
context.setContextPath("/welcome");
ResourceFactory resourceFactory = ResourceFactory.of(context);
context.setBaseResource(resourceFactory.newResource(webRootUri));
final var holderJs = new ServletHolder("js", DefaultServlet.class);
holderJs.setInitParameter("dirAllowed", "true");
holderJs.setInitParameter("cacheControl", "public, max-age=0, must-revalidate");
context.addServlet(holderJs, "*.js"); // Map to all paths ending with .js
ServletHolder holderAlt = new ServletHolder("static", DefaultServlet.class);
holderAlt.setInitParameter("dirAllowed", "false");
holderAlt.setInitParameter("cacheControl", "no-store");
context.addServlet(holderAlt, "/index.html");
ServletHolder holderDef = new ServletHolder("default", DefaultServlet.class);
holderDef.setInitParameter("dirAllowed", "true");
context.addServlet(holderDef, "/");
server.setHandler(context);
server.start();
server.join();`
Can you please copy/paste? Don't use screenshots / images, as it doesn't help others in the future. (people searching for help cannot find similar issues). Also, it doesn't help us when helping you.
You only need 1 DefaultServlet and it will always be mapped to / (no other url-pattern).
Get rid of the other ones.
If you want welcome file behavior, use one of the ServletContextHandler.setWelcomeFiles() methods.
If I want to specify a configuration for the static resource index.html, for example, or for other resources ending with .js, because not all of them have the same InitParameter?
ServletHolder holderAlt = new ServletHolder("static", DefaultServlet.class);
holderAlt.setInitParameter("dirAllowed", "false");
holderAlt.setInitParameter("cacheControl", "no-store");
context.addServlet(holderAlt, "/index.html");
ServletHolder holderDef = new ServletHolder("default", DefaultServlet.class);
holderDef.setInitParameter("dirAllowed", "true");
context.addServlet(holderDef, "/");
For the static resource index.html, we have set .setInitParameter("dirAllowed", "false"); and for the default, we have set .setInitParameter("dirAllowed", "true");
If I want to specify a configuration for the static resource index.html, for example, or for other resources ending with .js, because not all of them have the same InitParameter
DefaultServlet does not work with url-patterns that are absolute-path (eg: /index.html), or suffix based (eg: *.js). It only works with default (eg: /) or directory-prefix (eg: /static/*)
so I cannot assign special configurations for non-default DefaultServlets? But I don't understand if the problem is related to class DefaultServlet in Jetty 12 ee10, because the same code worked in Jetty 12 ee9, allowing access to all resources, including index.html with specific configuration to the index.html
so I cannot assign special configurations for non-default DefaultServlets?
You can, but there are restrictions.
- Extra configurations MUST be done on new
DefaultServletinstances (you cannot reuse theServletHolder) - Extra
DefaultServletinstances only support url-patterns defined as either ...- default pattern: only
/ - prefix directory pattern: eg:
/static/*or/css/*or/scripts/*, but not/foo.*as that's not a directory.
- default pattern: only
- Each new
DefaultServletneeds it's own Base Resource
See example at https://github.com/jetty/jetty-examples/blob/12.0.x/embedded/ee10-file-server/src/main/java/examples/ServletFileServerMultipleLocations.java
so I cannot assign special configurations for non-default DefaultServlets?
You can, but there are restrictions.
Extra configurations MUST be done on new
DefaultServletinstances (you cannot reuse theServletHolder)Extra
DefaultServletinstances only support url-patterns defined as either ...
- default pattern: only
/- prefix directory pattern: eg:
/static/*or/css/*or/scripts/*, but not/foo.*as that's not a directory.Each new
DefaultServletneeds it's own Base ResourceSee example at https://github.com/jetty/jetty-examples/blob/12.0.x/embedded/ee10-file-server/src/main/java/examples/ServletFileServerMultipleLocations.java
Thanks for this information. so If I need to configure the static resource index.html, I must place this file in a different base resource and then add the baseResource parameter to the ServletHolder
The static resource /index.html is served by the servlet default url-pattern of /.
Why do you need an entirely separate DefaultServlet for a precise / absolute-path url-pattern? It makes no sense to have a DefaultServlet mapping for that.
I see a serious regression with the DefaultServlet in EE10 compared to EE9. I think the problem is in the DefaultServlet class and it affects the DefaultServlet when serving a single, unique file. Please refer to this issue https://github.com/jetty/jetty.project/issues/11791
Why do you need that? Don't get hung up on the process, don't get caught up in the details, what's important to know is the end result.
If it's just for Cache-Control, then you are doing this entirely in the wrong place, as Cache-Control is applied to all resources in the entire Base Resource, not specific entries based on the DefaultServlet. (the Cache-Control init-param in DefaultServlet just configures the low level ResourceService which handles serving content from the Base Resource)
The whole point of serving static files from DefaultServlet is to serve them from a Base Resource. If you hardcode an absolute url-pattern then that will not be served from the Base Resource in the way you expect.
Take this for example...
- Base Resource:
C:\data\webroot\ - Context-Path:
/app - Default Servlet URL Pattern:
/ - HTTP Request Path:
/app/css/main.css
That request will result in a lookup against the Base Resource + (Path-In-Context).
The Path-In-Context is the path that is left over after you remove the Context-Path, and the url-pattern.
So that would mean C:\data\webroot\ + /css/main.css
Meaning that C:\data\webroot\css\main.css is what is served.
If you have an absolute-path url-pattern of say /index.html, and the request is /app/index.html, the Path-In-Context is `` (blank) as the url-pattern is excluded.
The lookup will attempt to load from Base Resource the file C:\data\webroot\, which wont work.
Then with all of this you are still not handling welcome file logic at all with your Cache-Control.
The user could use the request path /app/ and the welcome files logic will serve /index.html which wouldn't apply your custom Cache-Control either.
If you have specific Cache-Control behavior, that's not handled via DefaultServlet configuration, but rather by paying attention to the Response Content-Type and from where that response was generated (eg: the request path, but don't forget about welcome-files logic!). This is typically done via custom Servlet filters setup against specific paths.
@Emilyserap see my comment over on this other issue here: https://github.com/jetty/jetty.project/issues/11884#issuecomment-2155696862. It's not a regression, ee10 is not trying to be bug-for-bug compatible with previous versions. We are attempting to clean up the DefaultServlet. I think the piece we are missing is the ResourceServlet (see #10738) that in the meanwhile can probably be worked around via the ResourceHandler (see linked comment for a link to the doco).
@Emilyserap see my comment over on this other issue here: #11884 (comment). It's not a regression,
ee10is not trying to be bug-for-bug compatible with previous versions. We are attempting to clean up theDefaultServlet. I think the piece we are missing is theResourceServlet(see #10738) that in the meanwhile can probably be worked around via theResourceHandler(see linked comment for a link to the doco).
Thanks for the explanation. Otherwise, when will the ResourceServlet be ready?
@Emilyserap https://github.com/jetty/jetty.project/pull/11933 has been merged into jetty-12.0.x, so should be part of this month's 12.0.12 release.