How to fix "expected bound lifetime parameter, found concrete lifetime"

I am adding a middleware to actix_web according to the wrap_fn documentation. This works fine, but I would like to move the code from a closure into a seperate function. Doing that results in the following error:

error[E0271]: type mismatch resolving `for<'r> <for<'_> fn(lemmy_server::actix_web::dev::ServiceRequest, &mut lemmy_server::actix_web::app_service::AppRouting) -> impl std::future::Future {add_cache_headers::<lemmy_server::actix_web::app_service::AppRouting>} as std::ops::FnOnce<(lemmy_server::actix_web::dev::ServiceRequest, &'r mut lemmy_server::actix_web::app_service::AppRouting)>>::Output == _`
--> src/main.rs:68:8
|
68 |       .wrap_fn(add_cache_headers)
|        ^^^^^^^ expected bound lifetime parameter, found concrete lifetime

I have tried a lot of things already, but nothing worked. Can you give any advice how to fix this? Here is the code:

fn main() {
    let app = App::new()
        .wrap_fn(add_cache_headers);
    ...
}

async fn add_cache_headers<S>(req: ServiceRequest, srv: &mut S) -> Result<ServiceResponse, Error>
where
  S: Service<Request = ServiceRequest, Response = ServiceResponse<Body>, Error = Error>,
{
  let fut = srv.call(req);
  let mut res = fut.await?;
  if let Some(content_type) = res.headers().get(CONTENT_TYPE) {
    if CACHE_CONTROL_REGEX.is_match(content_type.to_str().unwrap()) {
      let header_val = HeaderValue::from_static("public, max-age=3600");
      res.headers_mut().insert(CACHE_CONTROL, header_val);
    }
  }
  Ok(res)
}

The issue is that wrap_fn does not allow the returned future to borrow from the srv argument, but it will always do so with an async fn. Try returning an async block instead:

fn add_cache_headers<S>(req: ServiceRequest, srv: &mut S) -> impl Future<Output = Result<ServiceResponse, Error>>
where
    S: Service<Request = ServiceRequest, Response = ServiceResponse<Body>, Error = Error>,
{
    // we access srv before creating the async block, so the returned async block doesn't
    // need to access srv
    let fut = srv.call(req);
    async move {
        let mut res = fut.await?;
        if let Some(content_type) = res.headers().get(CONTENT_TYPE) {
            if CACHE_CONTROL_REGEX.is_match(content_type.to_str().unwrap()) {
                let header_val = HeaderValue::from_static("public, max-age=3600");
                res.headers_mut().insert(CACHE_CONTROL, header_val);
            }
        }
        Ok(res)
    }
}

That did it, who knew it could be so easy! Thank you :slight_smile:

This is actually almost the same code as in the actix documentation, but I couldnt figure out the right return type.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.