Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

make FilteredService::call_with_addr() public #964

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

wfraser
Copy link

@wfraser wfraser commented Apr 29, 2022

This is an alternative to #713 which doesn't make breaking changes to any public interfaces.

This allows a caller to invoke the filter and manually specify a remote address, since this doesn't automatically get passed along when using one's own listener.

Invoking this properly is a bit involved, because it requires doing a bunch of Hyper service boilerplate, but if you're making your own listener, you probably don't mind doing this too.

My concrete use case is I want to listen on a socket opened by systemd, which it provides via a file descriptor. I can't call warp::Server::bind() with a file descriptor, and I can't pass the SocketAddr for that socket because Systemd is already listening on it on my behalf. I can make a TcpListener from a file descriptor just fine, but then Warp won't let me see the remote peers' addresses without this.

example of use:

    let filter = warp::filters::addr::remote()
        .map(|addr| format!("hello {:?}!", addr));

    let svc = warp::service(filter);
    let make_svc = make_service_fn(move |conn: &AddrStream| {
        let svc = svc.clone();
        let remote = conn.remote_addr();
        ready::<Result<_, Infallible>>(Ok(service_fn(move |req| {
            svc.call_with_addr(req, Some(remote))
        })))
    });

    hyper::Server::builder(MyCustomListener::new().await)
        .serve(make_svc)
        .await?;

Full compilable program:

Cargo.toml:

[package]
name = "warp-addr-inject"
version = "0.1.0"
edition = "2021"

[dependencies]
hyper = "0.14.18"
tokio = { version = "1.18.0", features = ["macros", "rt-multi-thread"] }
warp = "0.3.2"

src/main.rs:

use hyper::server::accept::Accept;
use hyper::server::conn::{AddrIncoming, AddrStream};
use hyper::service::{make_service_fn, service_fn};
use std::convert::Infallible;
use std::future::ready;
use std::io;
use std::pin::Pin;
use std::task::{Context, Poll};
use tokio::net::TcpListener;
use warp::Filter;

#[tokio::main]
async fn main() -> Result<(), hyper::Error> {
    let filter = warp::filters::addr::remote()
        .map(|addr| format!("hello {:?}!", addr));

    let svc = warp::service(filter);
    let make_svc = make_service_fn(move |conn: &AddrStream| {
        let svc = svc.clone();
        let remote = conn.remote_addr();
        ready::<Result<_, Infallible>>(Ok(service_fn(move |req| {
            svc.call_with_addr(req, Some(remote))
        })))
    });

    hyper::Server::builder(MyCustomListener::new().await)
        .serve(make_svc)
        .await?;

    Ok(())
}

struct MyCustomListener {
    inner: hyper::server::conn::AddrIncoming,
}

impl MyCustomListener {
    pub async fn new() -> Self {
        // for example only, actual use case is more involved than this
        let listener = TcpListener::bind("127.0.0.1:42069").await.unwrap();
        let inner = AddrIncoming::from_listener(listener).unwrap();
        Self { inner }
    }
}

impl Accept for MyCustomListener {
    type Conn = AddrStream;
    type Error = io::Error;

    fn poll_accept(self: Pin<&mut Self>, cx: &mut Context<'_>)
        -> Poll<Option<Result<Self::Conn, Self::Error>>>
    {
        // this is where my custom cool listener logic lives, but for demo purposes do this
        // instead:
        Pin::new(&mut self.get_mut().inner)
            .poll_accept(cx)
    }
}

This allows a caller to invoke the filter and manually specify a remote address, since this doesn't automatically get passed along when using one's own listener.
@NishantJoshi00
Copy link

NishantJoshi00 commented Jan 12, 2024

Is there any update on this? Also, Why was the visibility of this function restricted to be crate-only in the first place?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants