Error 400 Invalid location: Relative path cannot start with /

My servlet context path contains a space.
The servlet context path is passed into WebAppContext constructor.

When I try to access my application, I get the following error:

<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=ISO-8859-1"/>
<title>Error 400 Invalid location: Relative path cannot start with /</title>
</head>
<body><h2>HTTP ERROR 400 Invalid location: Relative path cannot start with /</h2>
<table>
<tr><th>URI:</th><td>/my%20app/</td></tr>
<tr><th>STATUS:</th><td>400</td></tr>
<tr><th>MESSAGE:</th><td>Invalid location: Relative path cannot start with /</td></tr>
<tr><th>SERVLET:</th><td>com.vaadin.flow.server.VaadinServlet-2e5c7cd5</td></tr>
</table>
<hr/><a href="https://jetty.org/">Powered by Jetty:// 12.0.23</a><hr/>

</body>
</html>

I have tried with both skeleton applications ( Tomcat and Jetty based ) to set a @route containing spaces, and it works without problems.

But, when I explicitly configure VaadinServlet as a JettyHandler with this context path containing a space, I get the above error message.

Any idea about what am I doing wrong?

Sorry… could not resist: Using space inside a servlet context path… That sounds like something nobody should do.

Yes, I know is weird. Nevertheless, I have to argue why it should not be done. And I have found nothing in the servlet specification.

Chapter 4. Servlet Context
4.1. Introduction to the ServletContext Interface
The ServletContext interface defines a servlet’s view of the web application within which the servlet is
running.
…
A ServletContext is rooted at a known path within a web server. For example, a servlet context could
be located at http://example.com/catalog. All requests that begin with the /catalog request path, known as the context path, are routed to the web application associated with the ServletContext.
…

This seems to me more like an issue with the Jetty integration code.
Could you please show how you configured the VaadinServlet as a JettyHandler?

The configuration and the code are not so easy to post.
But the most important thing is that I have a class that extends
org.eclipse.jetty.ee10.webapp.WebAppContext and is added as Jetty handler.

Inside this class that extends WebAppContext I call in the constructor

super(null, servletContextPath)

where the “servletContextPath” is the one containing a space.

Afterward, I call in the same context class:

  ServletHolder servletHolder = new ServletHolder(VaadinServlet.class);
  addServlet(servletHolder, "/*");

Is this enough information?

It doesn’t ring any bell, but I noticed you already created a ticket on the Jetty repository. Hopefully they can help.

I also hope, yes.
Thank you!

It looks like it’s in Vaadin. At least the error message is in com.vaadin.flow.router.LocationUtil.verifyRelativePath()

Can you share the error message (and stack trace if available)? I couldn’t find it in previous posts

There is no stack trace, it is only the error message rendered in the HTML page
Invalid location: Relative path cannot start with /

LocationUtil.verifyRelativePath() doesn’t complain about basic cases that include a space. Could you put a breakpoint in the method to see what the input is to that method when it throws?

sure, it is “/my app/”. With a space inside

Yeah but it’s not the space that makes it break. "/myapp/" without a space leads to the same result. So the question then is what gets passed to the method in the cases where it does work?

Shouldn’t the context path be /my app instead of /my app/?

Context Path: The path prefix associated with the ServletContext that this
servlet is a part of. If this context is the “default” context rooted at the base of the
Web server’s URL name space, this path will be an empty string. Otherwise, if the
context is not rooted at the root of the server’s name space, the path starts with a
/ character but does not end with a / character

the path starts with a
/ character but does not end with a / character

If I configure the context path with “-” instead of space (“my-app”) the relative path is empty string.

Do you mean that request.getPathInfo() returns /my app/? This does not sound correct to me. getPathInfo() is not supposed to contain the context path nor the servlet path segments

No, I was talking about the input of LocationUtil.verifyRelativePath()

        try {
            LocationUtil.verifyRelativePath(
                    LocationUtil.ensureRelativeNonNull(request.getPathInfo()));
        } catch (InvalidLocationException invalidLocationException) { // NOSONAR
            response.sendError(400, "Invalid location: "
                    + invalidLocationException.getMessage());
            return true;
        }

This is most likely where the error comes from. The input to verifyRelativePath is LocationUtil.ensureRelativeNonNull(request.getPathInfo()); ensureRelativeNonNull basically only handles null and removes the leading slash if present. So my guess was that /my app/ comes from request.getPathInfo().

But maybe the caller is not that one; above code is from BootstrapHandler class. Could you verify who is calling LocationUtil.verifyRelativePath() when the failure happens?