Hi all,
I'm trying to write an asynchronous middleware for actix-web. The code as I have it so far is below.
use actix_web::{HttpRequest, HttpResponse, HttpMessage, Result, Error};
use actix_web::middleware::{Middleware, Started};
use actix_web::http::Method;
use futures::{Future, future, future::Either};
use uuid::Uuid;
use std::collections::HashMap;
const CONTENT_TYPE_FORM_DATA: &'static str = "application/x-www-form-urlencoded";
const FORM_VALUE_AUTHN_ID: &'static str = "authnId";
pub struct AuthenticationMiddleware {
pub unauthenticated_routes: Vec<String>
}
impl AuthenticationMiddleware {
fn get_authn_id<S: 'static>(&self, req: &HttpRequest<S>) -> impl Future<Item=Option<Uuid>, Error=Error> {
if req.method() == Method::POST && req.content_type() == CONTENT_TYPE_FORM_DATA {
let fut = req.urlencoded::<HashMap<String, String>>()
.from_err()
.and_then(move |form_values| {
if form_values.contains_key(FORM_VALUE_AUTHN_ID) {
if let Some(value) = form_values.get(FORM_VALUE_AUTHN_ID) {
match Uuid::parse_str(value) {
Ok(authn_id) => Either::A(future::ok(Some(authn_id))),
_ => Either::B(self.get_authn_id_from_cookie(req))
}
}
else {
Either::B(self.get_authn_id_from_cookie(req))
}
}
else {
Either::B(self.get_authn_id_from_cookie(req))
}
});
Either::A(fut)
}
else {
Either::B(self.get_authn_id_from_cookie(req))
}
}
fn get_authn_id_from_cookie<S>(&self, req: &HttpRequest<S>) -> impl Future<Item=Option<Uuid>, Error=Error> {
future::ok(None)
}
}
impl<S: 'static> Middleware<S> for AuthenticationMiddleware {
fn start(&self, req: &HttpRequest<S>) -> Result<Started> {
let request_path = req.path();
if self.unauthenticated_routes.iter().any(|path| request_path.starts_with(path)) {
// The path does not require authentication. Proceed to next middleware.
Ok(Started::Done)
}
else {
let fut = self.get_authn_id(req)
.from_err()
.and_then(|authn_id| {
match authn_id {
Some(authn_id) => future::ok(None),
None => future::ok(Some(HttpResponse::Ok().finish()))
}
});
Ok(Started::Future(Box::new(fut)))
}
}
}
When I compile, I'm getting the following errors:
error: cannot infer an appropriate lifetime
--> /Users/jveatch/repos/wovelocity/GridIron/GridIron/server/src/web/middleware/actix/mod.rs:20:27
|
16 | fn get_authn_id<S: 'static>(&self, req: &HttpRequest<S>) -> impl Future<Item=Option<Uuid>, Error=Error> {
| ------------------------------------------- this return type evaluates to the `'static` lifetime...
...
20 | .and_then(move |form_values| {
| ___________________________^
21 | | if form_values.contains_key(FORM_VALUE_AUTHN_ID) {
22 | | if let Some(value) = form_values.get(FORM_VALUE_AUTHN_ID) {
23 | | match Uuid::parse_str(value) {
... |
34 | | }
35 | | });
| |_________________^ ...but this borrow...
|
note: ...can't outlive the anonymous lifetime #1 defined on the method body at 16:5
--> /Users/jveatch/repos/wovelocity/GridIron/GridIron/server/src/web/middleware/actix/mod.rs:16:5
|
16 | / fn get_authn_id<S: 'static>(&self, req: &HttpRequest<S>) -> impl Future<Item=Option<Uuid>, Error=Error> {
17 | | if req.method() == Method::POST && req.content_type() == CONTENT_TYPE_FORM_DATA {
18 | | let fut = req.urlencoded::<HashMap<String, String>>()
19 | | .from_err()
... |
41 | | }
42 | | }
| |_____^
help: you can add a constraint to the return type to make it last less than `'static` and match the anonymous lifetime #1 defined on the method body at 16:5
|
16 | fn get_authn_id<S: 'static>(&self, req: &HttpRequest<S>) -> impl Future<Item=Option<Uuid>, Error=Error> + '_ {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0621]: explicit lifetime required in the type of `req`
--> /Users/jveatch/repos/wovelocity/GridIron/GridIron/server/src/web/middleware/actix/mod.rs:16:65
|
16 | fn get_authn_id<S: 'static>(&self, req: &HttpRequest<S>) -> impl Future<Item=Option<Uuid>, Error=Error> {
| --------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'static` required
| |
| help: add explicit lifetime `'static` to the type of `req`: `&'static actix_web::HttpRequest<S>`
I'm still trying to figure out lifetimes. I can't figure out what this error means or how to correct it. Any help would be appreciated.