Skip to content

Rollup of #1498 and #1499 #1500

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 10 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
652 changes: 475 additions & 177 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ url = "1.2.1"
tar = "0.4.13"

openssl = "0.9.14"
curl = "0.4"
oauth2 = "0.3"
log = "0.3"
env_logger = "0.5"
Expand All @@ -58,6 +57,7 @@ docopt = "0.8.1"
itertools = "0.6.0"
scheduled-thread-pool = "0.2.0"
derive_deref = "1.0.0"
reqwest = "0.9.1"

lettre = "0.8"
lettre_email = "0.8"
Expand Down
13 changes: 7 additions & 6 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@ use std::path::PathBuf;
use std::sync::{Arc, Mutex};
use std::time::Duration;

use curl::easy::Easy;
use diesel::r2d2;
use git2;
use oauth2;
use reqwest;
use scheduled_thread_pool::ScheduledThreadPool;

use util::CargoResult;
use {db, Config, Env};

/// The `App` struct holds the main components of the application like
Expand Down Expand Up @@ -99,16 +100,16 @@ impl App {
}
}

/// Returns a handle for making HTTP requests to upload crate files.
/// Returns a client for making HTTP requests to upload crate files.
///
/// The handle will go through a proxy if the uploader being used has specified one, which
/// is only done in test mode in order to be able to record and inspect the HTTP requests
/// that tests make.
pub fn handle(&self) -> Easy {
let mut handle = Easy::new();
pub fn http_client(&self) -> CargoResult<reqwest::Client> {
let mut builder = reqwest::Client::builder();
if let Some(proxy) = self.config.uploader.proxy() {
handle.proxy(proxy).unwrap();
builder = builder.proxy(reqwest::Proxy::all(proxy)?);
}
handle
Ok(builder.build()?)
}
}
60 changes: 17 additions & 43 deletions src/bin/render-readmes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,24 @@ extern crate serde_derive;

extern crate cargo_registry;
extern crate chrono;
extern crate curl;
extern crate diesel;
extern crate docopt;
extern crate flate2;
extern crate itertools;
extern crate reqwest;
extern crate tar;
extern crate toml;
extern crate url;

use chrono::{TimeZone, Utc};
use curl::easy::{Easy, List};
use diesel::dsl::any;
use diesel::prelude::*;
use docopt::Docopt;
use flate2::read::GzDecoder;
use itertools::Itertools;
use std::io::{Cursor, Read};
use std::io::Read;
use std::path::Path;
use std::thread;
use tar::Archive;
use url::Url;

