diff --git a/src/bin/render-readmes.rs b/src/bin/render-readmes.rs index c7a6fb46174..ce10822f9cd 100644 --- a/src/bin/render-readmes.rs +++ b/src/bin/render-readmes.rs @@ -128,10 +128,12 @@ fn main() { return; } let readme = readme.unwrap(); + let content_length = readme.len() as u64; + let content = std::io::Cursor::new(readme); let readme_path = format!("readmes/{0}/{0}-{1}.html", krate_name, version.num); config .uploader - .upload(&client, &readme_path, readme.into_bytes(), "text/html") + .upload(&client, &readme_path, content, content_length, "text/html") .unwrap_or_else(|_| { panic!( "[{}-{}] Couldn't upload file to S3", diff --git a/src/s3/lib.rs b/src/s3/lib.rs index 4992d0266e8..db58536fcec 100644 --- a/src/s3/lib.rs +++ b/src/s3/lib.rs @@ -38,11 +38,12 @@ impl Bucket { } } - pub fn put( + pub fn put( &self, client: &reqwest::Client, path: &str, - content: Vec, + content: R, + content_length: u64, content_type: &str, ) -> reqwest::Result { let path = if path.starts_with('/') { @@ -59,7 +60,7 @@ impl Bucket { .header(header::AUTHORIZATION, auth) .header(header::CONTENT_TYPE, content_type) .header(header::DATE, date) - .body(content) + .body(reqwest::Body::sized(content, content_length)) .send()? .error_for_status() } diff --git a/src/uploaders.rs b/src/uploaders.rs index c27423bafbe..8a1fc1a737f 100644 --- a/src/uploaders.rs +++ b/src/uploaders.rs @@ -7,7 +7,7 @@ use crate::util::{human, internal, CargoResult, ChainError, Maximums}; use std::env; use std::fs::{self, File}; -use std::io::{Read, Write}; +use std::io::{Cursor, Read}; use std::sync::Arc; use crate::middleware::app::RequestApp; @@ -83,30 +83,29 @@ impl Uploader { /// Uploads a file using the configured uploader (either `S3`, `Local`). /// - /// It returns a a tuple containing the path of the uploaded file - /// and its checksum. - pub fn upload( + /// It returns the path of the uploaded file. + pub fn upload( &self, client: &reqwest::Client, path: &str, - body: Vec, + mut content: R, + content_length: u64, content_type: &str, - ) -> CargoResult<(Option, Vec)> { - let hash = hash(&body); + ) -> CargoResult> { match *self { Uploader::S3 { ref bucket, .. } => { bucket - .put(client, path, body, content_type) + .put(client, path, content, content_length, content_type) .map_err(|e| internal(&format_args!("failed to upload to S3: {}", e)))?; - Ok((Some(String::from(path)), hash)) + Ok(Some(String::from(path))) } Uploader::Local => { let filename = env::current_dir().unwrap().join("local_uploads").join(path); let dir = filename.parent().unwrap(); fs::create_dir_all(dir)?; let mut file = File::create(&filename)?; - file.write_all(&body)?; - Ok((filename.to_str().map(String::from), hash)) + std::io::copy(&mut content, &mut file)?; + Ok(filename.to_str().map(String::from)) } } } @@ -120,13 +119,20 @@ impl Uploader { vers: &semver::Version, ) -> CargoResult> { let app = Arc::clone(req.app()); - let (_, checksum) = { - let path = Uploader::crate_path(&krate.name, &vers.to_string()); - let mut body = Vec::new(); - LimitErrorReader::new(req.body(), maximums.max_upload_size).read_to_end(&mut body)?; - verify_tarball(krate, vers, &body, maximums.max_unpack_size)?; - self.upload(app.http_client(), &path, body, "application/x-tar")? - }; + let path = Uploader::crate_path(&krate.name, &vers.to_string()); + let mut body = Vec::new(); + LimitErrorReader::new(req.body(), maximums.max_upload_size).read_to_end(&mut body)?; + verify_tarball(krate, vers, &body, maximums.max_unpack_size)?; + let checksum = hash(&body); + let content_length = body.len() as u64; + let content = Cursor::new(body); + self.upload( + app.http_client(), + &path, + content, + content_length, + "application/x-tar", + )?; Ok(checksum) } @@ -138,7 +144,9 @@ impl Uploader { readme: String, ) -> CargoResult<()> { let path = Uploader::readme_path(crate_name, vers); - self.upload(http_client, &path, readme.into_bytes(), "text/html")?; + let content_length = readme.len() as u64; + let content = Cursor::new(readme); + self.upload(http_client, &path, content, content_length, "text/html")?; Ok(()) } }