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

Can't have a function returning a Wrap #994

Open
akriegman opened this issue Sep 12, 2022 · 1 comment
Open

Can't have a function returning a Wrap #994

akriegman opened this issue Sep 12, 2022 · 1 comment
Labels
bug Something isn't working

Comments

@akriegman
Copy link

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 akriegman added the bug Something isn't working label Sep 12, 2022
@infiniwave
Copy link

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants