Skip to content

Commit

Permalink
refactor(http): extract Axum extractor for the URL path param key
Browse files Browse the repository at this point in the history
  • Loading branch information
josecelano committed Mar 1, 2023
1 parent 94fbdeb commit a9e3a33
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 30 deletions.
55 changes: 55 additions & 0 deletions src/http/axum_implementation/extractors/key.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
use std::panic::Location;

use axum::async_trait;
use axum::extract::{FromRequestParts, Path};
use axum::http::request::Parts;
use axum::response::{IntoResponse, Response};

use crate::http::axum_implementation::handlers::auth::{self, KeyIdParam};
use crate::http::axum_implementation::responses;
use crate::tracker::auth::KeyId;

pub struct ExtractKeyId(pub KeyId);

#[async_trait]
impl<S> FromRequestParts<S> for ExtractKeyId
where
S: Send + Sync,
{
type Rejection = Response;

async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
match Path::<KeyIdParam>::from_request_parts(parts, state).await {
Ok(key_id_param) => {
let Ok(key_id) = key_id_param.0.value().parse::<KeyId>() else {
return Err(responses::error::Error::from(
auth::Error::InvalidKeyFormat {
location: Location::caller()
})
.into_response())
};
Ok(ExtractKeyId(key_id))
}
Err(rejection) => match rejection {
axum::extract::rejection::PathRejection::FailedToDeserializePathParams(_) => {
return Err(responses::error::Error::from(auth::Error::InvalidKeyFormat {
location: Location::caller(),
})
.into_response())
}
axum::extract::rejection::PathRejection::MissingPathParams(_) => {
return Err(responses::error::Error::from(auth::Error::MissingAuthKey {
location: Location::caller(),
})
.into_response())
}
_ => {
return Err(responses::error::Error::from(auth::Error::CannotExtractKeyParam {
location: Location::caller(),
})
.into_response())
}
},
}
}
}
1 change: 1 addition & 0 deletions src/http/axum_implementation/extractors/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub mod announce_request;
pub mod key;
pub mod peer_ip;
pub mod remote_client_ip;
pub mod scrape_request;
16 changes: 3 additions & 13 deletions src/http/axum_implementation/handlers/announce.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,19 @@ use std::panic::Location;
use std::sync::Arc;

use aquatic_udp_protocol::{AnnounceEvent, NumberOfBytes};
use axum::extract::{Path, State};
use axum::extract::State;
use axum::response::{IntoResponse, Response};
use log::debug;

use super::auth::KeyIdParam;
use crate::http::axum_implementation::extractors::announce_request::ExtractRequest;
use crate::http::axum_implementation::extractors::key::ExtractKeyId;
use crate::http::axum_implementation::extractors::peer_ip;
use crate::http::axum_implementation::extractors::remote_client_ip::RemoteClientIp;
use crate::http::axum_implementation::handlers::auth;
use crate::http::axum_implementation::requests::announce::{Announce, Compact, Event};
use crate::http::axum_implementation::responses::{self, announce};
use crate::http::axum_implementation::services;
use crate::protocol::clock::{Current, Time};
use crate::tracker::auth::KeyId;
use crate::tracker::peer::Peer;
use crate::tracker::Tracker;

Expand All @@ -42,20 +41,11 @@ pub async fn handle_without_key(
pub async fn handle_with_key(
State(tracker): State<Arc<Tracker>>,
ExtractRequest(announce_request): ExtractRequest,
Path(key_id_param): Path<KeyIdParam>,
ExtractKeyId(key_id): ExtractKeyId,
remote_client_ip: RemoteClientIp,
) -> Response {
debug!("http announce request: {:#?}", announce_request);

// todo: extract to Axum extractor. Duplicate code in `scrape` handler.
let Ok(key_id) = key_id_param.value().parse::<KeyId>() else {
return responses::error::Error::from(
auth::Error::InvalidKeyFormat {
location: Location::caller()
})
.into_response()
};

match tracker.authenticate(&key_id).await {
Ok(_) => (),
Err(error) => return responses::error::Error::from(error).into_response(),
Expand Down
6 changes: 4 additions & 2 deletions src/http/axum_implementation/handlers/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@ impl KeyIdParam {

#[derive(Debug, Error)]
pub enum Error {
#[error("Missing authentication key for private tracker. Error in {location}")]
#[error("Missing authentication key param for private tracker. Error in {location}")]
MissingAuthKey { location: &'static Location<'static> },
#[error("Invalid format authentication key. Error in {location}")]
#[error("Invalid format for authentication key param. Error in {location}")]
InvalidKeyFormat { location: &'static Location<'static> },
#[error("Cannot extract authentication key param from URL path. Error in {location}")]
CannotExtractKeyParam { location: &'static Location<'static> },
}

impl From<Error> for responses::error::Error {
Expand Down
18 changes: 3 additions & 15 deletions src/http/axum_implementation/handlers/scrape.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
use std::panic::Location;
use std::sync::Arc;

use axum::extract::{Path, State};
use axum::extract::State;
use axum::response::{IntoResponse, Response};
use log::debug;

use super::auth::KeyIdParam;
use crate::http::axum_implementation::extractors::key::ExtractKeyId;
use crate::http::axum_implementation::extractors::peer_ip;
use crate::http::axum_implementation::extractors::remote_client_ip::RemoteClientIp;
use crate::http::axum_implementation::extractors::scrape_request::ExtractRequest;
use crate::http::axum_implementation::handlers::auth;
use crate::http::axum_implementation::requests::scrape::Scrape;
use crate::http::axum_implementation::{responses, services};
use crate::tracker::auth::KeyId;
use crate::tracker::Tracker;

#[allow(clippy::unused_async)]
Expand All @@ -34,20 +31,11 @@ pub async fn handle_without_key(
pub async fn handle_with_key(
State(tracker): State<Arc<Tracker>>,
ExtractRequest(scrape_request): ExtractRequest,
Path(key_id_param): Path<KeyIdParam>,
ExtractKeyId(key_id): ExtractKeyId,
remote_client_ip: RemoteClientIp,
) -> Response {
debug!("http scrape request: {:#?}", &scrape_request);

// todo: extract to Axum extractor. Duplicate code in `announce` handler.
let Ok(key_id) = key_id_param.value().parse::<KeyId>() else {
return responses::error::Error::from(
auth::Error::InvalidKeyFormat {
location: Location::caller()
})
.into_response()
};

match tracker.authenticate(&key_id).await {
Ok(_) => (),
Err(_) => return handle_fake_scrape(&tracker, &scrape_request, &remote_client_ip).await,
Expand Down

0 comments on commit a9e3a33

Please sign in to comment.