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, trace};
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
46#[tracing::instrument(
47 name = "parse",
48 level = "trace",
49 skip(services),
50 err(level = "debug")
51 ret(level = "trace"),
52)]
53pub(super) async fn from(
54 services: &Services,
55 request: http::Request<axum::body::Body>,
56) -> Result<Request> {
57 let limited = request.with_limited_body();
58 let (mut parts, body) = limited.into_parts();
59 trace!(?parts, ?body);
60
61 let cookie: CookieJar = parts.extract().await?;
62 trace!(?cookie);
63
64 let path: Path<PathParams> = parts.extract().await?;
65 trace!(?path);
66
67 let query = parts.uri.query().unwrap_or_default();
68 let query = serde_html_form::from_str(query)
69 .map_err(|e| err!(Request(Unknown("Failed to read query parameters: {e}"))))?;
70
71 let max_body_size = services.server.config.max_request_size;
72 let body = axum::body::to_bytes(body, max_body_size)
73 .await
74 .map_err(|e| err!(Request(TooLarge("Request body too large: {e}"))))?;
75
76 Ok(Request { cookie, path, query, body, parts })
77}