0

I am trying to read request body using (req.into_body()) and generate a hash key based on parameters (request.uri and request.body) but as documentation states req.into_body() will consume request so I can't use the same variable below that line.

Question:

So how can I reuse the request variable consuming it. There is no clone function for request body either that I can use to replicate variable.

Below is the given sample code.

async fn readKey(req: Request<Body>) -> (String, Request<Body>) {
    let mut key: String;
    if (!req.method().as_str().eq("GET")) {
        let body_bytes = hyper::body::to_bytes(req.into_body()).await.unwrap();
        let body_string = String::from_utf8(body_bytes.to_vec()).unwrap();
        key = format!(
            "{}{}{}",
            req.uri().host().unwrap(),
            req.uri().path(),
            body_string
        );
    } else {
        key = format!("{}{}", req.uri().host().unwrap(), req.uri().path());
    }
    return (key, req);
}

Compilation error trace:

error[E0382]: borrow of moved value: `req`
   --> src/main.rs:72:33
    |
65  | async fn readKey(req: Request<Body>) -> (String , Request<Body>) {
    |                  --- move occurs because `req` has type `Request<Body>`, which does not implement the `Copy` trait
...
70  |         let body_bytes = hyper::body::to_bytes(req.into_body()).await.unwrap();
    |                                                    ----------- `req` moved due to this method call
71  |         let body_string = String::from_utf8(body_bytes.to_vec()).unwrap();
72  |         key = format!("{}{}{}", req.uri().host().unwrap(), req.uri().path(),body_string);
    |                                 ^^^^^^^^^ value borrowed here after move
    |
note: `Request::<T>::into_body` takes ownership of the receiver `self`, which moves `req`
   --> /Users/sunilsingh/.cargo/registry/src/github.com-1ecc6299db9ec823/http-0.2.9/src/request.rs:653:22
    |
653 |     pub fn into_body(self) -> T {
    |                      ^^^^
cafce25
  • 15,907
  • 4
  • 25
  • 31
nil96
  • 313
  • 1
  • 3
  • 12
  • 1
    Why do you use `into_parts` and then `from_parts`? – mkrieger1 Mar 26 '23 at 18:26
  • 2
    Side-note: You misspelled "borrow" as "burrow" twice (it's only spelled correctly in your error messages). If you legitimately think it's talking about "burrowing", I can absolutely see you having trouble understanding the concept... – ShadowRanger Mar 26 '23 at 18:33
  • @mkrieger1 that i added mistakenly.I thought of copying and then using it.Updated it now – nil96 Mar 26 '23 at 18:47
  • @ShadowRanger you might be correct i am very new to the language. What I understood req.into_body() will move the req variable taking its control and now its not usable as it is consumed by function.How can we use the req in below code? – nil96 Mar 26 '23 at 18:50

1 Answers1

3

Your initial destructuring attempt wasn't half bad, you just have to reconstruct after you got all the info out, not before:

use hyper::{Request, Body};
async fn readKey(mut req: Request<Body>) -> (String, Request<Body>) {
    let key: String;
    if !req.method().as_str().eq("GET") {
        // destructure the request so we can get the body & other parts separately
        let (parts, body) = req.into_parts();
        let body_bytes = hyper::body::to_bytes(body).await.unwrap();
        let body = std::str::from_utf8(&body_bytes).unwrap();
        key = format!(
            "{}{}{}",
            parts.uri.host().unwrap(),
            parts.uri.path(),
            body
        );
        // reconstruct the Request from parts and the data in `body_bytes`
        req = Request::from_parts(parts, body_bytes.into());
    } else {
        key = format!("{}{}", req.uri().host().unwrap(), req.uri().path());
    }

    return (key, req);
}
cafce25
  • 15,907
  • 4
  • 25
  • 31
  • thanks it worked.Can you please tell me if I have to use request 5 times I need to rebuild 5 times again. I am coming from Java,C++ background and this looks alien concept. Or there is some better pattern in rust that I need to learn? – nil96 Mar 26 '23 at 19:18
  • 2
    The core problem is that the `Body` doesn't necesarily hold all the data at once, so there's really no way to get all data without removing it, maybe instead you just want to pass `Parts` and the body as `String` around. You might also want to return `Request` after the first data extraction, then you can get it's body with `.body()` and don't have to convert to a `String` every time. – cafce25 Mar 26 '23 at 19:24