In setting up a couple of endpoints using Rocket (written in rust), I was able to easily get up the GET and POST handlers that I needed. These worked fine with all my testing in Postman.
However, when it came to real world testing, the browser was getting blocked due to CORS. So I found this Stack Overflow article, and was able to implement the CORS headers based off that:
https://stackoverflow.com/questions/62412361/how-to-set-up-cors-or-options-for-rocket-rs
This worked. Up to a point.
That point was the browser sending a preflight OPTIONS request, which is neither a GET or a POST. After floundering around with various efforts, such as trying to put a wildcard #[options()]
handler (which never got picked up by the compiler for some reason; kept getting the message that the following function was unused), and so on, I finally landed on the solution.
Taking the recommended implementation of on_response():
fn on_response(&self, request: &Request, response: &mut Response) {
response.set_header(Header::new("Access-Control-Allow-Origin", "<em>"));
response.set_header(Header::new("Access-Control-Allow-Methods", "POST, GET, PATCH, OPTIONS"));
response.set_header(Header::new("Access-Control-Allow-Headers", "</em>"));
response.set_header(Header::new("Access-Control-Allow-Credentials", "true"));
}
All that was needed was to add a few lines:
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", "GET, POST, OPTIONS"));
response.set_header(Header::new("Access-Control-Allow-Headers", "Content-Type"));
response.set_header(Header::new("Access-Control-Request-Method", "GET, POST, OPTIONS"));
if request.method() == Method::Options {
let body = "";
response.set_header(ContentType::Plain);
response.set_sized_body(body.len(), std::io::Cursor::new(body));
response.set_status(Status::Ok);
}
}
This worked to get the proper headers in place, and also overcome the 404 errors. The 404 errors were coming because I had no explicit #[options()];
route handler in place – they just weren’t taking for some reason, as mentioned above. So the last line, response.set_status(Status::Ok);
is what fixed that problem. This allowed the client to send an Options preflight request, which Rocket responded to with all the right bits, and without a 404 status coming back.
And to cut down on the length of messages about these requests in the shell, I implemented a catcher too, which are still present, due to the missing route handler:
#[catch(404)]
fn not_found(req: &Request<'_>) -> String {
if req.method() == Method::Options {
return "".to_string();
}
format!("Sorry, '{}' is not a valid path.", req.uri())
}
Attach the handler, and, bang! we’ve got a working set of endpoints handling CORS requests, with preflight Options requests. Rust with Rocket is very performant too – a release build responds with an average time of 63 milliseconds, most of which is probably the database query time.