Search code examples
rustlifetimeactix-webrust-futures

Using async functions within a Actix middleware


I'm making a rust API with Actix and Sqlx, and currently working on a JWT middleware, it's mostly done, but I'd like to retrieve the authorized user into my endpoints. That's what the code below is attempting, but I'm running into a lifetime issue.

fn call(&self, req: ServiceRequest) -> Self::Future {
    if ApiEnv::skip_auth() {
      return Box::pin(self.service.call(req));
    }

    // Box::pin(self.service.call(req))
    Box::pin(async move {
      let u = {
        let db: &Data<Database> = req.app_data().unwrap();
        let pool = db.pool.clone();
        let headers = req.headers().clone();
        let mut extensions = req.extensions_mut();

        match authorize(pool, headers).await {
          Ok(u) => {
            extensions.insert(u);
            Ok(())
          }, Err(e) => Err(e)
        }
      };
      
      match u {
        Ok(_) => { self.service.call(req).await } 
        Err(e) => Err(e)
      }
    })
  }

I'm getting the following error:

error: lifetime may not live long enough
   --> src/middleware/jwt.rs:98:5
    |
92  |     fn call(&self, req: ServiceRequest) -> Self::Future {
    |             - let's call the lifetime of this reference `'1`
...
98  | /     Box::pin(async move {
99  | |       let u = {
100 | |         let db: &Data<Database> = req.app_data().unwrap();
101 | |         let pool = db.pool.clone();
...   |
116 | |       }
117 | |     })
    | |______^ returning this value requires that `'1` must outlive `'static`

I know why this is: I'm using self.service.call inside of a Box::pin, but how do i fix it?

If I move self.service.call(req) outside of the Box::Pin, the req value is moved before i call let mut extensions = req.extensions_mut(); and extensions.insert(u), so as far as i know, i can't do that either.

There was a very similar issue here, but all the links either lead to deleted repo's, or one that calls self.service.clone(), despite Service not having a Clone trait

I'm pretty stuck, and I'm not an expert on Box::pin, so hopefully someone knows if there's a solution to this. Thanks for reading :)


Solution

  • After a few days I figured what was going on, the repo that had self.service.clone() wrapped Service in a Rc<> therefore being able to clone it. I missed it completely.