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

(async) How to get request guard in responder? #1953

Closed
couchand opened this issue Oct 20, 2021 · 2 comments
Closed

(async) How to get request guard in responder? #1953

couchand opened this issue Oct 20, 2021 · 2 comments
Labels
triage A bug report being investigated

Comments

@couchand
Copy link

Description

When updating an 0.4 application to 0.5, I've discovered a hiccup that I've not yet found a workaround for. We have a custom Responder impl on our error type that uses a request guard to determine how to respond: authenticated users get redirected to an error page with some details, but unauthenticated users get redirected to /login with a bare-bones message.

Unfortunately, in 0.5 Request::guard is async, but Responder::respond_to is sync. In #1065 (comment) it was clarified that Responder is intentionally sync, which makes sense.

The only solution I can see here is to front-load the request guard into each and every handler and explicitly pass it along to the error type. That would work, but seems to be a big cudgel for what should be a pretty small problem. Any other ideas?

To Reproduce

pub struct SessionData;

#[rocket::async_trait]
impl<'r> FromRequest<'r> for SessionData {
    // ...
}

pub struct ErrorResponse;

impl<'r, 'o: 'r> response::Responder<'r, 'o> for ErrorResponse {
    fn respond_to(self, req: &'r Request<'_>) -> response::Result<'o> {
        // UNABLE TO AWAIT HERE
        match req.guard::<SessionData>() {
            // ...
        }
    }
}

Expected Behavior

Some way to get the value of a request guard in a responder.

@couchand couchand added the triage A bug report being investigated label Oct 20, 2021
@couchand
Copy link
Author

After further reflection, I think the best answer is to cache the guard in request-local storage, and rely on that in the responder. This is good enough for my purposes, though it is incomplete: on unauthenticated routes the session guard will never be invoked, so the request-local storage will be empty.

@tvallotton
Copy link

I've been working on a library for rocket and I've found myself in a similar situation. In my case, I'm trying to write a configurable LangCode request guard. This type would be used to get the preferred language for a client request and can hopefully be consumed by other values. This way users can do things like this:

use authentication_lib::{Error, Auth, LoginForm}; 
// here the handler returns an Error from the library which knows in what language 
// to display the error message because it can retrieve the `LangCode` guard in 
// the responder
// the user doesn't need to worry about that stuff because it is already handled by the library. 
// they just try `?` the error and move on. 
#[get("/foo/", data="<form>")]
fn login(form: LoginForm, auth: Auth<'_>) -> Result<Template, Error> {
     auth.login(form).await?;
     /* .. */
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
triage A bug report being investigated
Projects
None yet
Development

No branches or pull requests

2 participants