Skip to content

Instantly share code, notes, and snippets.

Created May 8, 2017 20:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save anonymous/82742b0ebd011a5a2a60ff2b9c14f600 to your computer and use it in GitHub Desktop.
Save anonymous/82742b0ebd011a5a2a60ff2b9c14f600 to your computer and use it in GitHub Desktop.
Shared via Rust Playground
#[macro_use]
extern crate hyper;
extern crate reqwest;
use reqwest;
use std::io::Read;
header! { (ContentType, "Content-Type") => [String] }
header! { (ContentLength, "Content-Length") => [usize] }
pub trait MultipartFile {
fn name(&self) -> String;
fn as_bytes(&self) -> Vec<u8>;
fn len(&self) -> usize;
}
struct MyUpload {
pub name: String,
pub data: Vec<u8>,
}
impl MultipartFile for MyUpload {
fn name(&self) -> String {
self.name.clone()
}
fn as_bytes(&self) -> Vec<u8> {
self.data.clone()
}
fn len(&self) -> usize {
self.data.len()
}
}
fn main() {
let s = MyUpload {
data: Vec::new(),
name: "my_upload.txt".to_string(),
};
let uploads = vec![s];
let client = ::reqwest::Client::new().unwrap();
let (multipart_body, content_length) = multipart_for_binary(uploads.as_ref());
let request = client.request(reqwest::Method::Post, "https://domain.local/my_endpoint")
.body(multipart_body)
.header(ContentType(format!("multipart/form-data; boundary=MULTIPARTBINARY")))
.header(ContentLength(content_length));
let mut result = match request.send() {
Ok(result) => result,
Err(err) => {
println!("error: {}", err);
return;
}
};
println!("response received");
match result.status() {
&::reqwest::StatusCode::Ok => println!("OK"),
&::reqwest::StatusCode::Created => println!("Created"),
&::reqwest::StatusCode::Unauthorized => println!("Unauthorized"),
&::reqwest::StatusCode::BadRequest => println!("Bad request"),
_ => {
let mut response = String::new();
match result.read_to_string(&mut response) {
Ok(_) => {
println!("unexpected response (code HTTP{}): {}", result.status(), &response)
},
Err(err) => {
println!("unexpected response (code HTTP{}), unable to read response: {}", result.status(), err)
}
};
},
}
}
fn multipart_for_binary<T>(items: &[T]) -> (Vec<u8>, usize) where T: MultipartFile {
let mut body = Vec::new();
let rn = b"\r\n";
let body_boundary = br"--MULTIPARTBINARY";
let end_boundary = br"--MULTIPARTBINARY--";
let enc = br"Content-Transfer-Encoding: binary";
let field_name = match items.len() {
1 => "file",
_ => "files",
};
body.extend(rn);
body.extend(rn);
for item in items {
let name = item.name();
let data = item.as_bytes();
let disp = format!("Content-Disposition: form-data; name=\"{}\"; filename=\"{}\"", field_name, name);
let content_type = br"Content-Type: application/octet-stream";
body.extend(body_boundary.as_ref());
body.extend(rn);
body.extend(disp.as_bytes());
body.extend(rn);
body.extend(content_type.as_ref());
body.extend(rn);
body.extend(enc.as_ref());
body.extend(rn);
body.extend(rn);
body.extend(data.as_slice());
body.extend(rn);
}
body.extend(end_boundary.as_ref());
body.extend(rn);
body.extend(rn);
let content_length = body.len();
(body, content_length)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment