tuwunel_api/router/
request.rs1use std::str;
2
3use axum::{RequestExt, RequestPartsExt, extract::Path};
4use axum_extra::extract::cookie::CookieJar;
5use bytes::Bytes;
6use http::request::Parts;
7use serde::Deserialize;
8use tuwunel_core::{Result, err, smallstr::SmallString, smallvec::SmallVec};
9use tuwunel_service::Services;
10
11#[derive(Debug, Deserialize)]
12pub(super) struct QueryParams {
13 pub(super) access_token: Option<String>,
14
15 pub(super) user_id: Option<UserId>,
16
17 pub(super) device_id: Option<DeviceId>,
18
19 #[serde(rename = "org.matrix.msc3202.device_id")]
20 pub(super) msc3202_device_id: Option<DeviceId>,
21}
22
23impl QueryParams {
24 pub(super) fn device_id(&self) -> Option<&str> {
25 self.device_id
26 .as_deref()
27 .or(self.msc3202_device_id.as_deref())
28 }
29}
30
31pub(super) type UserId = SmallString<[u8; 48]>;
32pub(super) type DeviceId = SmallString<[u8; 24]>;
33
34#[derive(Debug)]
35pub(super) struct Request {
36 pub(super) cookie: CookieJar,
37 pub(super) path: Path<PathParams>,
38 pub(super) query: QueryParams,
39 pub(super) body: Bytes,
40 pub(super) parts: Parts,
41}
42
43pub(super) type PathParams = SmallVec<[PathParam; 8]>;
44pub(super) type PathParam = SmallString<[u8; 32]>;
45
46pub(super) async fn from(
47 services: &Services,
48 request: http::Request<axum::body::Body>,
49) -> Result<Request> {
50 let limited = request.with_limited_body();
51 let (mut parts, body) = limited.into_parts();
52
53 let cookie: CookieJar = parts.extract().await?;
54 let path: Path<PathParams> = parts.extract().await?;
55 let query = parts.uri.query().unwrap_or_default();
56 let query = serde_html_form::from_str(query)
57 .map_err(|e| err!(Request(Unknown("Failed to read query parameters: {e}"))))?;
58
59 let max_body_size = services.server.config.max_request_size;
60
61 let body = axum::body::to_bytes(body, max_body_size)
62 .await
63 .map_err(|e| err!(Request(TooLarge("Request body too large: {e}"))))?;
64
65 Ok(Request { cookie, path, query, body, parts })
66}