rustrust-axum

How to access user agent in Rust Axum's ConnectInfo custom impl?


Axum's into_make_service_with_connect_info provides the following way to access the IP address if the remote address:

https://docs.rs/axum/latest/axum/struct.Router.html#method.into_make_service_with_connect_info

Note how it says:

You can implement custom a Connected like so:

async fn handler(
    ConnectInfo(my_connect_info): ConnectInfo<MyConnectInfo>,
) -> String {
    format!("Hello {my_connect_info:?}")
}

#[derive(Clone, Debug)]
struct MyConnectInfo {
    // ...
}

impl Connected<IncomingStream<'_, TcpListener>> for MyConnectInfo {
    fn connect_info(target: IncomingStream<'_, TcpListener>) -> Self {
        MyConnectInfo {
            // ...
        }
    }
}

I am able to use this to have my custom MyConnectionInfo which can be accessed by all my routes:

#[derive(Clone, Debug)]
struct MyConnectionInfo {
    ip: String,
    user_agent: String,
}

impl Connected<IncomingStream<'_, TcpListener>> for MyConnectionInfo {
    fn connect_info(target: IncomingStream<'_, TcpListener>) -> Self {
        MyConnectionInfo {
            ip: target.remote_addr().to_string(), user_agent: "Firefox".to_string()
        }
    }
}

I am able to successfully get the target.remote_addr(). However, for the user agent, I am not sure how to access it within this custom impl. (note the currently hardcoded "Firefox" string).

Axum provides a way to get the user agent from the TypedHeader as below:

https://docs.rs/axum/latest/axum/extract/index.html

Is it possible to access this user agent and other headers within my custom impl?

Or is my approach wrong?


Solution

  • You cannot access the user agent from a Connected implementation.

    It is for retrieving metadata from the underlying connection - a TcpStream under typical conditions. The user agent on the other hand is only accessible from the HTTP headers which haven't even been parsed yet.

    If you do not need anything from the TCP layer beyond what ConnectInfo already can get, you likely just want a custom extractor (via a FromRequestParts implementation) from which you can get the existing ConnectInfo and any TypedHeaders as you require for your handlers or middleware.