warp icon indicating copy to clipboard operation
warp copied to clipboard

Can't have a function returning a `Wrap`

Open akriegman opened this issue 3 years ago • 1 comments

Version 0.3.2

Platform Linux sufjan 5.15.0-46-generic #49~20.04.1-Ubuntu SMP Thu Aug 4 19:15:44 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux

Description Thanks to the wrap_fn function, warp users are able to create their own Wraps for use with .with(). Super cool! However, in order to have a nice reusable Wrap, I would like to have a function that returns a Wrap. We can do something similar with filters by making a function that returns impl Filter<...>. However, this doesn't work with Wrap because Wrap, WrapSealed, and the concrete type WrapFn are all private, so afaict there's no way for me to define a function that returns the result of wrap_fn.

Here's the (pseudo)code that I want to write:

// auth.rs

fn basic<F: Filter>(user: String, pass: String) -> impl Wrap<F> {
    wrap_fn(|filter: F| {
        ...
    })
}

I would also be happy to put the concrete type WrapFn<???> as the return type instead. However, instead I had to write the following code:

#[macro_export]
macro_rules! basic {
    ($user:expr, $pass:expr) => {{
        use tap::Pipe;

        let credentials =
            Some("Basic ".to_string() + &base64::encode(format!("{}:{}", $user, $pass)));

        let check_creds = move |auth: Option<String>| {
            if auth == credentials {
                Ok(())
            } else {
                Err(reject::custom($crate::auth::AuthorizationRequired))
            }
            .pipe(|ret| async { ret })
        };

        wrap_fn(move |filter| {
            header::optional("authorization")
                .and_then(check_creds.clone())
                .and(filter)
                .map(|(), res| res)
                .recover(|rej: Rejection| async {
                    if let Some($crate::auth::AuthorizationRequired) = rej.find() {
                        Ok(hyper::Response::builder()
                            .status(401)
                            .header("WWW-Authenticate", "Basic")
                            .body("")
                            .unwrap())
                    } else {
                        Err(rej)
                    }
                })
        })
    }};
}

This shouldn't be a macro, but I couldn't make it a function, so this was the next best way to make my wrapper reusable. I also noticed that the Wrap trait is marked as pub, but it's in the private module warp::filter::wrap and isn't re-exported anywhere, so it's inaccessible to the user. Did you mean to re-export Wrap so that it can be used like Filter?

akriegman avatar Sep 12 '22 16:09 akriegman

Today I tried to do something similar as well. I was attempting to make my own CORS wrapper using WrapFn as the built-in one didn't fit my needs very well. I ended up just passing in a function and handling it differently.

infiniwave avatar Sep 17 '22 16:09 infiniwave