Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DefaultServlet configured for a subdir responds with 404 on existing files #11884

Open
gluser1357 opened this issue Jun 6, 2024 · 9 comments
Labels
Bug For general bugs on Jetty side

Comments

@gluser1357
Copy link

Jetty Environment: ee10 (Jetty 12.0.10)
Java version: OpenJDK 17.0.3
OS: Windows 10

With Jetty 12 we have (in contrast to former Jetty versions like 10 and likely also 11) the following issue with ee10 that static files wont be served when the DefaultServlet is configured only for a subpath:

Configuration:

web.xml:

<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>/doc/*</url-pattern>
</servlet-mapping>

Code:

WebAppContext webappContext = new WebAppContext();
webappContext.setContextPath("/mywebapp");
webappContext.setBaseResourceAsString("c:/my/folder");
Server server = new Server(8080); 
server.setHandler(webappContext);
server.start();

Data:

  • Static file is under c:/my/folder/doc/index.html

Effects:

It seems that the file locations are not resolved correctly if the DefaultServlet is configured for a subpath only (via doc/* in web.xml). Is this a possible bug in ee10's DefaultServlet?

@gluser1357 gluser1357 added the Bug For general bugs on Jetty side label Jun 6, 2024
@joakime
Copy link
Contributor

joakime commented Jun 6, 2024

Since you are using Windows ...
The String you use for webappContext.setBaseResourceAsString(...) must be accurate and not produce an alias.

Differences in case will trigger all kinds of security and resource alias issues.
This is especially true for a DefaultServlet that is mapped to / (the default url-pattern), or using the name "default" which is a special name for the Servlet spec defaults.

Do this ...

Path base = Path.of("c:/my/folder");
String baseStr = base.toRealPath().toString(); // use the filesystem specific naming and case for this reference.
webappContext.setBaseResourceAsString(baseStr);

@gluser1357
Copy link
Author

Thanks. I tried this, but it makes no difference. Just want to add that the web.xml contains no further servlets or filters, and also the directory doesn't contain symlinks.

What else could cause this issue?

@joakime
Copy link
Contributor

joakime commented Jun 6, 2024

What else could cause this issue?

Alias issues probably.
Try this, if it works, then you have still have security / alias issues to identify and resolve.

webappContext.clearAliasChecks();

@joakime
Copy link
Contributor

joakime commented Jun 6, 2024

Also, turn on server dump and see if the changes you made in the web.xml are being applied. (namely that the servlet "default" exists and is mapped according to what you want/need)

server.setDumpAfterStart(true);
server.start();

@gluser1357
Copy link
Author

gluser1357 commented Jun 7, 2024

Thanks for your help!
Obviously there are no alias issues and no problem with Windows, but dumping helped:

Using WebAppContext (see the (adapted) configuration above) - does not work, the dump says:

servlets oeje10s.ServletHandler@56380231{STARTED} size=2
    default==org.eclipse.jetty.ee10.servlet.DefaultServlet@5c13d641{...}
    jsp==org.eclipse.jetty.ee10.servlet.NoJspServlet@19c47{...}
servletMappings oeje10s.ServletHandler@56380231{STARTED} size=3
    [/]=>default
    [*.jsp, *.jspf, *.jspx, *.xsp, *.JSP, *.JSPF, *.JSPX, *.XSP]=>jsp
    [/doc/*]=>default

Using ServletContextHandler (without web.xml) - does work:

ServletContextHandler context = new ServletContextHandler();
context.setContextPath("/" + webappName);
context.setBaseResourceAsString(resourceBase);

ServletHolder holderDoc = new ServletHolder("doc", DefaultServlet.class);
holderDoc.setInitParameter("resourceBase", new File(resourceBase, "doc").toURI().toASCIIString());
context.addServlet(holderDoc, "/doc/*");

Server server = new Server(port);
server.setHandler(context);
server.start();

The dump says:

servlets oeje10s.ServletHandler@299266e2{STARTED} size=2
  doc==org.eclipse.jetty.ee10.servlet.DefaultServlet@18538{...)
    initParams size=1
      resourceBase=file:/C:/my/folder/doc
  org.eclipse.jetty.ee10.servlet.ServletHandler$Default404Servlet-363f6148==...
servletMappings oeje10s.ServletHandler@299266e2{STARTED} size=2
  [/doc/*]=>doc
  [/]=>org.eclipse.jetty.ee10.servlet.ServletHandler$Default404Servlet-363f6148

When comparing both dumps,

  • the servlet mappings of "/" and "/doc/*" are in reverse order
  • for the WebAppContext case (not working), "/" and "/doc/*" are mapped to the same DefaultServlet (without resourceBase defined)
  • whereas for the ServletContextHandler case (working), "/doc/*" are mapped to DefaultServlet (with resourceBase defined) being different to "/" mapped to Default404Servlet.

My remaining questions are:

  • What do I have to adapt in web.xml and code to get my case working again with WebAppContext in Jetty 12? When I remember right then with Jetty 10 (and 11) the behaviour was different (and worked).
  • Does Jetty provide a way to read the web.xml (including all the servlet and filter definitions) of a project with ServletContextHandler, or is WebAppContext required for that?
  • Does Jetty provide a way to scan for @ServletFilter, @ContextListener and @webfilter annotations in the codebase with ServletContextHandler, or is WebAppContext required for that?
  • For the Maven case for WebAppContext - is it required to always re-build the webapp into target/mywebapp and restart the Jetty server after making changes, or is there possibly also a way to directly use target/classes, src/main/webapp/WEB-INF/web.xml and the compiled workspace resolution files, ideally without restarting?
  • For the Maven case for ServletContextHandler - is it generally required to restart the Jetty server after changing code or web.xml content?

@janbartel
Copy link
Contributor

@gluser1357 actually, the DefaultServlet is not really what you want. The DefaultServlet is intended to be the servlet of last resort for a web container, to be used when nothing else matches. What you're trying to do is to serve static content from a particular disk location. So what you really want is a "ResourceServlet". We have an open issue for that here: #10738. In past versions of jetty, people were misusing the DefaultServlet to achieve this static resource serving from servlet mappings other than the default /, and the code became a real mess (the pathInfoOnly setting is a nightmare to get right, especially in a general-purpose way that also works with forwards/includes, redirects etc). We are trying to clean this up in ee10, but haven't got the ResourceServlet ready yet. In the meanwhile, could maybe try configuring a ResourceHandler to serve your static content instead? See https://jetty.org/docs/jetty/12/programming-guide/server/http.html#handler-use-resource

@gluser1357
Copy link
Author

@janbartel thank you for clarification. Following the example at https://github.com/jetty/jetty-examples/blob/12.0.x/embedded/ee10-file-server/src/main/java/examples/ServletFileServerMultipleLocations.java and adapting it led to the working ServletContextHandler-based solution above which requires (Jetty-related) programmatic configuration of servlets, filters and context listeners. Now, in our context, we use Tomcat for production and Jetty for local and CI testing based on a general web.xml configuration that can be used one-to-one for both Tomcat and Jetty. Using a ResourceHandler seems to be, at first glance, just another (Jetty-specific) programmatic approach which - in our case - may not have advantages over the ServletContextHandler-based solution above. Or do I miss something? The ResourceServlet - sounds also interesting. Is it Jetty-specific?

Concerning the other related question above, could you give me also some feedback? That would be really great.

@janbartel
Copy link
Contributor

My remaining questions are:

  • What do I have to adapt in web.xml and code to get my case working again with WebAppContext in Jetty 12? When I remember right then with Jetty 10 (and 11) the behaviour was different (and worked).

DefaultServlet will not work the way you want in ee10 as it expect that it is at the root of the document folder.

  • Does Jetty provide a way to read the web.xml (including all the servlet and filter definitions) of a project with ServletContextHandler, or is WebAppContext required for that?

You need WebAppContext.

  • Does Jetty provide a way to scan for @ServletFilter, @ContextListener and @webfilter annotations in the codebase with ServletContextHandler, or is WebAppContext required for that?

You need WebAppContext.

  • For the Maven case for WebAppContext - is it required to always re-build the webapp into target/mywebapp and restart the Jetty server after making changes, or is there possibly also a way to directly use target/classes, src/main/webapp/WEB-INF/web.xml and the compiled workspace resolution files, ideally without restarting?

This is what the jetty-maven-plugin is for.

  • For the Maven case for ServletContextHandler - is it generally required to restart the Jetty server after changing code or web.xml content?

If you're not using the jetty-maven-plugin then I guess normal maven class loading rules apply.

@gluser1357
Copy link
Author

gluser1357 commented Jun 10, 2024

@janbartel Thank you for referencing jetty-maven-plugin! That sounds great and I will test it.

We still look for a container-independent solution serving all url endpoints (url-pattern /*) by a certain servlet (in our case Jersey) except static content under (url-pattern /doc/*) that could be served so far by the DefaultServlet. Is the planned ResourceServlet the way to go, or are there alternatives not requiring Jetty-specific programmatic adaptions?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug For general bugs on Jetty side
Projects
None yet
Development

No branches or pull requests

3 participants