seanmonstar / reqwest

An easy and powerful Rust HTTP Client
https://docs.rs/reqwest
Apache License 2.0
9.77k stars 1.1k forks source link

multipart form file upload sometimes fails #252

Open martinlindhe opened 6 years ago

martinlindhe commented 6 years ago

Hello

I tried using reqwest to upload a file to a small golang webserver I am running inside a VM, this mostly works but every 50-200 or so request fails.

The error I eventually see in the client is thread panicked at 'calledResult::unwrap()on anErrvalue: Error { kind: Io(Custom { kind: WouldBlock, error: StringError("timed out") }), url: Some("http://10.10.30.63:28111/run") }', libcore/result.rs:945:5

and in the server: multipart: NextPart: unexpected EOF

This is what i do with reqwest

fn stdout_from_vm_http(prober_com: &str) -> String {
    let client = reqwest::Client::new();

    let form = reqwest::multipart::Form::new()
        .file("com", prober_com).unwrap();

    let mut res = client.post("http://10.10.30.63:28111/run")
        .multipart(form)
        .send().unwrap();

    res.text().unwrap()
}

Where http://10.10.30.63:28111/run is provided by https://github.com/martinlindhe/supersafe

In order to verify that the issue is unrelated to the server code, I re-ran using curl, with no issues:

#!/bin/bash
for i in {0..65535}
do
   echo "iteration $i"
   curl -F "com=@/Users/m/dev/rs/dustbox-rs/utils/prober/prober.com" http://10.10.30.63:28111/run
done
martinlindhe commented 6 years ago

I worked around this in my project by instead using curl-rust, using the following code

fn stdout_from_vm_http(prober_com: &str) -> String {
    use curl::easy::{Easy, Form};

    let mut dst = Vec::new();
    let mut easy = Easy::new();
    easy.url("http://10.10.30.63:28111/run").unwrap();

    let mut form = Form::new();
    form.part("com").file(prober_com).add();
    easy.httppost(form).unwrap();

    {
        let mut transfer = easy.transfer();
        transfer.write_function(|data| {
            dst.extend_from_slice(data);
            Ok(data.len())
        }).unwrap();
        transfer.perform().unwrap();
    }

    str::from_utf8(&dst).unwrap().to_owned()
}
martinlindhe commented 6 years ago

I would like to assist in analysing this issue more, but I am a bit clueless of where to begin.

As posted above, I have a "mostly" reproducible scenario for this issue.

I'm off to elsewhere, but please ping me if I can be of any help

seanmonstar commented 6 years ago

I have noticed before the multipart tests time out, I just assumed it was flakiness in Travis CI. To try to start debugging this, I'd look into the multipart file in this repo, and maybe add some trace! lines.