diff --git a/src/serve.rs b/src/serve.rs index f1ad4bc..2638262 100644 --- a/src/serve.rs +++ b/src/serve.rs @@ -16,9 +16,11 @@ use tracing::info; use warp::http::StatusCode; use warp::http::Uri; use warp::reject::Reject; -use warp::Filter; +use warp::{Filter, Reply, reply, trace}; +use warp::fs::File; use warp::Rejection; - +use warp::reply::Response; +use warp::trace::Info; use crate::index::handle_git; use crate::index::Index; use crate::publish::crate_file_name; @@ -142,7 +144,7 @@ pub async fn serve(root: &Path, binding: impl Into, server_addr: body, query, ) - .await, + .await, ) } }, @@ -154,7 +156,22 @@ pub async fn serve(root: &Path, binding: impl Into, server_addr: // downloading the .crate files, to which we redirect from the // download handler below. let crates = warp::path("crates") - .and(warp::fs::dir(crates_folder.to_path_buf())) + .and(warp::fs::dir(crates_folder.to_path_buf()) + // warp::fs::dir uses `and_then` so if file is missing it will try to find another route that match + // until returning Method not allowed... + // so we fix that by returning not found explicitly + .recover( + |err: Rejection| async { + if err.is_not_found() { + return Ok(reply::with_status(reply::json(&RegistryError { + detail: "Not found".to_string(), + }), StatusCode::NOT_FOUND)); + } + + return Err(err); + }) + ) + .with(warp::trace::request()); let download = warp::path("api") .and(warp::path("v1")) diff --git a/tests/end-to-end.rs b/tests/end-to-end.rs index cc22d2f..daa93c8 100644 --- a/tests/end-to-end.rs +++ b/tests/end-to-end.rs @@ -10,10 +10,9 @@ use anyhow::anyhow; use anyhow::bail; use anyhow::Context as _; use anyhow::Result; - -use reqwest::Url; +use reqwest::{Method, StatusCode, Url}; +use reqwest::header::USER_AGENT; use tempfile::tempdir; - use tokio::net::TcpListener; use tokio::spawn; use tokio::task::JoinHandle; @@ -40,6 +39,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(file: &Path, data: B) -> Result<()> where @@ -181,8 +194,42 @@ 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(); + + // "/crates/my/-l/my-lib-0.1.0.crate" + 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_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 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); } async fn test_publish_and_consume(registry_locator: Locator) {