parse_rust_server/
body_credentials.rs1use axum::body::{to_bytes, Body};
20use axum::extract::Request;
21use axum::middleware::Next;
22use axum::response::Response;
23use serde_json::Value as Json;
24
25use crate::auth::headers;
26
27#[derive(Debug, Clone)]
31pub struct MethodOverride(pub http::Method);
32
33const CREDENTIALS: [(&str, &str); 6] = [
35 ("_ApplicationId", headers::APP_ID),
36 ("_JavaScriptKey", headers::JAVASCRIPT_KEY),
37 ("_MasterKey", headers::MASTER_KEY),
38 ("_MaintenanceKey", headers::MAINTENANCE_KEY),
39 ("_SessionToken", headers::SESSION_TOKEN),
40 ("_InstallationId", headers::INSTALLATION_ID),
41];
42
43const DISCARDED: [&str; 4] = [
45 "_ClientVersion",
46 "_RevocableSession",
47 "_noBody",
48 "_ContentType",
49];
50
51const MAX_BODY: usize = 20 * 1024 * 1024;
53
54pub async fn extract(request: Request, next: Next) -> Response {
55 let (mut parts, body) = request.into_parts();
56
57 let bytes = match to_bytes(body, MAX_BODY).await {
58 Ok(b) => b,
59 Err(_) => return next.run(Request::from_parts(parts, Body::empty())).await,
60 };
61
62 let Ok(Json::Object(mut map)) = serde_json::from_slice::<Json>(&bytes) else {
64 return next
65 .run(Request::from_parts(parts, Body::from(bytes)))
66 .await;
67 };
68
69 for (body_key, header_name) in CREDENTIALS {
72 let Some(Json::String(value)) = map.shift_remove(body_key) else {
73 continue;
74 };
75 if parts.headers.contains_key(header_name) {
76 continue;
77 }
78 if let (Ok(name), Ok(val)) = (
79 http::HeaderName::from_bytes(header_name.as_bytes()),
80 http::HeaderValue::from_str(&value),
81 ) {
82 parts.headers.insert(name, val);
83 }
84 }
85 for key in DISCARDED {
86 map.shift_remove(key);
87 }
88
89 let overridden = match map.shift_remove("_method") {
98 Some(Json::String(m)) => m.parse::<http::Method>().ok(),
99 _ => None,
100 };
101 if let Some(method) = overridden.clone() {
102 parts.extensions.insert(MethodOverride(method));
103 }
104
105 let effective = overridden.clone().unwrap_or_else(|| parts.method.clone());
108 if effective == http::Method::GET || effective == http::Method::DELETE {
109 let mut pairs: Vec<(String, String)> = Vec::new();
110 for (k, v) in &map {
111 let value = match v {
112 Json::String(s) => s.clone(),
113 other => other.to_string(),
114 };
115 pairs.push((k.clone(), value));
116 }
117 if !pairs.is_empty() {
118 let existing = parts.uri.query().unwrap_or("").to_string();
119 let mut serializer = form_urlencoded::Serializer::new(String::new());
120 for (k, v) in pairs {
121 serializer.append_pair(&k, &v);
122 }
123 let merged = if existing.is_empty() {
124 serializer.finish()
125 } else {
126 format!("{existing}&{}", serializer.finish())
127 };
128 let path = parts.uri.path().to_string();
129 if let Ok(uri) = format!("{path}?{merged}").parse::<http::Uri>() {
130 parts.uri = uri;
131 }
132 }
133 let trace = std::env::var("PARSE_RUST_TRACE").is_ok();
135 let (m, u) = (parts.method.clone(), parts.uri.clone());
136 let res = next.run(Request::from_parts(parts, Body::empty())).await;
137 if trace {
138 eprintln!("[trace] {m} {u} -> {}", res.status());
139 }
140 return res;
141 }
142
143 parts.headers.insert(
147 http::header::CONTENT_TYPE,
148 http::HeaderValue::from_static("application/json"),
149 );
150
151 let body = match serde_json::to_vec(&Json::Object(map)) {
152 Ok(v) => Body::from(v),
153 Err(_) => Body::from(bytes),
154 };
155 let trace = std::env::var("PARSE_RUST_TRACE").is_ok();
156 let (m, u) = (parts.method.clone(), parts.uri.clone());
157 let res = next.run(Request::from_parts(parts, body)).await;
158 if trace {
159 eprintln!("[trace] {m} {u} -> {}", res.status());
160 }
161 res
162}