add x-forwarded-proto

This commit is contained in:
Jun Kurihara 2022-07-09 12:37:50 +09:00
commit 828d2300c0
No known key found for this signature in database
GPG key ID: 48ADFD173ED22B03
3 changed files with 96 additions and 86 deletions

View file

@ -10,8 +10,8 @@ services:
build: build:
context: ./ context: ./
environment: environment:
- LOG_LEVEL=info - LOG_LEVEL=debug
- LOG_TO_FILE - LOG_TO_FILE=false
tty: false tty: false
privileged: true privileged: true
volumes: volumes:

View file

@ -70,7 +70,7 @@ where
let request_upgraded = req.extensions_mut().remove::<hyper::upgrade::OnUpgrade>(); let request_upgraded = req.extensions_mut().remove::<hyper::upgrade::OnUpgrade>();
// Build request from destination information // Build request from destination information
let req_forwarded = if let Ok(req) = generate_request_forwarded( let req_forwarded = if let Ok(req) = self.generate_request_forwarded(
client_addr, client_addr,
req, req,
upstream_scheme_host, upstream_scheme_host,
@ -149,7 +149,7 @@ where
} }
} else { } else {
// Generate response to client // Generate response to client
if generate_response_forwarded(&mut res_backend).is_ok() { if self.generate_response_forwarded(&mut res_backend).is_ok() {
info!("{} => {}", request_log, response_log); info!("{} => {}", request_log, response_log);
Ok(res_backend) Ok(res_backend)
} else { } else {
@ -158,95 +158,99 @@ where
} }
} }
} }
}
//////////////////////////////////////////////////// ////////////////////////////////////////////////////
// Functions to generate messages // Functions to generate messages
fn generate_response_forwarded<B: core::fmt::Debug>(response: &mut Response<B>) -> Result<()> { fn generate_response_forwarded<B: core::fmt::Debug>(
let headers = response.headers_mut(); &self,
remove_hop_header(headers); response: &mut Response<B>,
remove_connection_header(headers); ) -> Result<()> {
append_header_entry( let headers = response.headers_mut();
headers, remove_hop_header(headers);
"server", remove_connection_header(headers);
&format!("{}/{}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")), append_header_entry(
)?; headers,
"server",
&format!("{}/{}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")),
)?;
Ok(()) Ok(())
} }
fn generate_request_forwarded<B: core::fmt::Debug>( fn generate_request_forwarded<B: core::fmt::Debug>(
client_addr: SocketAddr, &self,
mut req: Request<B>, client_addr: SocketAddr,
upstream_scheme_host: &Uri, mut req: Request<B>,
upgrade: &Option<String>, upstream_scheme_host: &Uri,
upstream: &Upstream, upgrade: &Option<String>,
) -> Result<Request<B>> { upstream: &Upstream,
debug!("Generate request to be forwarded"); ) -> Result<Request<B>> {
debug!("Generate request to be forwarded");
// Add te: trailer if contained in original request // Add te: trailer if contained in original request
let te_trailers = { let te_trailers = {
if let Some(te) = req.headers().get(header::TE) { if let Some(te) = req.headers().get(header::TE) {
te.to_str()?.split(',').any(|x| x.trim() == "trailers") te.to_str()?.split(',').any(|x| x.trim() == "trailers")
} else { } else {
false false
}
};
let headers = req.headers_mut();
// delete headers specified in header.connection
remove_connection_header(headers);
// delete hop headers including header.connection
remove_hop_header(headers);
// X-Forwarded-For
add_forwarding_header(headers, client_addr, self.tls_enabled)?;
// println!("{:?}", headers);
// Add te: trailer if te_trailer
if te_trailers {
headers.insert(header::TE, "trailer".parse()?);
} }
};
let headers = req.headers_mut(); // add "host" header of original server_name if not exist (default)
// delete headers specified in header.connection if req.headers().get(header::HOST).is_none() {
remove_connection_header(headers); let org_host = req.uri().host().unwrap_or("none").to_owned();
// delete hop headers including header.connection req
remove_hop_header(headers); .headers_mut()
// X-Forwarded-For .insert(header::HOST, HeaderValue::from_str(org_host.as_str())?);
add_forwarding_header(headers, client_addr)?; };
// println!("{:?}", headers);
// Add te: trailer if te_trailer // apply upstream-specific headers given in upstream_option
if te_trailers { let headers = req.headers_mut();
headers.insert(header::TE, "trailer".parse()?); apply_upstream_options_to_header(headers, client_addr, upstream_scheme_host, upstream)?;
// update uri in request
ensure!(upstream_scheme_host.authority().is_some() && upstream_scheme_host.scheme().is_some());
let new_uri = Uri::builder()
.scheme(upstream_scheme_host.scheme().unwrap().as_str())
.authority(upstream_scheme_host.authority().unwrap().as_str());
let pq = req.uri().path_and_query();
*req.uri_mut() = match pq {
None => new_uri,
Some(x) => new_uri.path_and_query(x.to_owned()),
}
.build()?;
// upgrade
if let Some(v) = upgrade {
req.headers_mut().insert("upgrade", v.parse()?);
req
.headers_mut()
.insert(header::CONNECTION, HeaderValue::from_str("upgrade")?);
}
// Change version to http/1.1 when destination scheme is http
if req.version() != Version::HTTP_11 && upstream_scheme_host.scheme() == Some(&Scheme::HTTP) {
*req.version_mut() = Version::HTTP_11;
} else if req.version() == Version::HTTP_3 {
debug!("HTTP/3 is currently unsupported for request to upstream. Use HTTP/2.");
*req.version_mut() = Version::HTTP_2;
}
Ok(req)
} }
// add "host" header of original server_name if not exist (default)
if req.headers().get(header::HOST).is_none() {
let org_host = req.uri().host().unwrap_or("none").to_owned();
req
.headers_mut()
.insert(header::HOST, HeaderValue::from_str(org_host.as_str())?);
};
// apply upstream-specific headers given in upstream_option
let headers = req.headers_mut();
apply_upstream_options_to_header(headers, client_addr, upstream_scheme_host, upstream)?;
// update uri in request
ensure!(upstream_scheme_host.authority().is_some() && upstream_scheme_host.scheme().is_some());
let new_uri = Uri::builder()
.scheme(upstream_scheme_host.scheme().unwrap().as_str())
.authority(upstream_scheme_host.authority().unwrap().as_str());
let pq = req.uri().path_and_query();
*req.uri_mut() = match pq {
None => new_uri,
Some(x) => new_uri.path_and_query(x.to_owned()),
}
.build()?;
// upgrade
if let Some(v) = upgrade {
req.headers_mut().insert("upgrade", v.parse()?);
req
.headers_mut()
.insert(header::CONNECTION, HeaderValue::from_str("upgrade")?);
}
// Change version to http/1.1 when destination scheme is http
if req.version() != Version::HTTP_11 && upstream_scheme_host.scheme() == Some(&Scheme::HTTP) {
*req.version_mut() = Version::HTTP_11;
} else if req.version() == Version::HTTP_3 {
debug!("HTTP/3 is currently unsupported for request to upstream. Use HTTP/2.");
*req.version_mut() = Version::HTTP_2;
}
Ok(req)
} }

View file

@ -49,6 +49,7 @@ pub(super) fn append_header_entry(
pub(super) fn add_forwarding_header( pub(super) fn add_forwarding_header(
headers: &mut HeaderMap, headers: &mut HeaderMap,
client_addr: SocketAddr, client_addr: SocketAddr,
tls: bool,
) -> Result<()> { ) -> Result<()> {
// default process // default process
// optional process defined by upstream_option is applied in fn apply_upstream_options // optional process defined by upstream_option is applied in fn apply_upstream_options
@ -57,6 +58,11 @@ pub(super) fn add_forwarding_header(
"x-forwarded-for", "x-forwarded-for",
&client_addr.to_canonical().ip().to_string(), &client_addr.to_canonical().ip().to_string(),
)?; )?;
append_header_entry(
headers,
"x-forwarded-proto",
if tls { "https" } else { "http" },
)?;
Ok(()) Ok(())
} }