Get client IP in hyper server

Hello
I wrote a web server with hyper.
and I want to get the client IP that requested to the server.
my code :

async fn show_headers(req: Request<Body>) -> Result<Response<Body>, Infallible> {
    let ip = "test!";
    let mut headers = format!(
        "{}\n{}\n\r{} {} {}\n",
        ip,
        std::iter::repeat("-").take(ip.len()).collect::<String>(),
        req.method(),
        req.uri().path_and_query().unwrap(),
        match req.version() {
            hyper::Version::HTTP_09 => "HTTP/0.9",
            hyper::Version::HTTP_10 => "HTTP/1.0",
            hyper::Version::HTTP_11 => "HTTP/1.1",
            hyper::Version::HTTP_2 => "HTTP/2.0",
            hyper::Version::HTTP_3 => "HTTP/3.0",
            _ => "Invalid",
        }
    );
    for (key, value) in req.headers() {
        headers.push_str(&format!(
            "{}: {}\r\n",
            key,
            match value.to_str() {
                Ok(value) => value,
                Err(_) => "",
            }
        ));
    }
    Ok(Response::new(Body::from(format!("{}", headers))))
}

The information is provided to the make_service_fn through the remote_addr method on the parameter on the closure, and you will have to pass the address further inside manually.

thanks but
I'm a newbie in Rust
could you please explain to how to do that?

If you're using hyper as a server, you probably have a make_service_fn somewhere in your code. Can you post that part?

Sure

let make_service =
make_service_fn(|_conn| async { Ok::<_, Infallible>(service_fn(show_headers)) });
let server = Server::bind(&addr).serve(make_service);

Thanks

You'll want something like this:

async fn show_headers(req: Request<Body>, addr: SocketAddr) -> Result<Response<Body>, Infallible> {
    ...
}

let make_service =
    make_service_fn(|conn| async {
        let addr = conn.remote_addr();
        Ok::<_, Infallible>(service_fn(move |req| show_headers(req, addr)))
    });
let server = Server::bind(&addr).serve(make_service);

I did but
There is an error :expressionless:

error[E0282]: type annotations needed for `&Target`
  --> src/main.rs:49:50
   |
49 |         let make_service = make_service_fn(move |conn| {
   |                                                  ^^^^ consider giving this closure parameter the explicit type `&Target`, where the type parameter `Target` is specified
   |
   = note: type must be known at this point

Give this a try:

use hyper::server::conn::AddrStream;

let make_service =
    make_service_fn(|conn: AddrStream| async {
        let addr = conn.remote_addr();
        Ok::<_, Infallible>(service_fn(move |req| show_headers(req, addr)))
    });
let server = Server::bind(&addr).serve(make_service);

I haven't set it up to try it locally.

didn't work :pensive:
errors:

error[E0631]: type mismatch in closure arguments
   --> src/main.rs:58:5
    |
58  |       make_service_fn(|conn: AddrStream|
    |  _____^^^^^^^^^^^^^^^_-
    | |     |
    | |     expected signature of `for<'r> fn(&'r _) -> _`
59  | |          async {
60  | |         let addr = conn.remote_addr();
61  | |         Ok::<_, Infallible>(service_fn(move |req| show_headers(req, addr)))
62  | |     });
    | |_____- found signature of `fn(hyper::server::tcp::addr_stream::AddrStream) -> _`
    | 
   ::: /home/sajjad/.cargo/registry/src/github.com-1ecc6299db9ec823/hyper-0.13.4/src/service/make.rs:140:8
    |
140 |       F: FnMut(&Target) -> Ret,
    |          --------------------- required by this bound in `hyper::service::make::make_service_fn`

and 3 more errors :man_facepalming:

Ah right, that should be &AddrStream.

Yes right :slightly_smiling_face: :pray:
but 1 error has occurred about lifetimes
I tried to fix that but I do not have enough experience :pensive:

code:

let make_service =
    make_service_fn(|conn: &AddrStream|{

         async {
             let addr=conn.remote_addr();
        Ok::<_, Infallible>(service_fn(move |req| show_headers(req, addr.clone())))
    }});

and the error:

error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
  --> src/main.rs:60:16
   |
60 |            async {
   |  ________________^
61 | |              let addr=conn.remote_addr();
62 | |         Ok::<_, Infallible>(service_fn(move |req| show_headers(req, addr.clone())))
63 | |     }});
   | |_____^

Ah, it should be async move.

1 Like

Yes, thank you so much :pray: :heart:
I made a few more changes and it was totally done
final code :

let make_service =
    make_service_fn(move |conn: &AddrStream|{
        let addr = conn.remote_addr();
         async move {
             let addr=addr.clone();
        Ok::<_, Infallible>(service_fn(move |req| show_headers(req, addr.clone())))
    }});
2 Likes

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.