mockforge_core/proxy/
handler.rs1use super::client::ProxyClient;
4use crate::{Error, Result};
5use axum::http::{HeaderMap, Method, Uri};
6use std::collections::HashMap;
7
8pub struct ProxyHandler {
10 pub config: super::config::ProxyConfig,
12}
13
14impl ProxyHandler {
15 pub fn new(config: super::config::ProxyConfig) -> Self {
17 Self { config }
18 }
19
20 pub async fn handle_request(
22 &self,
23 method: &str,
24 url: &str,
25 headers: &HashMap<String, String>,
26 body: Option<&[u8]>,
27 ) -> Result<ProxyResponse> {
28 if !self.config.enabled {
29 return Err(Error::generic("Proxy is not enabled"));
30 }
31
32 let reqwest_method = match method.to_uppercase().as_str() {
34 "GET" => reqwest::Method::GET,
35 "POST" => reqwest::Method::POST,
36 "PUT" => reqwest::Method::PUT,
37 "DELETE" => reqwest::Method::DELETE,
38 "HEAD" => reqwest::Method::HEAD,
39 "OPTIONS" => reqwest::Method::OPTIONS,
40 "PATCH" => reqwest::Method::PATCH,
41 _ => return Err(Error::generic(format!("Unsupported HTTP method: {}", method))),
42 };
43
44 let mut request_headers = headers.clone();
46 for (key, value) in &self.config.headers {
47 request_headers.insert(key.clone(), value.clone());
48 }
49
50 let client = ProxyClient::new();
52 let response = client.send_request(reqwest_method, url, &request_headers, body).await?;
53
54 let mut response_headers = HeaderMap::new();
56 for (key, value) in response.headers() {
57 if let Ok(header_name) = axum::http::HeaderName::try_from(key.as_str()) {
58 response_headers.insert(header_name, value.clone());
59 }
60 }
61
62 let status_code = response.status().as_u16();
63 let body_bytes = response
64 .bytes()
65 .await
66 .map_err(|e| Error::generic(format!("Failed to read response body: {}", e)))?;
67
68 Ok(ProxyResponse {
69 status_code,
70 headers: response_headers,
71 body: Some(body_bytes.to_vec()),
72 })
73 }
74
75 pub async fn proxy_request(
77 &self,
78 method: &Method,
79 uri: &Uri,
80 headers: &HeaderMap,
81 body: Option<&[u8]>,
82 ) -> Result<ProxyResponse> {
83 if !self.config.enabled {
84 return Err(Error::generic("Proxy is not enabled"));
85 }
86
87 if !self.config.should_proxy(method, uri.path()) {
89 return Err(Error::generic("Request should not be proxied"));
90 }
91
92 let upstream_url = self.config.get_upstream_url(uri.path());
94
95 let mut header_map = HashMap::new();
97 for (key, value) in headers {
98 if let Ok(value_str) = value.to_str() {
99 header_map.insert(key.to_string(), value_str.to_string());
100 }
101 }
102
103 for (key, value) in &self.config.headers {
105 header_map.insert(key.clone(), value.clone());
106 }
107
108 let reqwest_method = match *method {
110 Method::GET => reqwest::Method::GET,
111 Method::POST => reqwest::Method::POST,
112 Method::PUT => reqwest::Method::PUT,
113 Method::DELETE => reqwest::Method::DELETE,
114 Method::HEAD => reqwest::Method::HEAD,
115 Method::OPTIONS => reqwest::Method::OPTIONS,
116 Method::PATCH => reqwest::Method::PATCH,
117 _ => return Err(Error::generic(format!("Unsupported HTTP method: {}", method))),
118 };
119
120 let client = ProxyClient::new();
122 let response =
123 client.send_request(reqwest_method, &upstream_url, &header_map, body).await?;
124
125 let mut response_headers = HeaderMap::new();
127 for (key, value) in response.headers() {
128 if let Ok(header_name) = axum::http::HeaderName::try_from(key.as_str()) {
129 response_headers.insert(header_name, value.clone());
130 }
131 }
132
133 let status_code = response.status().as_u16();
134 let body_bytes = response
135 .bytes()
136 .await
137 .map_err(|e| Error::generic(format!("Failed to read response body: {}", e)))?;
138
139 Ok(ProxyResponse {
140 status_code,
141 headers: response_headers,
142 body: Some(body_bytes.to_vec()),
143 })
144 }
145}
146
147pub struct ProxyResponse {
149 pub status_code: u16,
151 pub headers: HeaderMap,
153 pub body: Option<Vec<u8>>,
155}