Skip to content

Commit

Permalink
Make crates.io timeout error specific to crates.io
Browse files Browse the repository at this point in the history
  • Loading branch information
sgrif committed May 14, 2019
1 parent 35cb079 commit 6af6789
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 57 deletions.
7 changes: 1 addition & 6 deletions src/cargo/ops/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,12 +129,7 @@ fn verify_dependencies(
// This extra hostname check is mostly to assist with testing,
// but also prevents someone using `--index` to specify
// something that points to crates.io.
let is_crates_io = registry
.host()
.to_url()
.map(|u| u.host_str() == Some("crates.io"))
.unwrap_or(false);
if registry_src.is_default_registry() || is_crates_io {
if registry_src.is_default_registry() || registry.host_is_crates_io() {
bail!("crates cannot be published to crates.io with dependencies sourced from other\n\
registries either publish `{}` on crates.io or pull it into this repository\n\
and specify it with a path and version\n\
Expand Down
110 changes: 59 additions & 51 deletions src/crates-io/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use http::status::StatusCode;
use serde::{Deserialize, Serialize};
use serde_json;
use url::percent_encoding::{percent_encode, QUERY_ENCODE_SET};
use url::Url;

pub type Result<T> = std::result::Result<T, failure::Error>;

Expand Down Expand Up @@ -142,6 +143,12 @@ impl Registry {
&self.host
}

pub fn host_is_crates_io(&self) -> bool {
Url::parse(self.host())
.map(|u| u.host_str() == Some("crates.io"))
.unwrap_or(false)
}

pub fn add_owners(&mut self, krate: &str, owners: &[&str]) -> Result<String> {
let body = serde_json::to_string(&OwnersReq { users: owners })?;
let body = self.put(&format!("/crates/{}/owners", krate), body.as_bytes())?;
Expand Down Expand Up @@ -208,7 +215,7 @@ impl Registry {
headers.append(&format!("Authorization: {}", token))?;
self.handle.http_headers(headers)?;

let body = handle(&mut self.handle, &mut |buf| body.read(buf).unwrap_or(0))?;
let body = self.handle(&mut |buf| body.read(buf).unwrap_or(0))?;

let response = if body.is_empty() {
"{}".parse()?
Expand Down Expand Up @@ -301,61 +308,62 @@ impl Registry {
Some(mut body) => {
self.handle.upload(true)?;
self.handle.in_filesize(body.len() as u64)?;
handle(&mut self.handle, &mut |buf| body.read(buf).unwrap_or(0))
self.handle(&mut |buf| body.read(buf).unwrap_or(0))
}
None => handle(&mut self.handle, &mut |_| 0),
None => self.handle(&mut |_| 0),
}
}
}

fn handle(handle: &mut Easy, read: &mut dyn FnMut(&mut [u8]) -> usize) -> Result<String> {
let mut headers = Vec::new();
let mut body = Vec::new();
let started;
{
let mut handle = handle.transfer();
handle.read_function(|buf| Ok(read(buf)))?;
handle.write_function(|data| {
body.extend_from_slice(data);
Ok(data.len())
})?;
handle.header_function(|data| {
headers.push(String::from_utf8_lossy(data).into_owned());
true
})?;
started = Instant::now();
handle.perform()?;
}

let body = match String::from_utf8(body) {
Ok(body) => body,
Err(..) => bail!("response body was not valid utf-8"),
};
let errors = serde_json::from_str::<ApiErrorList>(&body).ok().map(|s| {
s.errors.into_iter().map(|s| s.detail).collect::<Vec<_>>()
});

match (handle.response_code()?, errors) {
(0, None) | (200, None) => {},
(503, _) if started.elapsed().as_secs() >= 29 => {
bail!("Request took more than 30 seconds to complete. If you're\
trying to upload a crate it may be too large")
fn handle(&mut self, read: &mut dyn FnMut(&mut [u8]) -> usize) -> Result<String> {
let mut headers = Vec::new();
let mut body = Vec::new();
let started;
{
let mut handle = self.handle.transfer();
handle.read_function(|buf| Ok(read(buf)))?;
handle.write_function(|data| {
body.extend_from_slice(data);
Ok(data.len())
})?;
handle.header_function(|data| {
headers.push(String::from_utf8_lossy(data).into_owned());
true
})?;
started = Instant::now();
handle.perform()?;
}
(code, Some(errors)) => {
let code = StatusCode::from_u16(code as _)?;
bail!("api errors (status {}): {}", code, errors.join(", "))

let body = match String::from_utf8(body) {
Ok(body) => body,
Err(..) => bail!("response body was not valid utf-8"),
};
let errors = serde_json::from_str::<ApiErrorList>(&body).ok().map(|s| {
s.errors.into_iter().map(|s| s.detail).collect::<Vec<_>>()
});

match (self.handle.response_code()?, errors) {
(0, None) | (200, None) => {},
(503, _) if started.elapsed().as_secs() >= 29 && self.host_is_crates_io() => {
bail!("Request timed out after 30 seconds. If you're trying to \
upload a crate it may be too large. If the crate is under \
10MB in size, you can email [email protected] for assistance.")
}
(code, Some(errors)) => {
let code = StatusCode::from_u16(code as _)?;
bail!("api errors (status {}): {}", code, errors.join(", "))
}
(code, None) => bail!(
"failed to get a 200 OK response, got {}\n\
headers:\n\
\t{}\n\
body:\n\
{}",
code,
headers.join("\n\t"),
body,
),
}
(code, None) => bail!(
"failed to get a 200 OK response, got {}\n\
headers:\n\
\t{}\n\
body:\n\
{}",
code,
headers.join("\n\t"),
body,
),
}

Ok(body)
Ok(body)
}
}

0 comments on commit 6af6789

Please sign in to comment.