Skip to content

Commit

Permalink
Forward host and path rewrites
Browse files Browse the repository at this point in the history
Signed-off-by: Eloi DEMOLIS <[email protected]>
  • Loading branch information
Wonshtrum committed Jan 9, 2025
1 parent 33513c4 commit 0471a4c
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 25 deletions.
4 changes: 3 additions & 1 deletion e2e/src/tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -984,7 +984,9 @@ fn try_https_redirect() -> State {
client.connect();
client.send();
let answer = client.receive();
let expected_answer = format!("{answer_301_prefix}https://example.com/redirected?true\r\nContent-Length: 0\r\n\r\n");
let expected_answer = format!(
"{answer_301_prefix}https://example.com/redirected?true\r\nContent-Length: 0\r\n\r\n"
);
assert_eq!(answer, Some(expected_answer));

State::Success
Expand Down
19 changes: 17 additions & 2 deletions lib/src/protocol/kawa_h1/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use rusty_ulid::Ulid;
use crate::{
pool::Checkout,
protocol::http::{parser::compare_no_case, GenericHttpStream, Method},
Protocol,
Protocol, RetrieveClusterError,
};

use sozu_command_lib::logging::LogContext;
Expand All @@ -24,8 +24,10 @@ pub struct HttpContext {
pub keep_alive_frontend: bool,
/// the value of the sticky session cookie in the request
pub sticky_session_found: Option<String>,
/// position of the last authentication header, only valid until prepare is called
/// hashed value of the last authentication header
pub authentication_found: Option<u64>,
/// position of the last header (the "Sozu-Id"), only valid until prepare is called
pub last_header: Option<usize>,
// ---------- Status Line
/// the value of the method in the request line
pub method: Option<Method>,
Expand Down Expand Up @@ -284,6 +286,7 @@ impl HttpContext {
}));
}

self.last_header = Some(request.blocks.len());
// Create a custom "Sozu-Id" header
request.push_block(kawa::Block::Header(kawa::Pair {
key: kawa::Store::Static(b"Sozu-Id"),
Expand Down Expand Up @@ -376,4 +379,16 @@ impl HttpContext {
backend_id: self.backend_id.as_deref(),
}
}

// -> host, path, method
pub fn extract_route(&self) -> Result<(&str, &str, &Method), RetrieveClusterError> {
let given_method = self.method.as_ref().ok_or(RetrieveClusterError::NoMethod)?;
let given_authority = self
.authority
.as_deref()
.ok_or(RetrieveClusterError::NoHost)?;
let given_path = self.path.as_deref().ok_or(RetrieveClusterError::NoPath)?;

Ok((given_authority, given_path, given_method))
}
}
50 changes: 28 additions & 22 deletions lib/src/protocol/kawa_h1/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ impl<Front: SocketHandler, L: ListenerHandler + L7ListenerHandler> Http<Front, L
sticky_session: None,
sticky_session_found: None,
authentication_found: None,
last_header: None,

method: None,
authority: None,
Expand Down Expand Up @@ -1192,27 +1193,6 @@ impl<Front: SocketHandler, L: ListenerHandler + L7ListenerHandler> Http<Front, L
true
}

// -> host, path, method
pub fn extract_route(&self) -> Result<(&str, &str, &Method), RetrieveClusterError> {
let given_method = self
.context
.method
.as_ref()
.ok_or(RetrieveClusterError::NoMethod)?;
let given_authority = self
.context
.authority
.as_deref()
.ok_or(RetrieveClusterError::NoHost)?;
let given_path = self
.context
.path
.as_deref()
.ok_or(RetrieveClusterError::NoPath)?;

Ok((given_authority, given_path, given_method))
}

pub fn get_route(&self) -> String {
if let Some(method) = &self.context.method {
if let Some(authority) = &self.context.authority {
Expand All @@ -1230,7 +1210,7 @@ impl<Front: SocketHandler, L: ListenerHandler + L7ListenerHandler> Http<Front, L
&mut self,
proxy: Rc<RefCell<dyn L7Proxy>>,
) -> Result<String, RetrieveClusterError> {
let (host, path, method) = match self.extract_route() {
let (host, path, method) = match self.context.extract_route() {
Ok(tuple) => tuple,
Err(cluster_error) => {
self.set_answer(DefaultAnswer::Answer400 {
Expand Down Expand Up @@ -1306,6 +1286,28 @@ impl<Front: SocketHandler, L: ListenerHandler + L7ListenerHandler> Http<Front, L
);
}

match &mut self.request_stream.detached.status_line {
kawa::StatusLine::Request { authority, uri, .. } => {
let buf = self.request_stream.storage.mut_buffer();
if let Some(new) = &rewritten_host {
authority.modify(buf, new.as_bytes());
if let Some(position) = self.context.last_header {
self.request_stream.blocks.insert(
position,
kawa::Block::Header(kawa::Pair {
key: kawa::Store::Static(b"X-Forwarded-Host"),
val: kawa::Store::from_slice(host.as_bytes()),
}),
);
}
}
if let Some(new) = &rewritten_path {
uri.modify(buf, new.as_bytes());
}
}
_ => unreachable!(),
}

let host = rewritten_host.as_deref().unwrap_or(host);
let path = rewritten_path.as_deref().unwrap_or(path);
let port = rewritten_port.map_or_else(
Expand Down Expand Up @@ -1459,6 +1461,10 @@ impl<Front: SocketHandler, L: ListenerHandler + L7ListenerHandler> Http<Front, L
) -> Result<BackendConnectAction, BackendConnectionError> {
self.check_circuit_breaker()?;

// TODO: this is called on every connect attempt, not just the first
// cluster_id is determined from the triplet (method, authority, path)
// which doesn't ever change for a request
// this is wasteful and potentially dangerous with the rewrite logic
let cluster_id = self
.cluster_id_from_request(proxy.clone())
.map_err(BackendConnectionError::RetrieveClusterError)?;
Expand Down

0 comments on commit 0471a4c

Please sign in to comment.