From f0b0dbc252f644ba96a57d423a1fad2a7c048f61 Mon Sep 17 00:00:00 2001 From: Jun Kurihara Date: Tue, 28 Nov 2023 16:56:23 +0900 Subject: [PATCH] wip: manipulate response header --- rpxy-lib/src/backend/mod.rs | 2 +- rpxy-lib/src/message_handle/handler_main.rs | 16 ++-- .../handler_manipulate_messages.rs | 90 +++++++++---------- rpxy-lib/src/message_handle/http_result.rs | 3 + 4 files changed, 57 insertions(+), 54 deletions(-) diff --git a/rpxy-lib/src/backend/mod.rs b/rpxy-lib/src/backend/mod.rs index 3d3ddbf..788960d 100644 --- a/rpxy-lib/src/backend/mod.rs +++ b/rpxy-lib/src/backend/mod.rs @@ -10,4 +10,4 @@ pub(crate) use self::{ upstream::{PathManager, Upstream, UpstreamCandidates}, upstream_opts::UpstreamOption, }; -pub(crate) use backend_main::{BackendAppBuilderError, BackendAppManager}; +pub(crate) use backend_main::{BackendApp, BackendAppBuilderError, BackendAppManager}; diff --git a/rpxy-lib/src/message_handle/handler_main.rs b/rpxy-lib/src/message_handle/handler_main.rs index 5be08f1..666faa3 100644 --- a/rpxy-lib/src/message_handle/handler_main.rs +++ b/rpxy-lib/src/message_handle/handler_main.rs @@ -38,7 +38,7 @@ where U: CryptoSource + Clone, { // forwarder: Arc>, - globals: Arc, + pub(super) globals: Arc, app_manager: Arc>, } @@ -155,7 +155,7 @@ where tls_enabled, ) { Err(e) => { - error!("Failed to generate destination uri for backend application: {}", e); + error!("Failed to generate upstream request for backend application: {}", e); return Err(HttpError::FailedToGenerateUpstreamRequest(e.to_string())); } Ok(v) => v, @@ -199,12 +199,12 @@ where } if res_backend.status() != StatusCode::SWITCHING_PROTOCOLS { - // // Generate response to client - // if self.generate_response_forwarded(&mut res_backend, backend).is_err() { - // return self.return_with_error_log(StatusCode::INTERNAL_SERVER_ERROR, &mut log_data); - // } - // log_data.status_code(&res_backend.status()).output(); - // return Ok(res_backend); + // Generate response to client + if let Err(e) = self.generate_response_forwarded(&mut res_backend, backend_app) { + error!("Failed to generate downstream response for clients: {}", e); + return Err(HttpError::FailedToGenerateDownstreamResponse(e.to_string())); + } + return Ok(res_backend); } // // Handle StatusCode::SWITCHING_PROTOCOLS in response diff --git a/rpxy-lib/src/message_handle/handler_manipulate_messages.rs b/rpxy-lib/src/message_handle/handler_manipulate_messages.rs index 28a62b1..a33e58f 100644 --- a/rpxy-lib/src/message_handle/handler_manipulate_messages.rs +++ b/rpxy-lib/src/message_handle/handler_manipulate_messages.rs @@ -2,9 +2,14 @@ use super::{ handler_main::HandlerContext, utils_headers::*, utils_request::apply_upstream_options_to_request_line, HttpMessageHandler, }; -use crate::{backend::UpstreamCandidates, log::*, CryptoSource}; +use crate::{ + backend::{BackendApp, UpstreamCandidates}, + constants::RESPONSE_HEADER_SERVER, + log::*, + CryptoSource, +}; use anyhow::{anyhow, ensure, Result}; -use http::{header, uri::Scheme, HeaderValue, Request, Uri, Version}; +use http::{header, uri::Scheme, HeaderValue, Request, Response, Uri, Version}; use std::net::SocketAddr; impl HttpMessageHandler @@ -15,51 +20,46 @@ where // Functions to generate messages //////////////////////////////////////////////////// - // /// Manipulate a response message sent from a backend application to forward downstream to a client. - // fn generate_response_forwarded(&self, response: &mut Response, chosen_backend: &Backend) -> Result<()> { - // where - // B: core::fmt::Debug, - // { - // let headers = response.headers_mut(); - // remove_connection_header(headers); - // remove_hop_header(headers); - // add_header_entry_overwrite_if_exist(headers, "server", RESPONSE_HEADER_SERVER)?; + /// Manipulate a response message sent from a backend application to forward downstream to a client. + pub(super) fn generate_response_forwarded( + &self, + response: &mut Response, + backend_app: &BackendApp, + ) -> Result<()> { + let headers = response.headers_mut(); + remove_connection_header(headers); + remove_hop_header(headers); + add_header_entry_overwrite_if_exist(headers, "server", RESPONSE_HEADER_SERVER)?; - // #[cfg(any(feature = "http3-quinn", feature = "http3-s2n"))] - // { - // // Manipulate ALT_SVC allowing h3 in response message only when mutual TLS is not enabled - // // TODO: This is a workaround for avoiding a client authentication in HTTP/3 - // if self.globals.proxy_config.http3 - // && chosen_backend - // .crypto_source - // .as_ref() - // .is_some_and(|v| !v.is_mutual_tls()) - // { - // if let Some(port) = self.globals.proxy_config.https_port { - // add_header_entry_overwrite_if_exist( - // headers, - // header::ALT_SVC.as_str(), - // format!( - // "h3=\":{}\"; ma={}, h3-29=\":{}\"; ma={}", - // port, self.globals.proxy_config.h3_alt_svc_max_age, port, self.globals.proxy_config.h3_alt_svc_max_age - // ), - // )?; - // } - // } else { - // // remove alt-svc to disallow requests via http3 - // headers.remove(header::ALT_SVC.as_str()); - // } - // } - // #[cfg(not(any(feature = "http3-quinn", feature = "http3-s2n")))] - // { - // if let Some(port) = self.globals.proxy_config.https_port { - // headers.remove(header::ALT_SVC.as_str()); - // } - // } + #[cfg(any(feature = "http3-quinn", feature = "http3-s2n"))] + { + // Manipulate ALT_SVC allowing h3 in response message only when mutual TLS is not enabled + // TODO: This is a workaround for avoiding a client authentication in HTTP/3 + if self.globals.proxy_config.http3 && backend_app.crypto_source.as_ref().is_some_and(|v| !v.is_mutual_tls()) { + if let Some(port) = self.globals.proxy_config.https_port { + add_header_entry_overwrite_if_exist( + headers, + header::ALT_SVC.as_str(), + format!( + "h3=\":{}\"; ma={}, h3-29=\":{}\"; ma={}", + port, self.globals.proxy_config.h3_alt_svc_max_age, port, self.globals.proxy_config.h3_alt_svc_max_age + ), + )?; + } + } else { + // remove alt-svc to disallow requests via http3 + headers.remove(header::ALT_SVC.as_str()); + } + } + #[cfg(not(any(feature = "http3-quinn", feature = "http3-s2n")))] + { + if self.globals.proxy_config.https_port.is_some() { + headers.remove(header::ALT_SVC.as_str()); + } + } - // Ok(()) - // todo!() - // } + Ok(()) + } #[allow(clippy::too_many_arguments)] /// Manipulate a request message sent from a client to forward upstream to a backend application diff --git a/rpxy-lib/src/message_handle/http_result.rs b/rpxy-lib/src/message_handle/http_result.rs index 3f9df23..07a0034 100644 --- a/rpxy-lib/src/message_handle/http_result.rs +++ b/rpxy-lib/src/message_handle/http_result.rs @@ -25,6 +25,8 @@ pub enum HttpError { #[error("Failed to add set-cookie header in response")] FailedToAddSetCookeInResponse, + #[error("Failed to generated downstream response: {0}")] + FailedToGenerateDownstreamResponse(String), #[error(transparent)] Other(#[from] anyhow::Error), @@ -41,6 +43,7 @@ impl From for StatusCode { HttpError::NoUpstreamCandidates => StatusCode::NOT_FOUND, HttpError::FailedToGenerateUpstreamRequest(_) => StatusCode::INTERNAL_SERVER_ERROR, HttpError::FailedToAddSetCookeInResponse => StatusCode::INTERNAL_SERVER_ERROR, + HttpError::FailedToGenerateDownstreamResponse(_) => StatusCode::INTERNAL_SERVER_ERROR, _ => StatusCode::INTERNAL_SERVER_ERROR, } }