1

What I want to do is really what the title says. I would like to know how I can receive data per post in hyper, for example, suppose I execute the following command (with a server in hyper running on port :8000):

curl -X POST -F "field=@/path/to/file.txt" -F "tool=curl" -F "other-file=@/path/to/other.jpg" http://localhost:8000

Now, I'm going to take parf of the code on the main page of hyper as an example:

use std::{convert::Infallible, net::SocketAddr};
use hyper::{Body, Request, Response, Server};
use hyper::service::{make_service_fn, service_fn};

async fn handle(_: Request<Body>) -> Result<Response<Body>, Infallible> {
    Ok(Response::new("Hello, World!".into()))
}

#[tokio::main]
async fn main() {
    let addr = SocketAddr::from(([127, 0, 0, 1], 8000));

    let make_svc = make_service_fn(|_conn| async {
        Ok::<_, Infallible>(service_fn(handle))
    });

    let server = Server::bind(&addr).serve(make_svc);

    if let Err(e) = server.await {
        eprintln!("server error: {}", e);
    }
}

So, now, with this basic code, how can I receive the data per post that my curl command above would send? How do I adapt my code to read the data? I've tried to search the internet, but what I found was that hyper doesn't actually split the request body depending on the HTTP method, it's all part of the same body. But I haven't been able to find a way to process data like the above with code like mine. Thanks in advance.

Edit

I tried the exact code that they left me in the answer. That is, this code:

async fn handle(req: Request<Body>) -> Result<Response<Body>, Infallible> {
    let mut files = multipart::server::Multipart::from(req);
     .....
}

But I get this error:

expected struct multipart::server::Multipart, found struct hyper::Request

How can I solve that?

Agni21
  • 111
  • 3
DFG
  • 31
  • 1
  • 13
  • 1
    Hyper is relatively low-lowel lib [as they said in README](https://github.com/hyperium/hyper#low-level), I think you should try [axum](https://crates.io/crates/axum) or [warp](https://crates.io/crates/warp) for this. – vaan Nov 03 '22 at 06:37

1 Answers1

1

It is a single body, but the data is encoded in a way that contains the multiple files. This is called multipart, and in order to parse the body correctly you need a multipart library such as https://crates.io/crates/multipart

To hyper integration you need to add the feature flag hyper in Cargo.toml

multipart = { version = "*", features = ["hyper"] }

Then

async fn handle(mut files: multipart::server::Multipart) -> Result<Response<Body>, Infallible> {
    files.foreach_entry(|field| {
        // contains name, filename, type ..
        println!("Info: {:?}",field.headers);
        // contains data
        let mut bytes:Vec<u8> = Vec::new();
        field.data.read_to_end(&mut bytes);
    });
    Ok(Response::new("Received the files!".into()))
}

You can also use it like this

async fn handle(req: Request<Body>) -> Result<Response<Body>, Infallible> {
    let mut files = multipart::server::Multipart::from(req);
     .....
}
Oussama Gammoudi
  • 685
  • 7
  • 13
  • Is there a way to do that without overriding the first `handle` function? And how do I receive the data that is in text sent by POST? – DFG Nov 03 '22 at 15:02
  • @New1 added a different usage example using Multipart::from_request – Oussama Gammoudi Nov 03 '22 at 15:37
  • Could you give an example of how it would be with `Multipart::from_request`? I've seen it myself and I have errors, so I'd like to see how it's done correctly. – DFG Nov 03 '22 at 16:40
  • I already updated my question with an error that I have when I use your code. – DFG Nov 05 '22 at 03:48