diff --git a/src/bin/render-readmes.rs b/src/bin/render-readmes.rs index ce10822f9cd..550388cb314 100644 --- a/src/bin/render-readmes.rs +++ b/src/bin/render-readmes.rs @@ -133,7 +133,14 @@ fn main() { let readme_path = format!("readmes/{0}/{0}-{1}.html", krate_name, version.num); config .uploader - .upload(&client, &readme_path, content, content_length, "text/html") + .upload( + &client, + &readme_path, + content, + content_length, + "text/html", + None, + ) .unwrap_or_else(|_| { panic!( "[{}-{}] Couldn't upload file to S3", diff --git a/src/s3/lib.rs b/src/s3/lib.rs index db58536fcec..26313537348 100644 --- a/src/s3/lib.rs +++ b/src/s3/lib.rs @@ -45,6 +45,7 @@ impl Bucket { content: R, content_length: u64, content_type: &str, + extra_headers: Option, ) -> reqwest::Result { let path = if path.starts_with('/') { &path[1..] @@ -60,6 +61,7 @@ impl Bucket { .header(header::AUTHORIZATION, auth) .header(header::CONTENT_TYPE, content_type) .header(header::DATE, date) + .headers(extra_headers.unwrap_or_else(header::HeaderMap::new)) .body(reqwest::Body::sized(content, content_length)) .send()? .error_for_status() diff --git a/src/tasks/dump_db.rs b/src/tasks/dump_db.rs index b6c36a3a966..3db37a02d83 100644 --- a/src/tasks/dump_db.rs +++ b/src/tasks/dump_db.rs @@ -157,6 +157,7 @@ impl DumpTarball { tarfile, content_length, "application/gzip", + None, ) .map_err(std_error_no_send)?; Ok(()) diff --git a/src/tests/record.rs b/src/tests/record.rs index 4b8ffa96f34..79160d180cf 100644 --- a/src/tests/record.rs +++ b/src/tests/record.rs @@ -272,7 +272,7 @@ fn replay_http( mut exchange: Exchange, stdout: &mut dyn Write, ) -> Box, Error = hyper::Error> + Send> { - static IGNORED_HEADERS: &[&str] = &["authorization", "date", "user-agent"]; + static IGNORED_HEADERS: &[&str] = &["authorization", "date", "user-agent", "cache-control"]; assert_eq!(req.uri().to_string(), exchange.request.uri); assert_eq!(req.method().to_string(), exchange.request.method); diff --git a/src/uploaders.rs b/src/uploaders.rs index 8a1fc1a737f..c78b6a0842c 100644 --- a/src/uploaders.rs +++ b/src/uploaders.rs @@ -1,6 +1,7 @@ use conduit::Request; use flate2::read::GzDecoder; use openssl::hash::{Hasher, MessageDigest}; +use reqwest::header; use crate::util::LimitErrorReader; use crate::util::{human, internal, CargoResult, ChainError, Maximums}; @@ -13,6 +14,8 @@ use std::sync::Arc; use crate::middleware::app::RequestApp; use crate::models::Crate; +pub const CACHE_CONTROL_IMMUTABLE: &str = "public,max-age=31536000,immutable"; + #[derive(Clone, Debug)] pub enum Uploader { /// For production usage, uploads and redirects to s3. @@ -70,13 +73,13 @@ impl Uploader { } } - /// Returns the interna path of an uploaded crate's version archive. + /// Returns the internal path of an uploaded crate's version archive. fn crate_path(name: &str, version: &str) -> String { // No slash in front so we can use join format!("crates/{}/{}-{}.crate", name, name, version) } - /// Returns the interna path of an uploaded crate's version readme. + /// Returns the internal path of an uploaded crate's version readme. fn readme_path(name: &str, version: &str) -> String { format!("readmes/{}/{}-{}.html", name, name, version) } @@ -91,11 +94,19 @@ impl Uploader { mut content: R, content_length: u64, content_type: &str, + extra_headers: Option, ) -> CargoResult> { match *self { Uploader::S3 { ref bucket, .. } => { bucket - .put(client, path, content, content_length, content_type) + .put( + client, + path, + content, + content_length, + content_type, + extra_headers, + ) .map_err(|e| internal(&format_args!("failed to upload to S3: {}", e)))?; Ok(Some(String::from(path))) } @@ -126,12 +137,18 @@ impl Uploader { let checksum = hash(&body); let content_length = body.len() as u64; let content = Cursor::new(body); + let mut extra_headers = header::HeaderMap::new(); + extra_headers.insert( + header::CACHE_CONTROL, + CACHE_CONTROL_IMMUTABLE.parse().unwrap(), + ); self.upload( app.http_client(), &path, content, content_length, "application/x-tar", + Some(extra_headers), )?; Ok(checksum) } @@ -146,7 +163,14 @@ impl Uploader { let path = Uploader::readme_path(crate_name, vers); let content_length = readme.len() as u64; let content = Cursor::new(readme); - self.upload(http_client, &path, content, content_length, "text/html")?; + self.upload( + http_client, + &path, + content, + content_length, + "text/html", + None, + )?; Ok(()) } }