From 7ec903d712e634f37df3d129ee9a940f5b720205 Mon Sep 17 00:00:00 2001 From: xphoniex Date: Wed, 18 Jan 2023 14:09:48 +0000 Subject: [PATCH] httpd: Update axum from 0.5.x to 0.6.x Signed-off-by: xphoniex --- Cargo.lock | 24 +++++++++---- radicle-httpd/Cargo.toml | 4 +-- radicle-httpd/src/api/axum_extra.rs | 19 ++++++----- radicle-httpd/src/api/v1/delegates.rs | 7 ++-- radicle-httpd/src/api/v1/node.rs | 7 ++-- radicle-httpd/src/api/v1/projects.rs | 49 ++++++++++++++------------- radicle-httpd/src/api/v1/sessions.rs | 11 +++--- radicle-httpd/src/api/v1/stats.rs | 7 ++-- radicle-httpd/src/lib.rs | 2 +- 9 files changed, 75 insertions(+), 55 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c024c800..ef96c84f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -148,9 +148,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "axum" -version = "0.5.17" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acee9fd5073ab6b045a275b3e709c163dd36c90685219cb21804a147b58dba43" +checksum = "1304eab461cf02bd70b083ed8273388f9724c549b316ba3d1e213ce0e9e7fb7e" dependencies = [ "async-trait", "axum-core", @@ -167,8 +167,10 @@ dependencies = [ "mime", "percent-encoding", "pin-project-lite", + "rustversion", "serde", "serde_json", + "serde_path_to_error", "serde_urlencoded", "sync_wrapper", "tokio", @@ -180,9 +182,9 @@ dependencies = [ [[package]] name = "axum-core" -version = "0.2.9" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37e5939e02c56fecd5c017c37df4238c0a839fa76b7f97acdd7efb804fd181cc" +checksum = "f487e40dc9daee24d8a1779df88522f159a54a980f99cfbe43db0be0bd3444a8" dependencies = [ "async-trait", "bytes", @@ -190,6 +192,7 @@ dependencies = [ "http", "http-body", "mime", + "rustversion", "tower-layer", "tower-service", ] @@ -1587,9 +1590,9 @@ dependencies = [ [[package]] name = "matchit" -version = "0.5.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73cbba799671b762df5a175adf59ce145165747bb891505c43d09aefbbf38beb" +checksum = "b87248edafb776e59e6ee64a79086f65890d3510f2c656c000bf2a7e8a0aea40" [[package]] name = "memchr" @@ -2658,6 +2661,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_path_to_error" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b04f22b563c91331a10074bda3dd5492e3cc39d56bd557e91c0af42b6c7341" +dependencies = [ + "serde", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" diff --git a/radicle-httpd/Cargo.toml b/radicle-httpd/Cargo.toml index 4171aace..821416dc 100644 --- a/radicle-httpd/Cargo.toml +++ b/radicle-httpd/Cargo.toml @@ -16,8 +16,8 @@ logfmt = [ [dependencies] anyhow = { version = "1" } -axum = { version = "0.5.16", default-features = false, features = ["json", "headers", "query"] } -axum-server = { version = "0.4.2", default-features = false } +axum = { version = "0.6.2", default-features = false, features = ["headers", "json", "query", "tokio"] } +axum-server = { version = "0.4.4", default-features = false } chrono = { version = "0.4.22" } ethers-core = { version = "1.0" } fastrand = { version = "1.7.0" } diff --git a/radicle-httpd/src/api/axum_extra.rs b/radicle-httpd/src/api/axum_extra.rs index 8c23f965..0e1b1386 100644 --- a/radicle-httpd/src/api/axum_extra.rs +++ b/radicle-httpd/src/api/axum_extra.rs @@ -1,6 +1,7 @@ use axum::extract::path::ErrorKind; use axum::extract::rejection::{PathRejection, QueryRejection}; -use axum::extract::{FromRequest, RequestParts}; +use axum::extract::FromRequestParts; +use axum::http::request::Parts; use axum::http::StatusCode; use axum::{async_trait, Json}; @@ -10,15 +11,15 @@ use serde::Serialize; pub struct Path(pub T); #[async_trait] -impl FromRequest for Path +impl FromRequestParts for Path where T: DeserializeOwned + Send, - B: Send, + S: Send + Sync, { type Rejection = (StatusCode, axum::Json); - async fn from_request(req: &mut RequestParts) -> Result { - match axum::extract::Path::::from_request(req).await { + async fn from_request_parts(req: &mut Parts, state: &S) -> Result { + match axum::extract::Path::::from_request_parts(req, state).await { Ok(value) => Ok(Self(value.0)), Err(rejection) => { let status = StatusCode::BAD_REQUEST; @@ -52,15 +53,15 @@ where pub struct Query(pub T); #[async_trait] -impl FromRequest for Query +impl FromRequestParts for Query where T: DeserializeOwned + Send, - B: Send, + S: Send + Sync, { type Rejection = (StatusCode, axum::Json); - async fn from_request(req: &mut RequestParts) -> Result { - match axum::extract::Query::::from_request(req).await { + async fn from_request_parts(req: &mut Parts, state: &S) -> Result { + match axum::extract::Query::::from_request_parts(req, state).await { Ok(value) => Ok(Self(value.0)), Err(rejection) => { let status = StatusCode::BAD_REQUEST; diff --git a/radicle-httpd/src/api/v1/delegates.rs b/radicle-httpd/src/api/v1/delegates.rs index 8e8c2a0e..499ca909 100644 --- a/radicle-httpd/src/api/v1/delegates.rs +++ b/radicle-httpd/src/api/v1/delegates.rs @@ -1,6 +1,7 @@ +use axum::extract::State; use axum::response::IntoResponse; use axum::routing::get; -use axum::{Extension, Json, Router}; +use axum::{Json, Router}; use radicle::cob::issue::Issues; use radicle::identity::Did; @@ -18,13 +19,13 @@ pub fn router(ctx: Context) -> Router { "/delegates/:delegate/projects", get(delegates_projects_handler), ) - .layer(Extension(ctx)) + .with_state(ctx) } /// List all projects which delegate is a part of. /// `GET /delegates/:delegate/projects` async fn delegates_projects_handler( - Extension(ctx): Extension, + State(ctx): State, Path(delegate): Path, Query(qs): Query, ) -> impl IntoResponse { diff --git a/radicle-httpd/src/api/v1/node.rs b/radicle-httpd/src/api/v1/node.rs index 529c6598..1dfea613 100644 --- a/radicle-httpd/src/api/v1/node.rs +++ b/radicle-httpd/src/api/v1/node.rs @@ -1,6 +1,7 @@ +use axum::extract::State; use axum::response::IntoResponse; use axum::routing::get; -use axum::{Extension, Json, Router}; +use axum::{Json, Router}; use serde_json::json; use radicle::node::NodeId; @@ -12,12 +13,12 @@ pub fn router(ctx: Context) -> Router { Router::new() .route("/node", get(node_handler)) - .layer(Extension(node_id)) + .with_state(node_id) } /// Return the node id for the node identity. /// `GET /node` -async fn node_handler(Extension(node_id): Extension) -> impl IntoResponse { +async fn node_handler(State(node_id): State) -> impl IntoResponse { let response = json!({ "id": node_id.to_string(), }); diff --git a/radicle-httpd/src/api/v1/projects.rs b/radicle-httpd/src/api/v1/projects.rs index 36cc7f91..68c9e11f 100644 --- a/radicle-httpd/src/api/v1/projects.rs +++ b/radicle-httpd/src/api/v1/projects.rs @@ -1,10 +1,11 @@ use std::collections::BTreeMap; +use axum::extract::State; use axum::handler::Handler; use axum::http::{header, HeaderValue}; use axum::response::IntoResponse; use axum::routing::get; -use axum::{Extension, Json, Router}; +use axum::{Json, Router}; use hyper::StatusCode; use serde::{Deserialize, Serialize}; use serde_json::json; @@ -40,6 +41,7 @@ pub fn router(ctx: Context) -> Router { )), ), ) + .route("/projects/:project/tree/:sha/", get(tree_handler_root)) .route("/projects/:project/tree/:sha/*path", get(tree_handler)) .route("/projects/:project/remotes", get(remotes_handler)) .route("/projects/:project/remotes/:peer", get(remote_handler)) @@ -47,13 +49,13 @@ pub fn router(ctx: Context) -> Router { .route("/projects/:project/readme/:sha", get(readme_handler)) .route("/projects/:project/issues", get(issues_handler)) .route("/projects/:project/issues/:id", get(issue_handler)) - .layer(Extension(ctx)) + .with_state(ctx) } /// List all projects. /// `GET /projects` async fn project_root_handler( - Extension(ctx): Extension, + State(ctx): State, Query(qs): Query, ) -> impl IntoResponse { let PaginationQuery { page, per_page } = qs; @@ -87,10 +89,7 @@ async fn project_root_handler( /// Get project metadata. /// `GET /projects/:project` -async fn project_handler( - Extension(ctx): Extension, - Path(id): Path, -) -> impl IntoResponse { +async fn project_handler(State(ctx): State, Path(id): Path) -> impl IntoResponse { let info = ctx.project_info(id)?; Ok::<_, Error>(Json(info)) @@ -109,7 +108,7 @@ pub struct CommitsQueryString { /// Get project commit range. /// `GET /projects/:project/commits?since=` async fn history_handler( - Extension(ctx): Extension, + State(ctx): State, Path(project): Path, Query(qs): Query, ) -> impl IntoResponse { @@ -194,7 +193,7 @@ async fn history_handler( /// Get project commit. /// `GET /projects/:project/commits/:sha` async fn commit_handler( - Extension(ctx): Extension, + State(ctx): State, Path((project, sha)): Path<(Id, Oid)>, ) -> impl IntoResponse { let storage = &ctx.profile.storage; @@ -220,7 +219,7 @@ async fn commit_handler( /// Get project activity for the past year. /// `GET /projects/:project/activity` async fn activity_handler( - Extension(ctx): Extension, + State(ctx): State, Path(project): Path, ) -> impl IntoResponse { let current_date = chrono::Utc::now().timestamp(); @@ -244,13 +243,21 @@ async fn activity_handler( Ok::<_, Error>((StatusCode::OK, Json(json!({ "activity": timestamps })))) } +/// Get project source tree for '/' path. +/// `GET /projects/:project/tree/:sha/` +async fn tree_handler_root( + State(ctx): State, + Path((project, sha)): Path<(Id, Oid)>, +) -> impl IntoResponse { + tree_handler(State(ctx), Path((project, sha, String::new()))).await +} + /// Get project source tree. /// `GET /projects/:project/tree/:sha/*path` async fn tree_handler( - Extension(ctx): Extension, + State(ctx): State, Path((project, sha, path)): Path<(Id, Oid, String)>, ) -> impl IntoResponse { - let path = path.strip_prefix('/').ok_or(Error::NotFound)?.to_string(); let storage = &ctx.profile.storage; let repo = Repository::open(paths::repository(storage, &project))?; let tree = repo.tree(sha, &path)?; @@ -262,10 +269,7 @@ async fn tree_handler( /// Get all project remotes. /// `GET /projects/:project/remotes` -async fn remotes_handler( - Extension(ctx): Extension, - Path(project): Path, -) -> impl IntoResponse { +async fn remotes_handler(State(ctx): State, Path(project): Path) -> impl IntoResponse { let storage = &ctx.profile.storage; let repo = storage.repository(project)?; let remotes = repo @@ -296,7 +300,7 @@ async fn remotes_handler( /// Get project remote. /// `GET /projects/:project/remotes/:peer` async fn remote_handler( - Extension(ctx): Extension, + State(ctx): State, Path((project, node_id)): Path<(Id, NodeId)>, ) -> impl IntoResponse { let storage = &ctx.profile.storage; @@ -323,14 +327,13 @@ async fn remote_handler( /// Get project source file. /// `GET /projects/:project/blob/:sha/*path` async fn blob_handler( - Extension(ctx): Extension, + State(ctx): State, Path((project, sha, path)): Path<(Id, Oid, String)>, ) -> impl IntoResponse { - let path = path.strip_prefix('/').ok_or(Error::NotFound)?; let storage = &ctx.profile.storage; let repo = Repository::open(paths::repository(storage, &project))?; let blob = repo.blob(sha, &path)?; - let response = api::json::blob(&blob, path); + let response = api::json::blob(&blob, &path); Ok::<_, Error>(Json(response)) } @@ -338,7 +341,7 @@ async fn blob_handler( /// Get project readme. /// `GET /projects/:project/readme/:sha` async fn readme_handler( - Extension(ctx): Extension, + State(ctx): State, Path((project, sha)): Path<(Id, Oid)>, ) -> impl IntoResponse { let storage = &ctx.profile.storage; @@ -365,7 +368,7 @@ async fn readme_handler( /// Get project issues list. /// `GET /projects/:project/issues` async fn issues_handler( - Extension(ctx): Extension, + State(ctx): State, Path(project): Path, Query(qs): Query, ) -> impl IntoResponse { @@ -399,7 +402,7 @@ async fn issues_handler( /// Get project issue. /// `GET /projects/:project/issues/:id` async fn issue_handler( - Extension(ctx): Extension, + State(ctx): State, Path((project, issue_id)): Path<(Id, Oid)>, ) -> impl IntoResponse { let storage = &ctx.profile.storage; diff --git a/radicle-httpd/src/api/v1/sessions.rs b/radicle-httpd/src/api/v1/sessions.rs index 1b03d737..6ce7ad31 100644 --- a/radicle-httpd/src/api/v1/sessions.rs +++ b/radicle-httpd/src/api/v1/sessions.rs @@ -4,9 +4,10 @@ use std::env; use std::iter::repeat_with; use std::str::FromStr; +use axum::extract::State; use axum::response::IntoResponse; use axum::routing::{get, post}; -use axum::{Extension, Json, Router}; +use axum::{Json, Router}; use ethers_core::utils::hex; use hyper::http::uri::Authority; use serde_json::json; @@ -27,12 +28,12 @@ pub fn router(ctx: Context) -> Router { "/sessions/:id", get(session_get_handler).put(session_signin_handler), ) - .layer(Extension(ctx)) + .with_state(ctx) } /// Create session. /// `POST /sessions` -async fn session_create_handler(Extension(ctx): Extension) -> impl IntoResponse { +async fn session_create_handler(State(ctx): State) -> impl IntoResponse { let expiration_time = OffsetDateTime::now_utc() .checked_add(UNAUTHORIZED_SESSIONS_EXPIRATION) .unwrap(); @@ -45,7 +46,7 @@ async fn session_create_handler(Extension(ctx): Extension) -> impl Into /// Get session. /// `GET /sessions/:id` async fn session_get_handler( - Extension(ctx): Extension, + State(ctx): State, Path(id): Path, ) -> impl IntoResponse { let sessions = ctx.sessions.read().await; @@ -67,7 +68,7 @@ async fn session_get_handler( /// Update session. /// `PUT /sessions/:id` async fn session_signin_handler( - Extension(ctx): Extension, + State(ctx): State, Path(id): Path, Json(request): Json, ) -> impl IntoResponse { diff --git a/radicle-httpd/src/api/v1/stats.rs b/radicle-httpd/src/api/v1/stats.rs index a1bb588a..aadbf8d2 100644 --- a/radicle-httpd/src/api/v1/stats.rs +++ b/radicle-httpd/src/api/v1/stats.rs @@ -1,6 +1,7 @@ +use axum::extract::State; use axum::response::IntoResponse; use axum::routing::get; -use axum::{Extension, Json, Router}; +use axum::{Json, Router}; use serde_json::json; use crate::api::error::Error; @@ -9,12 +10,12 @@ use crate::api::Context; pub fn router(ctx: Context) -> Router { Router::new() .route("/stats", get(stats_handler)) - .layer(Extension(ctx)) + .with_state(ctx) } /// Return the stats for the node. /// `GET /stats` -async fn stats_handler(Extension(ctx): Extension) -> impl IntoResponse { +async fn stats_handler(State(ctx): State) -> impl IntoResponse { let storage = &ctx.profile.storage; let projects = storage.projects()?.len(); diff --git a/radicle-httpd/src/lib.rs b/radicle-httpd/src/lib.rs index baa77cd8..fe5bd696 100644 --- a/radicle-httpd/src/lib.rs +++ b/radicle-httpd/src/lib.rs @@ -98,9 +98,9 @@ async fn git_handler( AxumPath((project, request)): AxumPath<(String, String)>, method: Method, headers: HeaderMap, - body: Bytes, ConnectInfo(remote): ConnectInfo, query: RawQuery, + body: Bytes, ) -> impl IntoResponse { let query = query.0.unwrap_or_default(); let id: Id = project.strip_suffix(".git").unwrap_or(&project).parse()?;