Working with http request results in lifetime issue

I am working on a simple AWS Lambda function that handles http requests.

I would like to match on http path and method.

struct HReq {
    http_path: &'static str,
    http_method: &'static str,
}

fn router(req: Request, ctx: Context) -> Result<impl IntoResponse, HandlerError> {
    let h_req = HReq {
        http_path: req.uri().path(),
        http_method: req.method().as_str(),
    };

    match h_req {
        HReq {
            http_path: "/login",
            http_method: "POST",
        } => user_login(req, ctx),

        _ => {
            let mut resp = Response::default();
            *resp.status_mut() = StatusCode::METHOD_NOT_ALLOWED;
            Ok(resp)
        }
    }
}

This does not compile because:

error[E0597]: `req` does not live long enough
  --> src/main.rs:36:20
   |
36 |         http_path: req.uri().path(),
   |                    ^^^------
   |                    |
   |                    borrowed value does not live long enough
   |                    argument requires that `req` is borrowed for `'static`
...
52 | }
   | - `req` dropped here while still borrowed

error[E0597]: `req` does not live long enough
  --> src/main.rs:37:22
   |
37 |         http_method: req.method().as_str(),
   |                      ^^^---------
   |                      |
   |                      borrowed value does not live long enough
   |                      argument requires that `req` is borrowed for `'static`
...
52 | }
   | - `req` dropped here while still borrowed

What is the right way of handling http path and methods?

You can't have static reference to ephemeral req. Either use &str or make it String and clone data.

Thanks @Fiedzia, I am not sure what you mean. For string like "POST" which can stay in memory the entire lifetime of the program, what is the best way in Rust to handle? In Ruby I would use symbols (:something) so that it gets allocated once in memory and I can keep referring to it from all over the place and never mutate it.

For string like "POST" which can stay in memory the entire lifetime of the program, what is the best way in Rust to handle?

for strings it would be:

static POST:&str = "POST";

but you don't need a string here, enum would be better.

so what you could have:

struct HReq<'a> {
    http_path: &'a str,
    http_method: &'a str,
}

or with enums:

enum HttpMethod {
    POST,
    GET,
    HEAD
    //...(it is probably already defined by whatever library you are using)
}

struct HReq<'a> {
    http_path: &'a str,
    http_method: HttpMethod,
}

1 Like

Practically, &'static str means string literal which is embeded directly on the data section of the program executable. If you want dynamically constructed owned string, use String instead which is a growable buffer contains UTF-8 data.

This is exactly what I was looking for. Thanks @Fiedzia!

Ended up doing this:

use http::{Method, StatusCode};

struct HReq<'a> {
    http_path: &'a str,
    http_method: &'a Method,
}

fn router(req: Request, ctx: Context) -> Result<impl IntoResponse, HandlerError> {
    let h_req = HReq {
        http_path: req.uri().path(),
        http_method: req.method(),
    };

    match h_req {
        HReq {
            http_path: "/login",
            http_method: &Method::POST,
        } => user_login(req, ctx),

        _ => {
            let mut resp = Response::default();
            *resp.status_mut() = StatusCode::METHOD_NOT_ALLOWED;
            Ok(resp)
        }
    }
}

Not sure if there is a downside using &'a Method like this.