Skip to content

Commit 947b775

Browse files
authored
🐛 replace reponse header location with request origin
1 parent 020b69f commit 947b775

2 files changed

Lines changed: 81 additions & 4 deletions

File tree

Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/registry.rs

Lines changed: 79 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,61 @@
11
use anyhow::Result;
22
use axum::{
33
body::Body,
4-
http::{HeaderMap, HeaderValue, Method, Request, Response, StatusCode},
4+
http::{uri, HeaderMap, HeaderValue, Method, Request, Response, StatusCode},
55
};
66
use reqwest::Client;
77
use std::sync::Arc;
88
use tracing::{debug, error, info};
99

1010
use crate::{models::ProxyContext, AppState};
1111

12+
fn infer_origin(headers: &HeaderMap) -> Result<String> {
13+
let mut scheme = "http".to_string();
14+
let mut host = "".to_string();
15+
16+
if let Some(uri_str) = headers.get("x-forwarded-uri").and_then(|v| v.to_str().ok()) {
17+
if let Ok(u) = uri::Uri::try_from(uri_str) {
18+
if let Some(s) = u.scheme_str() {
19+
scheme = s.to_string();
20+
}
21+
if let Some(h) = u.host() {
22+
host = h.to_string();
23+
}
24+
}
25+
}
26+
27+
if let Some(origin) = headers
28+
.get("x-forwarded-origin")
29+
.and_then(|v| v.to_str().ok())
30+
{
31+
return Ok(origin.to_string());
32+
}
33+
34+
if let Some(h) = headers
35+
.get("x-forwarded-host")
36+
.and_then(|v| v.to_str().ok())
37+
{
38+
host = h.to_string();
39+
}
40+
41+
if let Some(s) = headers
42+
.get("x-forwarded-proto")
43+
.and_then(|v| v.to_str().ok())
44+
{
45+
scheme = s.to_string();
46+
}
47+
48+
if let Some(h) = headers.get("host").and_then(|v| v.to_str().ok()) {
49+
host = h.to_string();
50+
}
51+
52+
if !host.is_empty() {
53+
return Ok(format!("{}://{}", scheme, host));
54+
}
55+
56+
Err(anyhow::anyhow!("Cannot extract host from request headers"))
57+
}
58+
1259
pub async fn proxy_request(
1360
state: Arc<AppState>,
1461
request: Request<Body>,
@@ -28,7 +75,6 @@ pub async fn proxy_request(
2875

2976
// Extract user context from request extensions (clone it before consuming request)
3077
let proxy_context = request.extensions().get::<ProxyContext>().cloned();
31-
3278
info!(
3379
method = %method,
3480
path = %path,
@@ -121,13 +167,44 @@ pub async fn proxy_request(
121167
continue;
122168
}
123169

170+
// Replace header location with the original request origin
171+
if name_str.eq_ignore_ascii_case("location") {
172+
let loc = value.to_str().map_err(|e| {
173+
error!("Invalid location header value: {}", e);
174+
StatusCode::BAD_GATEWAY
175+
})?;
176+
let origin = infer_origin(&headers).map_err(|e| {
177+
error!("Failed to infer origin from request: {}", e);
178+
StatusCode::BAD_REQUEST
179+
})?;
180+
let new_location = match uri::Uri::try_from(loc) {
181+
Ok(u) => {
182+
let path_and_query = u.path_and_query().map_or("", |pq| pq.as_str());
183+
format!("{}{}", origin, path_and_query)
184+
}
185+
Err(_) => {
186+
// If location is a relative path, just prepend the origin
187+
format!("{}{}", origin, loc)
188+
}
189+
};
190+
if let Ok(new_value) = HeaderValue::from_str(&new_location) {
191+
response_headers.insert(name.clone(), new_value);
192+
}
193+
continue;
194+
}
195+
124196
if let Ok(header_value) = HeaderValue::from_bytes(value_bytes) {
125197
if let Ok(header_name) = name_str.parse::<axum::http::HeaderName>() {
126198
response_headers.insert(header_name, header_value);
127199
}
128200
}
129201
}
130202

203+
debug!(
204+
headers = ?response_headers,
205+
"Response headers processed"
206+
);
207+
131208
let body_bytes = match response.bytes().await {
132209
Ok(bytes) => bytes,
133210
Err(e) => {

0 commit comments

Comments
 (0)