Skip to content
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

Add HEAD request to /download (#14) and fix GET /download missing crate return 405 (#15) #16

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
25 changes: 25 additions & 0 deletions src/serve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,30 @@ pub async fn serve(root: &Path, binding: impl Into<ServerBinding>, server_addr:
path.parse::<Uri>().map(warp::redirect).unwrap()
})
.with(warp::trace::request());
let download_head = warp::head()
.and(warp::path("api"))
.and(warp::path("v1"))
.and(warp::path("crates"))
.and(warp::path::param())
.and(warp::path::param())
.and(warp::path("download"))
.map(move |name: String, version: String| {
let crate_path = crate_path(&name).join(crate_file_name(&name, &version));
let path = format!(
"/crates/{}",
crate_path
.components()
.map(|c| format!("{}", c.as_os_str().to_str().unwrap()))
.join("/")
);

// 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()
})
.with(warp::trace::request());
let publish = warp::put()
.and(warp::path("api"))
.and(warp::path("v1"))
Expand Down Expand Up @@ -210,6 +234,7 @@ pub async fn serve(root: &Path, binding: impl Into<ServerBinding>, server_addr:
let routes = frontend
.or(crates)
.or(download)
.or(download_head)
.or(publish)
.or(dist_dir)
.or(rustup_dir)
Expand Down
83 changes: 70 additions & 13 deletions tests/end-to-end.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ use anyhow::anyhow;
use anyhow::bail;
use anyhow::Context as _;
use anyhow::Result;

use reqwest::Url;
use reqwest::header::USER_AGENT;
use reqwest::{Method, StatusCode, Url};
use tempfile::tempdir;

use tokio::net::TcpListener;
Expand Down Expand Up @@ -40,6 +40,20 @@ async fn get_listener_in_available_port() -> TcpListener {
panic!("No port available");
}

async fn send_download_request(addr: SocketAddr, method: Method, pkg_name: &str, ver: &str)-> StatusCode {
let client = reqwest::Client::new();

let base_url = format!("http://{}/api/v1/crates", addr);

client
.request(method, format!("{}/{}/{}/download", base_url, pkg_name, ver))
.header(USER_AGENT, "cargo-upload")
.send()
.await
.expect("Failed to send request")
.status()
}

/// Append data to a file.
fn append<B>(file: &Path, data: B) -> Result<()>
where
Expand Down Expand Up @@ -147,17 +161,17 @@ where
async fn serve_registry() -> (JoinHandle<()>, PathBuf, SocketAddr) {
let root = tempdir().unwrap();
let path = root.path();
let listener = get_listener_in_available_port().await;
let addr = listener.local_addr().unwrap();
let listener = get_listener_in_available_port().await;
let addr = listener.local_addr().unwrap();

let server = move || {
let path = path.to_owned();
let addr = addr.clone();
async move { serve(&path, listener, addr).await.unwrap() }
};
let handle = spawn(server());
let server = move || {
let path = path.to_owned();
let addr = addr.clone();
async move { serve(&path, listener, addr).await.unwrap() }
};
let handle = spawn(server());

(handle, path.to_owned(), addr)
(handle, path.to_owned(), addr)
}

/// Check that we can publish a crate.
Expand All @@ -181,8 +195,51 @@ async fn publish() {
my_lib.join("Cargo.toml").to_str().unwrap(),
],
)
.await
.unwrap();
.await
.unwrap();
}

#[tokio::test]
async fn publish_and_consume_download_endpoint() {
let (_handle, _reg_root, addr) = serve_registry().await;

let src_root = tempdir().unwrap();
let src_root = src_root.path();
let home = setup_cargo_home(src_root, Locator::Socket(addr)).unwrap();

let my_lib = src_root.join("my-lib");
cargo_init(&home, ["--lib", my_lib.to_str().unwrap()])
.await
.unwrap();

cargo_publish(
&home,
[
"--manifest-path",
my_lib.join("Cargo.toml").to_str().unwrap(),
],
)
.await
.unwrap();

let existing_crate_and_version_status = send_download_request(addr, Method::GET, "my-lib", "0.1.0").await;
assert_eq!(existing_crate_and_version_status, 200);

let existing_crate_and_version_status = send_download_request(addr, Method::HEAD, "my-lib", "0.1.0").await;
assert_eq!(existing_crate_and_version_status, 200);

let existing_crate_and_missing_version_status = send_download_request(addr, Method::GET, "my-lib", "99.99.99").await;
assert_eq!(existing_crate_and_missing_version_status, 404);

let existing_crate_and_missing_version_status = send_download_request(addr, Method::HEAD, "my-lib", "99.99.99").await;
assert_eq!(existing_crate_and_missing_version_status, 404);

let missing_crate_and_status = send_download_request(addr, Method::GET, "ba93ba78-f47a-4a37-b25b-1c713e5d11f8", "99.99.99").await;
assert_eq!(missing_crate_and_status, 404);

let missing_crate_and_status = send_download_request(addr, Method::HEAD, "ba93ba78-f47a-4a37-b25b-1c713e5d11f8", "99.99.99").await;
assert_eq!(missing_crate_and_status, 404);

}

async fn test_publish_and_consume(registry_locator: Locator) {
Expand Down