Rocket: Feature request: More flexibility for catch-all routes

Created on 15 Apr 2017  路  3Comments  路  Source: SergioBenitez/Rocket

Perhaps this is documented somewhere, but I'm digging through the source and it doesn't seem obvious that this is supported.

I want to match everything at a specific path, /git in this instance. I'd like to construct a function with the various matchers/guards as currently supported, but then to perform all significant handling within that function based on method type, parameter presence, etc.

I believe this feature is necessary because, as documented, route-matching is very specific. This is great for things like typed APIs, but some API boundaries are already well-structured and don't need that much help from Rust.

My use case is proxying everything under /git to a Rust function that calls git http-backend. git-http-backend is specified well enough that I'd trust it as is. Sometimes the URI has query parameters, sometimes it doesn't. I think the methods used vary as well. But right now I don't see how to specify that I want everything under /git passed to this function. This would also be useful for, say, CGI handling or embedded HTTP proxies.

I can define a route like so:

#[get("/git/<path..>?<query>")]

but that won't work for POSTs, nor for requests that don't include query parameters, of which there are several I think (I'm very much implementing this for the first time so am learning as I go.) In the end, maybe I could have bunches of routes specifying every possibility, and proxy their calls to a central function. But that's ugly, and as nice as it'd be to fully type that API boundary in Rust, I trust git-http-backend well enough for this weekend side project. :)

I think this needs to be in Rocket because it changes how the router works. At the moment it looks like everything is tied to a single method, and query parameters can't be optional. Instead of adding a bunch of extra code covering every corner case (support for all methods in specific routes, support for everything-optional) it might make sense to just proxy every matching path to a handler. Call it unsafe for routes if you like. :)

Thanks.

question

Most helpful comment

This is possible in master with manual routing. The gist of a solution would be to create a Route instance for every HTTP method to the path /<path..>, each pointing to the same handler. In master, if you don't specify a query parameter in the path matcher, then Rocket will match requests with and without a query parameter (see https://github.com/SergioBenitez/Rocket/issues/185#issuecomment-292052648 and 9160483). Then, simply mount them at /git (or wherever) and pass whatever information you'd like to git http-backend. For instance, you could retrieve the URI directly via request.uri().as_str().

The pseudocode for something like this is:

fn git_http(req: &Request, _: Data) -> Outcome<'static> {
    Outcome::of(git_http_backend(req.method(), req.uri().as_str())
}

fn main() {
    let mut git_routes = vec![];
    for method in &[Get, Put, Post, Delete, Options, Head, Trace, Connect, Patch] {
        git_routes.push(Route::new(*method, "<path..>", git_http));
    }

    rocket.ignite().mount("/git", git_routes).launch()
}

This is the "unsafe" escape hatch in Rocket. It should rarely, if ever be used, but it's important for cases like yours.

All 3 comments

This is possible in master with manual routing. The gist of a solution would be to create a Route instance for every HTTP method to the path /<path..>, each pointing to the same handler. In master, if you don't specify a query parameter in the path matcher, then Rocket will match requests with and without a query parameter (see https://github.com/SergioBenitez/Rocket/issues/185#issuecomment-292052648 and 9160483). Then, simply mount them at /git (or wherever) and pass whatever information you'd like to git http-backend. For instance, you could retrieve the URI directly via request.uri().as_str().

The pseudocode for something like this is:

fn git_http(req: &Request, _: Data) -> Outcome<'static> {
    Outcome::of(git_http_backend(req.method(), req.uri().as_str())
}

fn main() {
    let mut git_routes = vec![];
    for method in &[Get, Put, Post, Delete, Options, Head, Trace, Connect, Patch] {
        git_routes.push(Route::new(*method, "<path..>", git_http));
    }

    rocket.ignite().mount("/git", git_routes).launch()
}

This is the "unsafe" escape hatch in Rocket. It should rarely, if ever be used, but it's important for cases like yours.

@ndarilek Does this solve your issue?

I believe this has been answered. If you disagree, please comment and we'll revisit the issue. :)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

incker picture incker  路  3Comments

shssoichiro picture shssoichiro  路  4Comments

lambda-fairy picture lambda-fairy  路  4Comments

sphinxc0re picture sphinxc0re  路  3Comments

denysvitali picture denysvitali  路  3Comments