0

I'm trying to handle cors requests in my rocket application, I have followed the rocket_cors guard example by creating and manageing a cors struct, then mounting rocket_cors::catch_all_options_routes(). This causes a trait bound error.

main.rs

...

#[rocket::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let cors = rocket_cors::CorsOptions::default().to_cors()?;
    let _ = rocket::build()
        .mount("/", routes![sample, sample_index])
        .mount("/", rocket_cors::catch_all_options_routes())
        .attach(Shield::new())
        .attach(Db::init())
        .manage(cors)
        .launch().await?;
    Ok(())
}

Cargo.toml

[dependencies.rocket]
version = "0.5.0-rc.2"
features = ["json"]

[dependencies]
rocket_cors = "0.5.2"

Error

error[E0277]: the trait bound `Vec<Route>: From<Vec<rocket::router::route::Route>>` is not satisfied
   --> src/main.rs:313:21
    |
313 |         .mount("/", rocket_cors::catch_all_options_routes())
    |          -----      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `From<Vec<rocket::router::route::Route>>` is not implemented for `Vec<Route>`
    |          |
    |          required by a bound introduced by this call
    |
    = help: the trait `From<FileServer>` is implemented for `Vec<Route>`
    = note: required for `Vec<rocket::router::route::Route>` to implement `Into<Vec<Route>>`
note: required by a bound in `Rocket::<Build>::mount`
   --> /home/aiden/.cargo/registry/src/github.com-1ecc6299db9ec823/rocket-0.5.0-rc.2/src/rocket.rs:341:18
    |
341 |               R: Into<Vec<Route>>
    |                  ^^^^^^^^^^^^^^^^ required by this bound in `Rocket::<Build>::mount`

For more information about this error, try `rustc --explain E0277`.
KillerHawk
  • 33
  • 7

2 Answers2

1

The 0.5.2 version of rocket_cors uses types and implements traits for Rocket 0.4 which is incompatible with Rocket 0.5.0-rc.2. You'll need to either downgrade Rocket or upgrade rocket_cors to 0.6.0-alpha1.

kmdreko
  • 42,554
  • 6
  • 57
  • 106
  • Thanks for the quick answer. I cant downgrade rocket, and simply changing rocket_cors' verion to 0.6.0-alpha1 left me with scope errors from fairing.rs and lib.rs. This is likely a result of the crate still being in alpha. Should I keep trying to get rocket_cors 0.6 to work? Or would you happen to know of any examples getting cors to work in rocket 0.5? – KillerHawk Jan 07 '23 at 02:37
  • @KillerHawk I don't really have other suggestions if the alpha version doesn't work. – kmdreko Jan 07 '23 at 02:45
0

The accepted answer explains why rocket_cors was throwing trait bound errors, but still doesn't get CORS up and running in rocket 0.5. After bashing my head against this for a couple of days, I finally got my solution. If you do not understand CORS, I strongly recommend reading the MDN documentation. In my case, I needed to handle the OPTIONS preflight request.


For a preflight to succeed, you need to have the "Access-Control-Allow-Origin" header set on an OPTIONS route in rocket. This route should return rocket::response::status::NoContent.

I solved this by adding CORS headers to all methods and manually catching all options routes. Ideally, you should only apply CORS headers to requests that require them, as it may be unsafe to do a catch-all like this.


First I created a CORS fairing based off of this answer

use rocket::http::Header;
use rocket::{Request, Response};
use rocket::fairing::{Fairing, Info, Kind};

pub struct CORS;

#[rocket::async_trait]
impl Fairing for CORS {
  fn info(&self) -> Info {
    Info {
      name: "Add CORS headers to responses",
      kind: Kind::Response
    }
  }

  async fn on_response<'r>(&self, _request: &'r Request<'_>, response: &mut Response<'r>) {
    response.set_header(Header::new("Access-Control-Allow-Origin", "*"));
    response.set_header(Header::new("Access-Control-Allow-Methods", "POST, GET, OPTIONS"));
    response.set_header(Header::new("Access-Control-Allow-Headers", "*"));
    response.set_header(Header::new("Access-Control-Allow-Credentials", "true"));
  }
}

Then, I caught all OPTIONS requests and responded with NoContent

use rocket::response::status::NoContent;

#[options("/<_..>")]
fn preflight() -> NoContent {
  NoContent
}

Finally, I attached the route and fairing to the rocket build

rocket::build()
  .attach(CORS).mount("/", routes![preflight, ..])
KillerHawk
  • 33
  • 7