pippo icon indicating copy to clipboard operation
pippo copied to clipboard

Requesting a path ending with / must find a route with or without / at the end

Open mhagnumdw opened this issue 4 years ago • 1 comments

Hi all!

For Spring and Pippo, the table is as follows:

Case Client request Defined route Spring match? Pippo match?
1 /user /user yes yes
2 /user/ /user yes no
3 /user /user/ no no
4 /user/ /user/ yes yes

Tests made for http: GET and PUT methods. Spring by default is forward and not redirect. Pipo does nothing.

In Pippo the case [2] does not happen. There is TrailingSlashHandler, but it redirects and only works for GET.

I found this comment https://github.com/pippo-java/pippo/issues/366#issuecomment-307214009-permalink from @decebals about registering a RoutePreDispatchListener to modify the request's path, but this is not possible because the path attribute is private. Another problem with this approach is removing the / at the end from the request path we will have a problem in the case [4].

Another excerpt from the same comment is:

We need a mechanism to modify the initial Request (and probably Response) object(s) before to call Router.findRoutes()

I think this is not the way out. I think that the uriMatcher.match method within Router.findRoutes, should match the case [2]. It seems to be the ideal point to check this.

It goes something like this: if the request path ends with / you must find a route that ends with or without /. Cases [2] and [4].

What do you think? Did I miss something?

mhagnumdw avatar Jul 11 '20 01:07 mhagnumdw

I think that is a good idea to have a Pippo-Spring match (case 2).

I have relative an annoying bug relative on this subject.

// add routes for security (login, logout, ...)
// addRouteGroup(new SecurityRoutes(authenticator)); // natural, but PIppo is not capable to understand this
 new SecurityRoutes(authenticator).getRoutes().forEach(this::addRoute); // workaround

where SecurityRoutes looks like:

public class SecurityRoutes extends RouteGroup {

    private Authenticator authenticator;

    public SecurityRoutes(Authenticator authenticator) {
        super("");

        this.authenticator = authenticator;

        // PAC4J config
        Config config = getPac4jConfig();

        // authentication filter
        ANY(securePaths(), new Pac4jSecurityHandler(config, "FormClient"));

        // login
        GET("/login", routeContext -> { ... });

        // other routes
    }

}

decebals avatar Jul 28 '20 17:07 decebals