seanmonstar / warp

A super-easy, composable, web server framework for warp speeds.
https://seanmonstar.com/post/176530511587/warp
MIT License
9.58k stars 719 forks source link

Not found error translate to method not allowed when there is route with method is at the start of the route #1104

Open rluvaton opened 3 months ago

rluvaton commented 3 months ago

Maybe related to #1017

Version v0.3.7

Platform

Darwin MacBook-Pro.local 23.5.0 Darwin Kernel Version 23.5.0: Wed May  1 20:12:58 PDT 2024; root:xnu-10063.121.3~5/RELEASE_ARM64_T6000 arm64

Description Reproduction Repo

When some route return NOT FOUND (404) I get METHOD NOT ALLOWED (405) when there is a route that have the method at the start of the paths instead of at the end:

When put is at the start:

let problematic_route = warp::put()
        .and(warp::path("api"))
        .map(move || {
            "Hello".to_string()
        });

VS when `put is at the end:

let problematic_route = warp::path("api")
    .and(warp::put())
    .map(move || {
        "Hello".to_string()
    });

I did not see anywhere that putting the method at the start will cause this which is why I'm considering it as a bug


The following is working:

let crates = warp::path("b")
      // Simulating .and(warp::fs::dir(<some-dir>)) for simplicity
      .and(warp::get())
      .and(custom_filter())

      .with(warp::trace::request());

  let problematic_route = warp::path("api")
      .and(warp::put())
      .map(move || {
          "Hello".to_string()
      });

  let routes = problematic_route
      .or(crates);

Almost complete code

The following does not work:

let crates = warp::path("b")
      // Simulating .and(warp::fs::dir(<some-dir>)) for simplicity
      .and(warp::get())
      .and(custom_filter())

      .with(warp::trace::request());

  // <-------- This does not work
  let problematic_route =
      warp::put()
          .and(warp::path("api"))
          .map(move || {
              "Hello".to_string()
          });

  let routes = problematic_route
      .or(crates);

Custom filter is:

fn custom_filter() -> impl Filter<Extract=(String,), Error=Rejection> + Copy {
    warp::path::tail()

        // I use `and_then` to simulate warp::fs::dir(<some-dir>) which does that as well
        .and_then(|s: Tail| async move {
            let route = s.as_str();

            if !route.ends_with("something") {
                return Err(reject::not_found());
            }

            Ok(route.to_string())
        })
}
arampp-xitaso commented 2 months ago

Thank you for explaining the workaround. I have the same problem, the workaround helps. I'd be interested to know what the root-cause of this issue is.