rwf2 / Rocket

A web framework for Rust.

Home Page:https://rocket.rs

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Conflicts among routes when `FileServer::rank()` function is used

Luni-4 opened this issue Β· comments

Rocket Version

0.5.0

Operating System

Ubuntu 23.10

Rust Toolchain Version

Rust stable version 1.74.1

What happened?

I do not know if this is an issue, or just me who do not understand how to do things. If it turns out to be the second case, apologies in advance.

When I use FileServer::rank() in this example.zip I get the I/O error present in the Log Output section when I set the rank.

Test Case

#[macro_use]
extern crate rocket;

use rocket::fs::{relative, FileServer};
use rocket::response::stream::{Event, EventStream};
use rocket::tokio::time::{self, Duration};

#[get("/")]
async fn index() -> &'static str {
    "Hello index"
}

#[get("/", rank = 2)]
async fn second() -> &'static str {
    "Hello try route"
}

#[get("/", format = "text/event-stream", rank = 1)]
async fn one() -> EventStream![] {
    EventStream! {
        let mut interval = time::interval(Duration::from_secs(1));
        loop {
            yield Event::data("ping");
            interval.tick().await;
        }
    }
}

#[launch]
async fn rocket() -> _ {
    rocket::build()
        .mount("/", routes![index])
        .mount("/try", routes![one, second])
        .mount("/", FileServer::from(relative!("assets")).rank(0))
        .mount("/try", FileServer::from(relative!("assets")).rank(3))
}

Log Output

πŸ”§ Configured for debug.
   >> address: 127.0.0.1
   >> port: 8080
   >> workers: 12
   >> max blocking threads: 512
   >> ident: Rocket
   >> IP header: X-Real-IP
   >> limits: bytes = 8KiB, data-form = 2MiB, file = 1MiB, form = 32KiB, json = 1MiB, msgpack = 1MiB, string = 8KiB
   >> temp dir: /tmp
   >> http/2: true
   >> keep-alive: 5s
   >> tls: disabled
   >> shutdown: ctrlc = true, force = true, signals = [SIGTERM], grace = 2s, mercy = 3s
   >> log level: normal
   >> cli colors: true
πŸ“¬ Routes:
   >> (index) GET /
   >> (FileServer: assets) GET /<path..>
   >> (one) GET /try/ text/event-stream
   >> (second) GET /try/ [2]
   >> (FileServer: assets) GET /try/<path..> [3]
πŸ“‘ Fairings:
   >> Shield (liftoff, response, singleton)
πŸ›‘οΈ Shield:
   >> X-Content-Type-Options: nosniff
   >> Permissions-Policy: interest-cohort=()
   >> X-Frame-Options: SAMEORIGIN
πŸš€ Rocket has launched from http://127.0.0.1:8080
GET /try text/html:
   >> Matched: (FileServer: assets) GET /<path..>
   >> I/O Error: Os { code: 2, kind: NotFound, message: "No such file or directory" }
   >> Outcome: Forward(404 Not Found)
   >> Matched: (second) GET /try/ [2]
   >> Outcome: Success(200 OK)
   >> Response succeeded.

Additional Context

No response

System Checks

  • My bug report relates to functionality.
  • I have tested against the latest Rocket release or a recent git commit.
  • I have tested against the latest stable rustc toolchain.
  • I was unable to find this issue previously reported.

I'm confused about what you're trying to accomplish. An actual test case here would have been very useful. In particular, I'm not sure what your desired outcome is: which requests do you want routed where? If you could provide a list of requests and where you'd like them routed, then determining how to declare your routes should be straightforward. Something like this:

  • GET /foo/bar -> this_route
  • POST /foo/bar (accept json) -> that_route

@SergioBenitez

Sorry for the messy explanation, I've improved my first post adding:

  • The entire zipped example
  • The code
  • Thre complete log output

Let me know if you can reproduce the problem or if I'm doing something wrong.

Neither your test case nor your updated explanation include what you expected to happen. I'm still not sure what you're trying to accomplish. I understand what's happening, but not what you want to make happen.

I do not want this I/O Error: Os { code: 2, kind: NotFound, message: "No such file or directory" } to happen

