this repo has no description
1use crate::state::AppState; 2use axum::{ 3 body::Bytes, 4 extract::{Path, Query, State}, 5 http::{HeaderMap, Method, StatusCode}, 6 response::{IntoResponse, Response}, 7}; 8use crate::api::proxy_client::proxy_client; 9use std::collections::HashMap; 10use tracing::{error, info}; 11 12pub async fn proxy_handler( 13 State(state): State<AppState>, 14 Path(method): Path<String>, 15 method_verb: Method, 16 headers: HeaderMap, 17 Query(params): Query<HashMap<String, String>>, 18 body: Bytes, 19) -> Response { 20 let proxy_header = headers 21 .get("atproto-proxy") 22 .and_then(|h| h.to_str().ok()) 23 .map(|s| s.to_string()); 24 let appview_url = match &proxy_header { 25 Some(url) => url.clone(), 26 None => match std::env::var("APPVIEW_URL") { 27 Ok(url) => url, 28 Err(_) => { 29 return (StatusCode::BAD_GATEWAY, "No upstream AppView configured").into_response(); 30 } 31 }, 32 }; 33 let target_url = format!("{}/xrpc/{}", appview_url, method); 34 info!("Proxying {} request to {}", method_verb, target_url); 35 let client = proxy_client(); 36 let mut request_builder = client.request(method_verb, &target_url).query(&params); 37 let mut auth_header_val = headers.get("Authorization").map(|h| h.clone()); 38 if let Some(aud) = &proxy_header { 39 if let Some(token) = crate::auth::extract_bearer_token_from_header( 40 headers.get("Authorization").and_then(|h| h.to_str().ok()) 41 ) { 42 if let Ok(auth_user) = crate::auth::validate_bearer_token(&state.db, &token).await { 43 if let Some(key_bytes) = auth_user.key_bytes { 44 if let Ok(new_token) = 45 crate::auth::create_service_token(&auth_user.did, aud, &method, &key_bytes) 46 { 47 if let Ok(val) = 48 axum::http::HeaderValue::from_str(&format!("Bearer {}", new_token)) 49 { 50 auth_header_val = Some(val); 51 } 52 } 53 } 54 } 55 } 56 } 57 if let Some(val) = auth_header_val { 58 request_builder = request_builder.header("Authorization", val); 59 } 60 for (key, value) in headers.iter() { 61 if key != "host" && key != "content-length" && key != "authorization" { 62 request_builder = request_builder.header(key, value); 63 } 64 } 65 request_builder = request_builder.body(body); 66 match request_builder.send().await { 67 Ok(resp) => { 68 let status = resp.status(); 69 let headers = resp.headers().clone(); 70 let body = match resp.bytes().await { 71 Ok(b) => b, 72 Err(e) => { 73 error!("Error reading proxy response body: {:?}", e); 74 return (StatusCode::BAD_GATEWAY, "Error reading upstream response") 75 .into_response(); 76 } 77 }; 78 let mut response_builder = Response::builder().status(status); 79 for (key, value) in headers.iter() { 80 response_builder = response_builder.header(key, value); 81 } 82 match response_builder.body(axum::body::Body::from(body)) { 83 Ok(r) => r, 84 Err(e) => { 85 error!("Error building proxy response: {:?}", e); 86 (StatusCode::INTERNAL_SERVER_ERROR, "Internal Server Error").into_response() 87 } 88 } 89 } 90 Err(e) => { 91 error!("Error sending proxy request: {:?}", e); 92 if e.is_timeout() { 93 (StatusCode::GATEWAY_TIMEOUT, "Upstream Timeout").into_response() 94 } else { 95 (StatusCode::BAD_GATEWAY, "Upstream Error").into_response() 96 } 97 } 98 } 99}