Rust Axum Get Full URI request
Asked Answered
U

2

6

Trying to get the full request URI (scheme + authority + path)

I have found the discussion: https://github.com/tokio-rs/axum/discussions/1149 which says that Request.uri() should have it. So I tried the following:

use axum::body::Body;
use axum::http::Request;
use axum::routing::get;
use axum::Router;

async fn handler(req: Request<Body>) -> &'static str {
    println!("The request is: {}", req.uri());
    println!("The request is: {}", req.uri().scheme_str().unwrap());
    println!("The request is: {}", req.uri().authority().unwrap());

    "Hello world"
}

#[tokio::main]
async fn main() {
    let app = Router::new().route("/test", get(handler));

    axum::Server::bind(&"0.0.0.0:8080".parse().unwrap())
        .serve(app.into_make_service())
        .await
        .unwrap();
}

And run curl -v "http://localhost:8080/test" but I get:

The request is: /test
thread 'tokio-runtime-worker' panicked at 'called `Option::unwrap()` on a `None` value', src/main.rs:8:59

It seems like it only contains the path.

I also found the other discussion: https://github.com/tokio-rs/axum/discussions/858 which suggests that axum::http::Uri should be able to extract all the details, but I get the same issue:

use axum::http::Uri;
use axum::routing::get;
use axum::Router;

async fn handler(uri: Uri) -> &'static str {
    println!("The request is: {}", uri);
    println!("The request is: {}", uri.scheme_str().unwrap());
    println!("The request is: {}", uri.authority().unwrap());

    "Hello world"
}

#[tokio::main]
async fn main() {
    let app = Router::new().route("/test", get(handler));

    axum::Server::bind(&"0.0.0.0:8080".parse().unwrap())
        .serve(app.into_make_service())
        .await
        .unwrap();
}

curl -v "http://localhost:8080/test"

The request is: /test
thread 'tokio-runtime-worker' panicked at 'called `Option::unwrap()` on a `None` value', src/main.rs:7:53
> cargo -V
cargo 1.68.0-nightly (2381cbdb4 2022-12-23)

> rustc --version
rustc 1.68.0-nightly (ad8ae0504 2022-12-29)

Cargo.toml

[package]
name = "axum_test"
version = "0.1.0"
edition = "2021"

[dependencies]
axum = "0.6.10"
tokio = { version = "1.26.0", features = ["macros", "rt-multi-thread"] }
Unfetter answered 5/3, 2023 at 2:16 Comment(4)
what about don't unwrap ? I don't understand your question.Rondarondeau
I have a basic local server running on localhost on port 8080. And I make a request to my server at http://127.0.0.1/test. How can I get axum to give me the full request URL, which is expected to be http://127.0.0.1/test. Using both Request.uri() and axum::http::Uri only gives me the path /test and not http://127.0.0.1/test. Axum should be able to give me the full request URI, right? I don't want to hardcode the values http, 127.0.0.1, and 8080 to reconstruct the whole URL. It makes it less flexible. I briefly used actix-web and I was able to get the full request URLUnfetter
its look axium doesn't give you that information, I suggest you open an issueRondarondeau
github.com/tokio-rs/axum/blob/main/examples/http-proxy/src/…Rondarondeau
R
3

The Uri in Request only provides path. You could use the Host extractor:

use axum::extract::Host;
use axum::http::Request;

#[tokio::main]
async fn main() {
    // ...
    let app = Router::new()
        .route(
            "/",
            any(|Host(hostname): Host, request: Request<Body>| async move {
                format!("Hi {hostname}")
            }),
        )
        .layer(Extension(state));
    // ...
}
Retainer answered 15/6, 2023 at 3:16 Comment(0)
M
0

axum::http::request::Parts.uri gives you the full request URL, including scheme and authority.

Custom extractor to get an url::URL:

use async_trait::async_trait;
use url::Url;
use axum::extract::FromRequestParts;
use http::StatusCode;

struct Host(Url);

#[async_trait]
impl<S> FromRequestParts<S> for Host
where
    S: Send + Sync,
{
    type Rejection = (StatusCode, &'static str);

    async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result<Self, Self::Rejection> {
        let url =
            Url::parse(&parts.uri.to_string()).map_err(|_| (StatusCode::BAD_REQUEST, "Invalid URL"))?;
        Ok(Host(url))
    }
}
Manley answered 30/7, 2024 at 7:50 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.