17

Is this is the only possibility to get the content-type header from an Actix-Web request? This has to check if the header is available or if to_str failed...

let req: actix_web::HttpRequest;

let content_type: &str = req
    .request()
    .headers()
    .get(actix_web::http::header::CONTENT_TYPE)
    .unwrap()
    .to_str()
    .unwrap();
3
  • str != String ! Commented Oct 21, 2018 at 20:25
  • 1
    What should this tell me? I know that str is different from String... the first unwrap doesn't return a String, this is a HeaderValue, if this would be the idea... or because of the title? I've put in a "string value". ;-) Commented Oct 22, 2018 at 10:25
  • I guess you could replace .unwrap().to_str() with .and_then(HeaderValue::to_str) to have one less panic risk. Commented Oct 24, 2018 at 15:59

3 Answers 3

19

Yes, that is the "only" possibility, but it's like that because:

  1. The header may not exist, headers().get(key) returns Option.
  2. The header may have non-ASCII chars, and HeaderValue::to_str might fail.

actix-web lets you handle those errors individually.

To simplify, you could make a helper function that does not differentiate between the two errors:

fn get_content_type<'a>(req: &'a HttpRequest) -> Option<&'a str> {
    req.headers().get("content-type")?.to_str().ok()
}

Full example:

use actix_web::{web, App, HttpRequest, HttpServer, Responder};

fn main() {
    HttpServer::new(|| App::new().route("/", web::to(handler)))
        .bind("127.0.0.1:8000")
        .expect("Cannot bind to port 8000")
        .run()
        .expect("Unable to run server");
}

fn handler(req: HttpRequest) -> impl Responder {
    if let Some(content_type) = get_content_type(&req) {
        format!("Got content-type = '{}'", content_type)
    } else {
        "No content-type header.".to_owned()
    }
}

fn get_content_type<'a>(req: &'a HttpRequest) -> Option<&'a str> {
    req.headers().get("content-type")?.to_str().ok()
}

Which will give you the results:

$ curl localhost:8000
No content-type header.⏎
$ curl localhost:8000 -H 'content-type: application/json'
Got content-type = 'application/json'⏎
$ curl localhost:8000 -H 'content-type: 💩'
No content-type header.⏎

By the way, you may be interested in guards:

web::route()
    .guard(guard::Get())
    .guard(guard::Header("content-type", "text/plain"))
    .to(handler)
Sign up to request clarification or add additional context in comments.

2 Comments

Ok. I've expected that a webframework provides something like your fn get_content_type and not everybody needs to reinvent it. But thanks.
@Markus Depends on your perspective. actix-web gives you an API to the HTTP-protocol, with all the things that might fail. In this lower level context, getting the content type is straight forward. If you only want to work at a higher level, you can copy this code and publish it to crates.io 😉
3

I use the following from a route:

#[get("/auth/login")]
async fn login(request: HttpRequest, session: Session) -> Result<HttpResponse, ApiError> {
    let req_headers = request.headers();

    let basic_auth_header = req_headers.get("Authorization");
    let basic_auth: &str = basic_auth_header.unwrap().to_str().unwrap();
    // Keep in mind that calling "unwrap" here could make your application
    // panic. The right approach at this point is to evaluate the resulting
    // enum variant from `get`'s call

    println!("{}", basic_auth); // At this point I have the value of the header as a string

    // ...
}

4 Comments

Forgive my newbie question but what does Actix do/return when your unwrap fails, for example if you have an emoji in the header value?
No problem, all questions are valid questions! When you call unwrap on any value, Rust your thread will panic if the resulting variant is either Err or None (based on the type returned), and application exits. Using unwrap most of the time is not recommended, the right approach is to handle the variant resulting from the get call.
Thank you, it works! Note that request and session on the example are injected by the framework automagically.
@DavidBell the handler crashes (panics), but the application does not exit as Esteban says, and the client will not get a proper response, the actix server will continue just fine though.
0

Allways create a function for that purpose. This is an example for detect if an actix web request is sended by htmx.

use actix_web::HttpRequest;

pub fn is_htmx_request(req: HttpRequest) -> bool {
  match req.headers().get("HX-Request") {
    Some(header) => match header.to_str() {
      Ok(value) => value == "true",
      _ => false,
    },
    _ => false,
  }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.