Skip to content

Remove restriction that a crate must be in the database to get a download URL #405

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

Merged
Merged
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
3 changes: 3 additions & 0 deletions .env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
# `postgres://postgres:@localhost/cargo_registry`.
export DATABASE_URL=""

# If you are running a mirror of crates.io, uncomment this line.
# export MIRROR=1

# Key to sign and encrypt cookies with. Change this to a long, random string
# for production.
export SESSION_KEY="badkey"
Expand Down
1 change: 1 addition & 0 deletions src/bin/fill-in-user-id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ fn main() {
db_url: env("DATABASE_URL"),
env: cargo_registry::Env::Production,
max_upload_size: 0,
mirror: false,
};
let app = cargo_registry::App::new(&config);
{
Expand Down
1 change: 1 addition & 0 deletions src/bin/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ fn main() {
db_url: env("DATABASE_URL"),
env: cargo_env,
max_upload_size: 10 * 1024 * 1024,
mirror: env::var("MIRROR").is_ok(),
};
let app = cargo_registry::App::new(&config);
let app = cargo_registry::middleware(Arc::new(app));
Expand Down
1 change: 1 addition & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub struct Config {
pub db_url: String,
pub env: ::Env,
pub max_upload_size: u64,
pub mirror: bool,
}

impl Config {
Expand Down
41 changes: 27 additions & 14 deletions src/krate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -827,6 +827,31 @@ fn read_fill<R: Read + ?Sized>(r: &mut R, mut slice: &mut [u8])
pub fn download(req: &mut Request) -> CargoResult<Response> {
let crate_name = &req.params()["crate_id"];
let version = &req.params()["version"];

// If we are a mirror, ignore failure to update download counts.
// API-only mirrors won't have any crates in their database, and
// incrementing the download count will look up the crate in the
// database. Mirrors just want to pass along a redirect URL.
if req.app().config.mirror {
let _ = increment_download_counts(req, crate_name, version);
} else {
try!(increment_download_counts(req, crate_name, version));
}

let redirect_url = format!("https://{}/crates/{}/{}-{}.crate",
req.app().bucket.host(),
crate_name, crate_name, version);

if req.wants_json() {
#[derive(RustcEncodable)]
struct R { url: String }
Ok(req.json(&R{ url: redirect_url }))
} else {
Ok(req.redirect(redirect_url))
}
}

fn increment_download_counts(req: &Request, crate_name: &str, version: &str) -> CargoResult<()> {
let tx = try!(req.tx());
let stmt = try!(tx.prepare("SELECT versions.id as version_id
FROM crates
Expand All @@ -836,7 +861,7 @@ pub fn download(req: &mut Request) -> CargoResult<Response> {
canon_crate_name($1)
AND versions.num = $2
LIMIT 1"));
let rows = try!(stmt.query(&[crate_name, version]));
let rows = try!(stmt.query(&[&crate_name, &version]));
let row = try!(rows.iter().next().chain_error(|| {
human("crate or version not found")
}));
Expand All @@ -862,19 +887,7 @@ pub fn download(req: &mut Request) -> CargoResult<Response> {
try!(tx.execute("INSERT INTO version_downloads
(version_id) VALUES ($1)", &[&version_id]));
}

// Now that we've done our business, redirect to the actual data.
let redirect_url = format!("https://{}/crates/{}/{}-{}.crate",
req.app().bucket.host(),
crate_name, crate_name, version);

if req.wants_json() {
#[derive(RustcEncodable)]
struct R { url: String }
Ok(req.json(&R{ url: redirect_url }))
} else {
Ok(req.redirect(redirect_url))
}
Ok(())
}

/// Handles the `GET /crates/:crate_id/downloads` route.
Expand Down
1 change: 1 addition & 0 deletions src/tests/all.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ fn app() -> (record::Bomb, Arc<App>, conduit_middleware::MiddlewareBuilder) {
db_url: env("TEST_DATABASE_URL"),
env: cargo_registry::Env::Test,
max_upload_size: 1000,
mirror: false,
};
INIT.call_once(|| db_setup(&config.db_url));
let app = App::new(&config);
Expand Down