Skip to content

Commit

Permalink
Implement download handler using redirection
Browse files Browse the repository at this point in the history
With this patch we change the way with which we implement the
/api/v1/crates/../../download handler. Specifically, instead of
"manually" implementing the .crate file lookup, open the file, and send
it back, we use a redirection to a new endpoint that serves the contents
of the root directory where all .crate files are stored. This way we
we make better use of warp's functionality that we already use
elsewhere.
  • Loading branch information
d-e-s-o committed Feb 11, 2021
1 parent 9dc0df6 commit b502570
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 44 deletions.
32 changes: 0 additions & 32 deletions src/download.rs

This file was deleted.

30 changes: 20 additions & 10 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
//!
//! [here]: https://doc.rust-lang.org/cargo/reference/registries.html

mod download;
mod index;
mod publish;

Expand Down Expand Up @@ -37,8 +36,8 @@ use tracing_subscriber::filter::LevelFilter;
use tracing_subscriber::fmt::time::ChronoLocal;
use tracing_subscriber::FmtSubscriber;

use warp::http::Response;
use warp::http::StatusCode;
use warp::http::Uri;
use warp::Filter as _;
use warp::Reply as _;

Expand Down Expand Up @@ -113,13 +112,18 @@ fn run() -> Result<()> {
// index we have a circular dependency that we can only resolve by use
// of an `Option`. *sadpanda*
let shared = Arc::new(Mutex::new(Option::<index::Index>::None));
let copy1 = shared.clone();
let copy2 = shared.clone();
let copy = shared.clone();

// Serve the contents of <root>/.git at /git.
let index = warp::path("git")
.and(warp::fs::dir(args.root.join(".git")))
.with(warp::trace::request());
// Serve the contents of <root>/ at /crates. This allows for directly
// downloading the .crate files, to which we redirect from the
// download handler below.
let crates = warp::path("crates")
.and(warp::fs::dir(args.root.clone()))
.with(warp::trace::request());
let download = warp::get()
.and(warp::path("api"))
.and(warp::path("v1"))
Expand All @@ -128,11 +132,13 @@ fn run() -> Result<()> {
.and(warp::path::param())
.and(warp::path("download"))
.map(move |name: String, version: String| {
let index = copy1.lock().unwrap();
let index = index.as_ref().unwrap();
download::download_crate(&name, &version, &index).map(Response::new)
let path = format!("/crates/{}", publish::crate_file_name(&name, &version));
// TODO: Ideally we shouldn't unwrap here. That's not that easily
// possible, though, because then we'd need to handle errors
// and we can't use the response function because it will
// overwrite the HTTP status even on success.
path.parse::<Uri>().map(warp::redirect).unwrap()
})
.and_then(response)
.with(warp::trace::request());
let publish = warp::put()
.and(warp::path("api"))
Expand All @@ -145,7 +151,7 @@ fn run() -> Result<()> {
// believe that's what crates.io does as well.
.and(warp::body::content_length_limit(2 * 1024 * 1024))
.map(move |body| {
let mut index = copy2.lock().unwrap();
let mut index = copy.lock().unwrap();
let mut index = index.as_mut().unwrap();
publish::publish_crate(body, &mut index).map(|()| String::new())
})
Expand Down Expand Up @@ -180,7 +186,11 @@ fn run() -> Result<()> {
}

let (addr, serve) = loop {
let routes = index.clone().or(download.clone()).or(publish.clone());
let routes = index
.clone()
.or(crates.clone())
.or(download.clone())
.or(publish.clone());
// Despite the claim that this function "Returns [...] a Future that
// can be executed on any runtime." not even the call itself can
// happen outside of a tokio runtime. Boy.
Expand Down
9 changes: 7 additions & 2 deletions src/publish.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (C) 2020 Daniel Mueller <[email protected]>
// Copyright (C) 2020-2021 Daniel Mueller <[email protected]>
// SPDX-License-Identifier: GPL-3.0-or-later

use std::collections::BTreeMap;
Expand Down Expand Up @@ -171,6 +171,11 @@ impl From<(MetaData, &[u8])> for Entry {
}
}

/// Craft the file name for a crate named `name` in version `version`.
pub fn crate_file_name(name: &str, version: &str) -> String {
format!("{}-{}.crate", name, version)
}

/// Extract and parse a `u32` value from a `Bytes` object.
fn parse_u32(bytes: &mut Bytes) -> Result<u32> {
ensure!(bytes.len() >= size_of::<u32>(), "not enough data for u32");
Expand Down Expand Up @@ -275,7 +280,7 @@ pub fn publish_crate(mut body: Bytes, index: &mut Index) -> Result<()> {
to_writer(&mut file, &entry).context("failed to write crate index meta data")?;
writeln!(file).context("failed to append new line to crate index meta data file")?;

let crate_file_name = format!("{}-{}.crate", crate_name, crate_vers);
let crate_file_name = crate_file_name(&crate_name, &crate_vers);
let crate_path = index.root().join(&crate_file_name);
let mut file = OpenOptions::new()
.write(true)
Expand Down

0 comments on commit b502570

Please sign in to comment.