Skip to content

Instantly share code, notes, and snippets.

@simmons
Last active June 28, 2023 14:52
Show Gist options
  • Save simmons/6c2e6eb3ade5bfcb962250603dd667cf to your computer and use it in GitHub Desktop.
Save simmons/6c2e6eb3ade5bfcb962250603dd667cf to your computer and use it in GitHub Desktop.
extern crate multipart;
extern crate reqwest;
use multipart::client::lazy::Multipart;
use reqwest::mime;
use std::process;
use std::io::Read;
const URL: &'static str = "http://example.com/fileupload";
const UPLOAD_FORM_FIELD_NAME: &'static str = "thefile";
const FILENAME: &'static str = "sample.txt";
/// This is example code for using the multipart crate with reqwest to
/// upload a file. The multipart crate is used to encode the file, and
/// the necessary headers/body are manually added to the reqwest
/// request.
///
/// NOTE: Built-in multipart support in reqwest is pending, and this
/// example will be obsolete when that is available.
///
/// NOTE: For simplicity, this example stores the entire encoded file in
/// memory. For anything but very small files, you'd want a streaming
/// approach instead.
fn main() {
// Construct a multipart description
let mut multipart = Multipart::new();
multipart.add_file(UPLOAD_FORM_FIELD_NAME, FILENAME);
let mut multipart_prepared = multipart.prepare().unwrap();
let mut multipart_buffer: Vec<u8> = vec![];
multipart_prepared
.read_to_end(&mut multipart_buffer)
.unwrap();
// Compose a request
let client = reqwest::Client::new().unwrap();
let requestbuilder = client
.post(&String::from(URL))
.header(reqwest::header::ContentType(mime::Mime(
mime::TopLevel::Multipart,
mime::SubLevel::FormData,
vec![
(
mime::Attr::Ext(String::from("boundary")),
mime::Value::Ext(
String::from(multipart_prepared.boundary()),
)
),
],
)))
.body(multipart_buffer);
// Send request
let mut response = match requestbuilder.send() {
Ok(r) => r,
Err(e) => {
println!("error: {:?}", e);
process::exit(0);
}
};
// Report
println!("status: {}", response.status());
let mut response_data: Vec<u8> = vec![];
response.read_to_end(&mut response_data).unwrap();
println!(
"response:\n{}",
std::str::from_utf8(&response_data).unwrap()
);
}
@sakex
Copy link

sakex commented Aug 19, 2020

Hello, do you have an example with async support? Thank you very much for the good work

@simmons
Copy link
Author

simmons commented Aug 19, 2020

Hi,
Sorry, I don't have an async upload example. And even this sync code is really old. The technique it outlines may not be needed any more.

@phunguyen19
Copy link

phunguyen19 commented Jun 28, 2023

Just posting here in case someone needs an async solution (like me). The code is inspired by this conversation

// reqwest = { version = "0.11", features = ["multipart"] }
use reqwest::multipart::Part;

async fn upload_file() -> Result<(), Box<dyn std::error::Error>> {
    let content: Vec<u8> = tokio::fs::read("path/to/file").await?;

    let part = Part::bytes(content).file_name("file_name.extension");
    let file = reqwest::multipart::Form::new().part("field_name", part);

    let response = reqwest::Client::new()
        .post("api/endpoint")
        .multipart(file)
        .send()
        .await?;

    println!("Status: {}", response.status());
    println!("Headers:\n{:#?}", response.headers());
    println!("Body:\n{}", response.text().await?);

    Ok(())
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment