From 34b15f9f16d95de3f78e32ca4610280fdf16eb6c Mon Sep 17 00:00:00 2001 From: xphoniex Date: Thu, 23 Feb 2023 06:16:37 +0000 Subject: [PATCH] httpd: Add `/raw` route Signed-off-by: xphoniex --- radicle-httpd/src/api.rs | 1 - radicle-httpd/src/api/v1/delegates.rs | 2 +- radicle-httpd/src/api/v1/projects.rs | 5 +- radicle-httpd/src/api/v1/sessions.rs | 2 +- radicle-httpd/src/{api => }/axum_extra.rs | 0 radicle-httpd/src/error.rs | 4 ++ radicle-httpd/src/lib.rs | 6 ++- radicle-httpd/src/raw.rs | 59 +++++++++++++++++++++++ radicle-httpd/src/test.rs | 6 ++- 9 files changed, 78 insertions(+), 7 deletions(-) rename radicle-httpd/src/{api => }/axum_extra.rs (100%) create mode 100644 radicle-httpd/src/raw.rs diff --git a/radicle-httpd/src/api.rs b/radicle-httpd/src/api.rs index 4f89da50..848fdef5 100644 --- a/radicle-httpd/src/api.rs +++ b/radicle-httpd/src/api.rs @@ -21,7 +21,6 @@ use radicle::identity::Id; use radicle::storage::{ReadRepository, ReadStorage}; use radicle::Profile; -mod axum_extra; mod error; mod json; mod v1; diff --git a/radicle-httpd/src/api/v1/delegates.rs b/radicle-httpd/src/api/v1/delegates.rs index 52fa5ca5..530dc76d 100644 --- a/radicle-httpd/src/api/v1/delegates.rs +++ b/radicle-httpd/src/api/v1/delegates.rs @@ -8,11 +8,11 @@ use radicle::cob::patch::Patches; use radicle::identity::Did; use radicle::storage::{ReadRepository, ReadStorage}; -use crate::api::axum_extra::{Path, Query}; use crate::api::error::Error; use crate::api::project::Info; use crate::api::Context; use crate::api::PaginationQuery; +use crate::axum_extra::{Path, Query}; pub fn router(ctx: Context) -> Router { Router::new() diff --git a/radicle-httpd/src/api/v1/projects.rs b/radicle-httpd/src/api/v1/projects.rs index d768a3e4..1bde6fee 100644 --- a/radicle-httpd/src/api/v1/projects.rs +++ b/radicle-httpd/src/api/v1/projects.rs @@ -17,13 +17,14 @@ use radicle::cob::patch::Patches; use radicle::cob::{thread, ActorId, Tag}; use radicle::identity::Id; use radicle::node::NodeId; -use radicle::storage::{git::paths, ReadRepository, ReadStorage}; +use radicle::storage::git::paths; +use radicle::storage::{ReadRepository, ReadStorage}; use radicle_surf::{Glob, Oid, Repository}; -use crate::api::axum_extra::{Path, Query}; use crate::api::error::Error; use crate::api::project::Info; use crate::api::{self, Context, PaginationQuery}; +use crate::axum_extra::{Path, Query}; const CACHE_1_HOUR: &str = "public, max-age=3600, must-revalidate"; diff --git a/radicle-httpd/src/api/v1/sessions.rs b/radicle-httpd/src/api/v1/sessions.rs index c1e2146b..340951fb 100644 --- a/radicle-httpd/src/api/v1/sessions.rs +++ b/radicle-httpd/src/api/v1/sessions.rs @@ -11,10 +11,10 @@ use serde::{Deserialize, Serialize}; use time::OffsetDateTime; use crate::api::auth::{self, AuthState, Session}; -use crate::api::axum_extra::Path; use crate::api::error::Error; use crate::api::json; use crate::api::Context; +use crate::axum_extra::Path; pub fn router(ctx: Context) -> Router { Router::new() diff --git a/radicle-httpd/src/api/axum_extra.rs b/radicle-httpd/src/axum_extra.rs similarity index 100% rename from radicle-httpd/src/api/axum_extra.rs rename to radicle-httpd/src/axum_extra.rs diff --git a/radicle-httpd/src/error.rs b/radicle-httpd/src/error.rs index 1bee5d9e..a722aa8e 100644 --- a/radicle-httpd/src/error.rs +++ b/radicle-httpd/src/error.rs @@ -31,6 +31,10 @@ pub enum Error { /// HeaderValue error. #[error(transparent)] InvalidHeaderValue(#[from] axum::http::header::InvalidHeaderValue), + + /// Surf error. + #[error(transparent)] + Surf(#[from] radicle_surf::Error), } impl Error { diff --git a/radicle-httpd/src/lib.rs b/radicle-httpd/src/lib.rs index 29dd01ad..f69bf097 100644 --- a/radicle-httpd/src/lib.rs +++ b/radicle-httpd/src/lib.rs @@ -16,7 +16,9 @@ use tower_http::trace::TraceLayer; use tracing::Span; mod api; +mod axum_extra; mod git; +mod raw; #[cfg(test)] mod test; @@ -41,13 +43,15 @@ pub async fn run(options: Options) -> anyhow::Result<()> { let ctx = api::Context::new(profile.clone()); let api_router = api::router(ctx); - let git_router = git::router(profile); + let git_router = git::router(profile.clone()); + let raw_router = raw::router(profile); tracing::info!("listening on http://{}", options.listen); let app = Router::new() .merge(git_router) .nest("/api", api_router) + .nest("/raw", raw_router) .layer( TraceLayer::new_for_http() .make_span_with(|request: &Request| { diff --git a/radicle-httpd/src/raw.rs b/radicle-httpd/src/raw.rs new file mode 100644 index 00000000..648defc9 --- /dev/null +++ b/radicle-httpd/src/raw.rs @@ -0,0 +1,59 @@ +use std::sync::Arc; + +use axum::extract::State; +use axum::http::header; +use axum::response::IntoResponse; +use axum::routing::get; +use axum::Router; +use hyper::HeaderMap; + +use radicle::prelude::Id; +use radicle::profile::Profile; +use radicle::storage::git::paths; +use radicle_surf::{Oid, Repository}; + +use crate::axum_extra::Path; +use crate::error::Error; + +pub fn router(profile: Arc) -> Router { + Router::new() + .route("/:project/:sha/*path", get(file_handler)) + .with_state(profile) +} + +async fn file_handler( + Path((project, sha, path)): Path<(Id, Oid, String)>, + State(profile): State>, +) -> impl IntoResponse { + let storage = &profile.storage; + let repo = Repository::open(paths::repository(storage, &project))?; + let blob = repo.blob(sha, &path)?; + + let mut response_headers = HeaderMap::new(); + response_headers.insert(header::CONTENT_TYPE, "text; charset=utf-8".parse().unwrap()); + + Ok::<_, Error>((response_headers, blob.content().to_owned())) +} + +#[cfg(test)] +mod routes { + use axum::http::StatusCode; + + use crate::test::{self, get, HEAD}; + + #[tokio::test] + async fn test_file_handler() { + let tmp = tempfile::tempdir().unwrap(); + let ctx = test::seed(tmp.path()); + let app = super::router(ctx.profile().to_owned()); + + let response = get( + &app, + format!("/rad:z4FucBZHZMCsxTyQE1dfE2YR59Qbp/{HEAD}/dir1/README"), + ) + .await; + + assert_eq!(response.status(), StatusCode::OK); + assert_eq!(response.body().await, "Hello World from dir1!\n"); + } +} diff --git a/radicle-httpd/src/test.rs b/radicle-httpd/src/test.rs index 283ac818..d3f9c948 100644 --- a/radicle-httpd/src/test.rs +++ b/radicle-httpd/src/test.rs @@ -4,7 +4,7 @@ use std::str::FromStr; use std::sync::Arc; use std::{env, fs}; -use axum::body::Body; +use axum::body::{Body, Bytes}; use axum::http::{Method, Request}; use axum::Router; use serde_json::Value; @@ -235,4 +235,8 @@ impl Response { pub fn status(&self) -> axum::http::StatusCode { self.0.status() } + + pub async fn body(self) -> Bytes { + hyper::body::to_bytes(self.0.into_body()).await.unwrap() + } }