From 47ea4bb9862a0c8354ca205dc25ee6f0991b5d5c Mon Sep 17 00:00:00 2001 From: Jordan Doyle Date: Fri, 03 Jan 2025 21:13:17 +0700 Subject: [PATCH] Split out URI parsing code to improve testability and remove need for boxing --- Cargo.lock | 3 +-- Cargo.toml | 1 - src/methods/repo/mod.rs | 190 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------- 3 files changed, 137 insertions(+), 57 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fece92b..239bd46 100644 --- a/Cargo.lock +++ a/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 4 +version = 3 [[package]] name = "addr2line" @@ -2600,7 +2600,6 @@ "tokio", "tokio-stream", "tokio-util", - "tower", "tower-http", "tower-layer", "tower-service", diff --git a/Cargo.toml b/Cargo.toml index ae94462..6f93ff9 100644 --- a/Cargo.toml +++ a/Cargo.toml @@ -68,7 +68,6 @@ tokio = { version = "1.42", features = ["full", "tracing"] } tokio-stream = "0.1" tokio-util = { version = "0.7.10", features = ["io"] } -tower = "0.5" tower-http = { version = "0.6", features = ["cors", "timeout"] } tower-layer = "0.3" tower-service = "0.3" diff --git a/src/methods/repo/mod.rs b/src/methods/repo/mod.rs index 821836d..34d8c9e 100644 --- a/src/methods/repo/mod.rs +++ a/src/methods/repo/mod.rs @@ -18,12 +18,11 @@ use axum::{ body::Body, - handler::HandlerWithoutStateExt, + handler::Handler, http::{Request, StatusCode}, response::{IntoResponse, Response}, }; use path_clean::PathClean; -use tower::{util::BoxCloneService, Service}; use self::{ about::handle as handle_about, @@ -38,10 +37,7 @@ tree::handle as handle_tree, }; use crate::database::schema::tag::YokedString; -use crate::{ - database::schema::{commit::YokedCommit, tag::YokedTag}, - layers::UnwrapInfallible, -}; +use crate::database::schema::{commit::YokedCommit, tag::YokedTag}; pub const DEFAULT_BRANCHES: [&str; 2] = ["refs/heads/master", "refs/heads/main"]; @@ -52,16 +48,53 @@ .extensions() .get::>() .expect("scan_path missing"); + + let ParsedUri { + uri, + child_path, + action, + } = parse_uri(request.uri().path().trim_matches('/')); + + let uri = Path::new(uri).clean(); + let path = scan_path.join(&uri); + + let db = request + .extensions() + .get::>() + .expect("db extension missing"); + if path.as_os_str().is_empty() + || !crate::database::schema::repository::Repository::exists(db, &uri).unwrap_or_default() + { + return RepositoryNotFound.into_response(); + } - let mut child_path = None; + request.extensions_mut().insert(ChildPath(child_path)); + request.extensions_mut().insert(Repository(uri)); + request.extensions_mut().insert(RepositoryPath(path)); - macro_rules! h { - ($handler:ident) => { - BoxCloneService::new($handler.into_service()) - }; + match action { + HandlerAction::About => handle_about.call(request, None::<()>).await, + HandlerAction::SmartGit => handle_smart_git.call(request, None::<()>).await, + HandlerAction::Refs => handle_refs.call(request, None::<()>).await, + HandlerAction::Log => handle_log.call(request, None::<()>).await, + HandlerAction::Tree => handle_tree.call(request, None::<()>).await, + HandlerAction::Commit => handle_commit.call(request, None::<()>).await, + HandlerAction::Diff => handle_diff.call(request, None::<()>).await, + HandlerAction::Patch => handle_patch.call(request, None::<()>).await, + HandlerAction::Tag => handle_tag.call(request, None::<()>).await, + HandlerAction::Snapshot => handle_snapshot.call(request, None::<()>).await, + HandlerAction::Summary => handle_summary.call(request, None::<()>).await, } +} + +#[derive(Debug, PartialEq, Eq)] +struct ParsedUri<'a> { + action: HandlerAction, + uri: &'a str, + child_path: Option, +} - let uri = request.uri().path().trim_matches('/'); +fn parse_uri(uri: &str) -> ParsedUri<'_> { let mut uri_parts = memchr::memchr_iter(b'/', uri.as_bytes()); let original_uri = uri; @@ -71,28 +104,75 @@ (None, uri) }; - let mut service = match action { - Some("about") => h!(handle_about), - Some("git-upload-pack") => h!(handle_smart_git), + match action { + Some("about") => ParsedUri { + action: HandlerAction::About, + uri, + child_path: None, + }, + Some("git-upload-pack") => ParsedUri { + action: HandlerAction::SmartGit, + uri, + child_path: None, + }, Some("refs") => { if let Some(idx) = uri_parts.next_back() { if uri.get(idx + 1..) == Some("info") { - uri = &uri[..idx]; - h!(handle_smart_git) + ParsedUri { + action: HandlerAction::SmartGit, + uri: &uri[..idx], + child_path: None, + } } else { - h!(handle_refs) + ParsedUri { + action: HandlerAction::Refs, + uri, + child_path: None, + } } } else { - h!(handle_refs) + ParsedUri { + action: HandlerAction::Refs, + uri, + child_path: None, + } } } - Some("log") => h!(handle_log), - Some("tree") => h!(handle_tree), - Some("commit") => h!(handle_commit), - Some("diff") => h!(handle_diff), - Some("patch") => h!(handle_patch), - Some("tag") => h!(handle_tag), - Some("snapshot") => h!(handle_snapshot), + Some("log") => ParsedUri { + action: HandlerAction::Log, + uri, + child_path: None, + }, + Some("tree") => ParsedUri { + action: HandlerAction::Tree, + uri, + child_path: None, + }, + Some("commit") => ParsedUri { + action: HandlerAction::Commit, + uri, + child_path: None, + }, + Some("diff") => ParsedUri { + action: HandlerAction::Diff, + uri, + child_path: None, + }, + Some("patch") => ParsedUri { + action: HandlerAction::Patch, + uri, + child_path: None, + }, + Some("tag") => ParsedUri { + action: HandlerAction::Tag, + uri, + child_path: None, + }, + Some("snapshot") => ParsedUri { + action: HandlerAction::Snapshot, + uri, + child_path: None, + }, Some(_) => { static TREE_FINDER: LazyLock = LazyLock::new(|| memchr::memmem::Finder::new(b"/tree/")); @@ -101,39 +181,41 @@ // match tree children if let Some(idx) = TREE_FINDER.find(uri.as_bytes()) { - // 6 is the length of /tree/ - child_path = Some(Path::new(&uri[idx + 6..]).clean()); - uri = &uri[..idx]; - h!(handle_tree) + ParsedUri { + action: HandlerAction::Tree, + uri: &uri[..idx], + // 6 is the length of /tree/ + child_path: Some(Path::new(&uri[idx + 6..]).clean()), + } } else { - h!(handle_summary) + ParsedUri { + action: HandlerAction::Summary, + uri, + child_path: None, + } } } - None => h!(handle_summary), - }; - - let uri = Path::new(uri).clean(); - let path = scan_path.join(&uri); - - let db = request - .extensions() - .get::>() - .expect("db extension missing"); - if path.as_os_str().is_empty() - || !crate::database::schema::repository::Repository::exists(db, &uri).unwrap_or_default() - { - return RepositoryNotFound.into_response(); + None => ParsedUri { + action: HandlerAction::Summary, + uri, + child_path: None, + }, } - - request.extensions_mut().insert(ChildPath(child_path)); - request.extensions_mut().insert(Repository(uri)); - request.extensions_mut().insert(RepositoryPath(path)); +} - service - .call(request) - .await - .unwrap_infallible() - .into_response() +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +enum HandlerAction { + About, + SmartGit, + Refs, + Log, + Tree, + Commit, + Diff, + Patch, + Tag, + Snapshot, + Summary, } #[derive(Clone)] -- rgit 0.1.4