use cargo_registry::render::readme_to_html;
use cargo_registry::Config;
Expand Down Expand Up @@ -146,15 +143,13 @@ fn main() {
}
let readme = readme.unwrap();
let readme_path = format!("readmes/{0}/{0}-{1}.html", krate_name, version.num);
let readme_len = readme.len();
config
.uploader
.upload(
Easy::new(),
&reqwest::Client::new(),
&readme_path,
readme.as_bytes(),
readme.into_bytes(),
"text/html",
readme_len as u64,
).unwrap_or_else(|_| {
panic!(
"[{}-{}] Couldn't upload file to S3",
Expand All @@ -174,53 +169,32 @@ fn main() {

/// Renders the readme of an uploaded crate version.
fn get_readme(config: &Config, version: &Version, krate_name: &str) -> Option<String> {
let mut handle = Easy::new();
let location = match config
let location = config
.uploader
.crate_location(krate_name, &version.num.to_string())
{
Some(l) => l,
None => return None,
};
let date = Utc::now().to_rfc2822();
let url = Url::parse(&location)
.unwrap_or_else(|_| panic!("[{}-{}] Couldn't parse crate URL", krate_name, version.num));

let mut headers = List::new();
headers
.append(&format!("Host: {}", url.host().unwrap()))
.unwrap();
headers.append(&format!("Date: {}", date)).unwrap();
.crate_location(krate_name, &version.num.to_string())?;

handle.url(url.as_str()).unwrap();
handle.get(true).unwrap();
handle.http_headers(headers).unwrap();

let mut response = Vec::new();
{
let mut req = handle.transfer();
req.write_function(|data| {
response.extend(data);
Ok(data.len())
}).unwrap();
if let Err(err) = req.perform() {
let mut response = match reqwest::get(&location) {
Ok(r) => r,
Err(err) => {
println!(
"[{}-{}] Unable to fetch crate: {}",
krate_name, version.num, err
);
return None;
}
}
if handle.response_code().unwrap() != 200 {
let response = String::from_utf8_lossy(&response);
};

if !response.status().is_success() {
println!(
"[{}-{}] Failed to get a 200 response: {}",
krate_name, version.num, response
krate_name,
version.num,
response.text().unwrap()
);
return None;
}
let reader = Cursor::new(response);
let reader = GzDecoder::new(reader);

let reader = GzDecoder::new(response);
let mut archive = Archive::new(reader);
let mut entries = archive.entries().unwrap_or_else(|_| {
panic!(
Expand Down
38 changes: 38 additions & 0 deletions src/bin/test-pagerduty.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//! Send a test event to pagerduty
//!
//! Usage:
//! cargo run --bin test-pagerduty event_type [description]
//!
//! Event type can be trigger, acknowledge, or resolve

#![deny(warnings)]

extern crate cargo_registry;

use std::env::args;

use cargo_registry::on_call;

fn main() {
let args = args().collect::<Vec<_>>();

let event_type = &*args[1];
let description = args.get(2).cloned();

let event = match event_type {
"trigger" => on_call::Event::Trigger {
incident_key: Some("test".into()),
description: description.unwrap_or_else(|| "Test event".into()),
},
"acknowledge" => on_call::Event::Acknowledge {
incident_key: "test".into(),
description,
},
"resolve" => on_call::Event::Resolve {
incident_key: "test".into(),
description,
},
_ => panic!("Event type must be trigger, acknowledge, or resolve"),
};
event.send().unwrap()
}
8 changes: 4 additions & 4 deletions src/controllers/krate/publish.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,10 +166,10 @@ pub fn publish(req: &mut dyn Request) -> CargoResult<Response> {
// Upload the crate, return way to delete the crate from the server
// If the git commands fail below, we shouldn't keep the crate on the
// server.
let (cksum, mut crate_bomb, mut readme_bomb) =
app.config
.uploader
.upload_crate(req, &krate, readme, file_length, maximums, vers)?;
let (cksum, mut crate_bomb, mut readme_bomb) = app
.config
.uploader
.upload_crate(req, &krate, readme, maximums, vers)?;
version.record_readme_rendering(&conn)?;

let mut hex_cksum = String::new();
Expand Down
3 changes: 1 addition & 2 deletions src/controllers/user/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,7 @@ pub fn github_access_token(req: &mut dyn Request) -> CargoResult<Response> {
.exchange(code.clone())
.map_err(|s| human(&s))?;

let (handle, resp) = github::github(req.app(), "/user", &token)?;
let ghuser: GithubUser = github::parse_github_response(handle, &resp)?;
let ghuser = github::github::<GithubUser>(req.app(), "/user", &token)?;

let user = NewUser::new(
ghuser.id,
Expand Down
104 changes: 37 additions & 67 deletions src/github.rs
Original file line number Diff line number Diff line change
@@ -1,88 +1,58 @@
//! This module implements functionality for interacting with GitHub.

use curl;
use curl::easy::{Easy, List};

use oauth2::*;
use reqwest::{self, header};

use serde::Deserialize;
use serde_json;
use serde::de::DeserializeOwned;

use std::str;

use app::App;
use util::{human, internal, CargoResult, ChainError};
use util::{errors::NotFound, human, internal, CargoError, CargoResult};

/// Does all the nonsense for sending a GET to Github. Doesn't handle parsing
/// because custom error-code handling may be desirable. Use
/// `parse_github_response` to handle the "common" processing of responses.
pub fn github(app: &App, url: &str, auth: &Token) -> Result<(Easy, Vec<u8>), curl::Error> {
pub fn github<T>(app: &App, url: &str, auth: &Token) -> CargoResult<T>
where
T: DeserializeOwned,
{
let url = format!("{}://api.github.com{}", app.config.api_protocol, url);
info!("GITHUB HTTP: {}", url);

let mut headers = List::new();
headers
.append("Accept: application/vnd.github.v3+json")
.unwrap();
headers.append("User-Agent: hello!").unwrap();
headers
.append(&format!("Authorization: token {}", auth.access_token))
.unwrap();

let mut handle = app.handle();
handle.url(&url).unwrap();
handle.get(true).unwrap();
handle.http_headers(headers).unwrap();

let mut data = Vec::new();
{
let mut transfer = handle.transfer();
transfer
.write_function(|buf| {
data.extend_from_slice(buf);
Ok(buf.len())
}).unwrap();
transfer.perform()?;
}
Ok((handle, data))
let client = app.http_client()?;
client
.get(&url)
.header(header::ACCEPT, "application/vnd.github.v3+json")
.header(
header::AUTHORIZATION,
format!("token {}", auth.access_token),
).send()?
.error_for_status()
.map_err(|e| handle_error_response(&e))?
.json()
.map_err(Into::into)
}

/// Checks for normal responses
pub fn parse_github_response<'de, 'a: 'de, T: Deserialize<'de>>(
mut resp: Easy,
data: &'a [u8],
) -> CargoResult<T> {
match resp.response_code().unwrap() {
// Ok!
200 => {}
// Unauthorized or Forbidden
401 | 403 => {
return Err(human(
"It looks like you don't have permission \
to query a necessary property from Github \
to complete this request. \
You may need to re-authenticate on \
crates.io to grant permission to read \
github org memberships. Just go to \
https://crates.io/login",
));
}
// Something else
n => {
let resp = String::from_utf8_lossy(data);
return Err(internal(&format_args!(
"didn't get a 200 result from \
github, got {} with: {}",
n, resp
)));
}
}

let json = str::from_utf8(data)
.ok()
.chain_error(|| internal("github didn't send a utf8-response"))?;
fn handle_error_response(error: &reqwest::Error) -> Box<dyn CargoError> {
use reqwest::StatusCode as Status;

serde_json::from_str(json).chain_error(|| internal("github didn't send a valid json response"))
match error.status() {
Some(Status::UNAUTHORIZED) | Some(Status::FORBIDDEN) => human(
"It looks like you don't have permission \
to query a necessary property from Github \
to complete this request. \
You may need to re-authenticate on \
crates.io to grant permission to read \
github org memberships. Just go to \
https://crates.io/login",
),
Some(Status::NOT_FOUND) => Box::new(NotFound),
_ => internal(&format_args!(
"didn't get a 200 result from github: {}",
error
)),
}
}

/// Gets a token with the given string as the access token, but all
Expand Down
3 changes: 2 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
extern crate ammonia;
extern crate chrono;
extern crate comrak;
extern crate curl;
#[macro_use]
extern crate derive_deref;
#[macro_use]
Expand All @@ -32,6 +31,7 @@ extern crate log;
extern crate oauth2;
extern crate openssl;
extern crate rand;
extern crate reqwest;
extern crate s3;
extern crate scheduled_thread_pool;
extern crate semver;
Expand Down Expand Up @@ -69,6 +69,7 @@ pub mod email;
pub mod git;
pub mod github;
pub mod middleware;
pub mod on_call;
pub mod render;
pub mod schema;
pub mod uploaders;
Expand Down
Loading