atagen

jelq

public

an http based roguelike rpg about jelqing

Star0
Watch0
058650ec79d6eb6841ce768ab49335ed74ae8b97
1
ssh://brewery@pls.lobotomise.me:33/atagen/jelq.git

Blame: src/http/ctx.rs

782069860236atagen2026-10-10 12:44 UTC1
use std::{collections::HashMap, time::Instant};
782069860236atagen2026-10-10 12:44 UTC2
782069860236atagen2026-10-10 12:44 UTC3
use axum::{
782069860236atagen2026-10-10 12:44 UTC4
    body::Bytes,
782069860236atagen2026-10-10 12:44 UTC5
    extract::{FromRequest, FromRequestParts, Query, RawPathParams, Request},
782069860236atagen2026-10-10 12:44 UTC6
    http::{HeaderMap, HeaderName, Method, StatusCode, Uri, Version, header},
782069860236atagen2026-10-10 12:44 UTC7
    response::{IntoResponse, Response},
782069860236atagen2026-10-10 12:44 UTC8
};
782069860236atagen2026-10-10 12:44 UTC9
use hyper::upgrade::OnUpgrade;
782069860236atagen2026-10-10 12:44 UTC10
782069860236atagen2026-10-10 12:44 UTC11
use crate::problem::Problem;
782069860236atagen2026-10-10 12:44 UTC12
782069860236atagen2026-10-10 12:44 UTC13
const BODY_LIMIT: usize = 64 * 1024;
782069860236atagen2026-10-10 12:44 UTC14
782069860236atagen2026-10-10 12:44 UTC15
/// Everything a handler may look at, gathered once per request.
782069860236atagen2026-10-10 12:44 UTC16
pub struct Ctx {
782069860236atagen2026-10-10 12:44 UTC17
    pub method: Method,
782069860236atagen2026-10-10 12:44 UTC18
    pub uri: Uri,
782069860236atagen2026-10-10 12:44 UTC19
    pub version: Version,
782069860236atagen2026-10-10 12:44 UTC20
    pub headers: HeaderMap,
782069860236atagen2026-10-10 12:44 UTC21
    pub query: HashMap<String, String>,
782069860236atagen2026-10-10 12:44 UTC22
    pub params: HashMap<String, String>,
782069860236atagen2026-10-10 12:44 UTC23
    pub body: Bytes,
782069860236atagen2026-10-10 12:44 UTC24
    pub now: Instant,
782069860236atagen2026-10-10 12:44 UTC25
    pub upgrade: Option<OnUpgrade>,
782069860236atagen2026-10-10 12:44 UTC26
}
782069860236atagen2026-10-10 12:44 UTC27
782069860236atagen2026-10-10 12:44 UTC28
impl Ctx {
782069860236atagen2026-10-10 12:44 UTC29
    pub fn header(&self, name: HeaderName) -> Option<&str> {
782069860236atagen2026-10-10 12:44 UTC30
        self.headers.get(name).and_then(|v| v.to_str().ok())
782069860236atagen2026-10-10 12:44 UTC31
    }
782069860236atagen2026-10-10 12:44 UTC32
782069860236atagen2026-10-10 12:44 UTC33
    pub fn cookie(&self, name: &str) -> Option<&str> {
782069860236atagen2026-10-10 12:44 UTC34
        self.headers
782069860236atagen2026-10-10 12:44 UTC35
            .get_all(header::COOKIE)
782069860236atagen2026-10-10 12:44 UTC36
            .iter()
782069860236atagen2026-10-10 12:44 UTC37
            .filter_map(|v| v.to_str().ok())
782069860236atagen2026-10-10 12:44 UTC38
            .flat_map(|v| v.split(';'))
782069860236atagen2026-10-10 12:44 UTC39
            .filter_map(|pair| pair.trim().split_once('='))
782069860236atagen2026-10-10 12:44 UTC40
            .find(|(key, _)| *key == name)
782069860236atagen2026-10-10 12:44 UTC41
            .map(|(_, value)| value)
782069860236atagen2026-10-10 12:44 UTC42
    }
782069860236atagen2026-10-10 12:44 UTC43
782069860236atagen2026-10-10 12:44 UTC44
    pub fn param(&self, name: &str) -> &str {
782069860236atagen2026-10-10 12:44 UTC45
        self.params.get(name).map_or("", String::as_str)
782069860236atagen2026-10-10 12:44 UTC46
    }
782069860236atagen2026-10-10 12:44 UTC47
782069860236atagen2026-10-10 12:44 UTC48
    pub fn query(&self, name: &str) -> Option<&str> {
782069860236atagen2026-10-10 12:44 UTC49
        self.query.get(name).map(String::as_str)
782069860236atagen2026-10-10 12:44 UTC50
    }
782069860236atagen2026-10-10 12:44 UTC51
}
782069860236atagen2026-10-10 12:44 UTC52
782069860236atagen2026-10-10 12:44 UTC53
impl<S: Send + Sync> FromRequest<S> for Ctx {
782069860236atagen2026-10-10 12:44 UTC54
    type Rejection = Response;
782069860236atagen2026-10-10 12:44 UTC55
782069860236atagen2026-10-10 12:44 UTC56
    async fn from_request(mut request: Request, state: &S) -> Result<Self, Self::Rejection> {
782069860236atagen2026-10-10 12:44 UTC57
        let upgrade = request.extensions_mut().remove::<OnUpgrade>();
782069860236atagen2026-10-10 12:44 UTC58
        let (mut parts, body) = request.into_parts();
782069860236atagen2026-10-10 12:44 UTC59
        let params = RawPathParams::from_request_parts(&mut parts, state)
782069860236atagen2026-10-10 12:44 UTC60
            .await
782069860236atagen2026-10-10 12:44 UTC61
            .map(|raw| {
782069860236atagen2026-10-10 12:44 UTC62
                raw.iter()
782069860236atagen2026-10-10 12:44 UTC63
                    .map(|(k, v)| (k.to_owned(), v.to_owned()))
782069860236atagen2026-10-10 12:44 UTC64
                    .collect()
782069860236atagen2026-10-10 12:44 UTC65
            })
782069860236atagen2026-10-10 12:44 UTC66
            .unwrap_or_default();
782069860236atagen2026-10-10 12:44 UTC67
        let query = Query::<HashMap<String, String>>::try_from_uri(&parts.uri)
782069860236atagen2026-10-10 12:44 UTC68
            .map(|q| q.0)
782069860236atagen2026-10-10 12:44 UTC69
            .unwrap_or_default();
782069860236atagen2026-10-10 12:44 UTC70
        let body = axum::body::to_bytes(body, BODY_LIMIT).await.map_err(|_| {
782069860236atagen2026-10-10 12:44 UTC71
            Problem::new(
782069860236atagen2026-10-10 12:44 UTC72
                StatusCode::PAYLOAD_TOO_LARGE,
782069860236atagen2026-10-10 12:44 UTC73
                "body-too-large",
782069860236atagen2026-10-10 12:44 UTC74
                "The request body is larger than anything the server is prepared to receive.",
782069860236atagen2026-10-10 12:44 UTC75
            )
782069860236atagen2026-10-10 12:44 UTC76
            .into_response()
782069860236atagen2026-10-10 12:44 UTC77
        })?;
782069860236atagen2026-10-10 12:44 UTC78
        Ok(Self {
782069860236atagen2026-10-10 12:44 UTC79
            method: parts.method,
782069860236atagen2026-10-10 12:44 UTC80
            uri: parts.uri,
782069860236atagen2026-10-10 12:44 UTC81
            version: parts.version,
782069860236atagen2026-10-10 12:44 UTC82
            headers: parts.headers,
782069860236atagen2026-10-10 12:44 UTC83
            query,
782069860236atagen2026-10-10 12:44 UTC84
            params,
782069860236atagen2026-10-10 12:44 UTC85
            body,
782069860236atagen2026-10-10 12:44 UTC86
            now: Instant::now(),
782069860236atagen2026-10-10 12:44 UTC87
            upgrade,
782069860236atagen2026-10-10 12:44 UTC88
        })
782069860236atagen2026-10-10 12:44 UTC89
    }
782069860236atagen2026-10-10 12:44 UTC90
}