You're still not saying what you do want to happen.

I guess I need to explain my opinion even if I do not have the knowledge to say that correctly, but ok, let's try, I hope I'm right this time :)

I would like to set up FileServer ranks in a simpler way. In this case I would like to write .mount("/", FileServer::from(relative!("assets"))) only once and apply that to each route, because in my specific case I'm loading a logo, so it would be simpler to define that only once and in one line of code.

I would like to use FileServe::rank() just to tell: "load that artifact only for that specific route and that specific rank.

If even this explanation does not achieve the goal, please help me in writing a sentence that says what one does want to happen, thanks!

@Luni-4 When you make the request, provide the path to your image file relative to assets folder because that's how you mounted your FileServer
GET localhost:8080/try/img/image.png

@allmywatts

Yes, you're right about that, but when I remove this line

.mount("/try", FileServer::from(relative!("assets")).rank(3))

in order to not have the route GET localhost:8080/try/img/image.png I cannot load the logo in GET localhost:8080/try route only using

.mount("/", FileServer::from(relative!("assets")))

Leaving only the line before, if I'm not wrong, should correspond to GET localhost:8080/img/image.png route.

Even if I follow this strategy:

.mount("/", FileServer::from(relative!("assets")).rank(3))

I only obtain conflicts

@Luni-4 If I understood correctly, this is what you are looking for

#[launch]
async fn rocket() -> _ {
    rocket::build()
        .mount("/", routes![index])
        .mount("/try", routes![one, second])
        .mount("/", FileServer::from(relative!("assets")).rank(5))
        .mount("/try", FileServer::from(relative!("assets")).rank(4))
}
GET /try text/html:
   >> Matched: (second) GET /try/ [2]
   >> Outcome: Success(200 OK)
   >> Response succeeded.
GET / text/html:
   >> Matched: (index) GET /
   >> Outcome: Success(200 OK)
   >> Response succeeded.
GET /try/img/image.png:
   >> Matched: (FileServer: assets) GET /try/<path..> [4]
   >> Outcome: Success(200 OK)
   >> Remote left: channel closed.
GET /img/image.png:
   >> Matched: (FileServer: assets) GET /<path..> [5]
   >> Outcome: Success(200 OK)
   >> Remote left: channel closed.

@allmywatts

Thanks a lot for your help, this is what I wanted! In my opinion, it's a bit counterintuitive though, because it's necessary to use ranks which are not present in the web-app.

I do not know if it's the same problem, but it happened a similar situation with /favicon.ico which I have not defined in my web-app. So am I obliged to define it? Is it always related to ranks the I/O error or something different?

2023-12-15T22:31:40.457+01:00 [Runtime]  INFO rocket::server: GET /favicon.ico image/avif:
2023-12-15T22:31:40.457+01:00 [Runtime]  INFO rocket::server::_: Matched: (FileServer: assets) GET /<path..> [4]
2023-12-15T22:31:40.457+01:00 [Runtime]  WARN rocket::response::debug::_: I/O Error: Os { code: 2, kind: NotFound, message: "No such file or directory" }
2023-12-15T22:31:40.457+01:00 [Runtime]  INFO rocket::server::_: Outcome: Forward(404 Not Found)
2023-12-15T22:31:40.457+01:00 [Runtime] ERROR rocket::server::_: No matching routes for GET /favicon.ico image/avif.
2023-12-15T22:31:40.457+01:00 [Runtime]  WARN rocket::server::_: Responding with registered (not_found) 404 catcher.

Thanks a lot for your help, this is what I wanted! In my opinion, it's a bit counterintuitive though, because it's necessary to use ranks which are not present in the web-app.

What do you mean by "not present"? Ranks are something you assign to routes to determine which order to try conflicting routes in. The code presented worked ask you wanted because it instructs Rocket to try the one route before the FileServer route (since the one route is ranked lower).

I do not know if it's the same problem, but it happened a similar situation with /favicon.ico which I have not defined in my web-app. So am I obliged to define it? Is it always related to ranks the I/O error or something different?

That's a request coming in from the browser. There's nothing wrong with this I/O error - it simply means that the file server couldn't find the file that was requested and is forwarding the request, as it indicates.