feat: changed options for http version of requests to upstream app servers

This commit is contained in:
Jun Kurihara 2023-08-09 02:13:04 +09:00
commit 02c333905f
No known key found for this signature in database
GPG key ID: 48ADFD173ED22B03
6 changed files with 35 additions and 23 deletions

View file

@ -1,5 +1,6 @@
# TODO List
- [Try in v0.5.1 or 0.6.0] Fix strategy for `h2c` requests on forwarded requests upstream. This needs to update forwarder definition. Also, maybe forwarder would have a cache corresponding to the following task.
- [Try in v0.6.0] **Cache option for the response with `Cache-Control: public` header directive ([#55](https://github.com/junkurihara/rust-rpxy/issues/55))**
- Improvement of path matcher
- More flexible option for rewriting path

View file

@ -78,7 +78,7 @@ load_balance = "random" # or "round_robin" or "sticky" (sticky session) or "none
upstream_options = [
"override_host",
"upgrade_insecure_requests",
"convert_https_to_11",
"force_http11_upstream",
]
######################################################################

2
quinn

@ -1 +1 @@
Subproject commit 70e14b5c26b45ee1e3d5dd64b2a184e2d6376880
Subproject commit 8076ffe94d38813ce0220af9d3438e7bfb5e8429

View file

@ -7,13 +7,13 @@ pub type Result<T> = std::result::Result<T, RpxyError>;
/// Describes things that can go wrong in the Rpxy
#[derive(Debug, Error)]
pub enum RpxyError {
#[error("Proxy build error")]
#[error("Proxy build error: {0}")]
ProxyBuild(#[from] crate::proxy::ProxyBuilderError),
#[error("Backend build error")]
#[error("Backend build error: {0}")]
BackendBuild(#[from] crate::backend::BackendBuilderError),
#[error("MessageHandler build error")]
#[error("MessageHandler build error: {0}")]
HandlerBuild(#[from] crate::handler::HttpMessageHandlerBuilderError),
#[error("Config builder error: {0}")]
@ -32,40 +32,40 @@ pub enum RpxyError {
#[error("LoadBalance Layer Error: {0}")]
LoadBalance(String),
#[error("I/O Error")]
#[error("I/O Error: {0}")]
Io(#[from] io::Error),
// #[error("Toml Deserialization Error")]
// TomlDe(#[from] toml::de::Error),
#[cfg(feature = "http3-quinn")]
#[error("Quic Connection Error")]
#[error("Quic Connection Error [quinn]: {0}")]
QuicConn(#[from] quinn::ConnectionError),
#[cfg(feature = "http3-s2n")]
#[error("Quic Connection Error [s2n-quic]")]
#[error("Quic Connection Error [s2n-quic]: {0}")]
QUicConn(#[from] s2n_quic::connection::Error),
#[cfg(feature = "http3-quinn")]
#[error("H3 Error")]
#[error("H3 Error [quinn]: {0}")]
H3(#[from] h3::Error),
#[cfg(feature = "http3-s2n")]
#[error("H3 Error [s2n-quic]")]
#[error("H3 Error [s2n-quic]: {0}")]
H3(#[from] s2n_quic_h3::h3::Error),
#[error("rustls Connection Error")]
#[error("rustls Connection Error: {0}")]
Rustls(#[from] rustls::Error),
#[error("Hyper Error")]
#[error("Hyper Error: {0}")]
Hyper(#[from] hyper::Error),
#[error("Hyper Http Error")]
#[error("Hyper Http Error: {0}")]
HyperHttp(#[from] hyper::http::Error),
#[error("Hyper Http HeaderValue Error")]
#[error("Hyper Http HeaderValue Error: {0}")]
HyperHeaderValue(#[from] hyper::header::InvalidHeaderValue),
#[error("Hyper Http HeaderName Error")]
#[error("Hyper Http HeaderName Error: {0}")]
HyperHeaderName(#[from] hyper::header::InvalidHeaderName),
#[error(transparent)]

View file

@ -4,6 +4,7 @@ use derive_builder::Builder;
use hyper::{
body::{Body, HttpBody},
client::{connect::Connect, HttpConnector},
http::Version,
Client, Request, Response,
};
use hyper_rustls::HttpsConnector;
@ -21,24 +22,28 @@ pub struct Forwarder<C, B = Body>
where
C: Connect + Clone + Sync + Send + 'static,
{
// TODO: need `h2c` or http/2-only client separately
// TODO: maybe this forwarder definition is suitable for cache handling.
inner: Client<C, B>,
inner_h2: Client<C, B>, // `h2c` or http/2-only client is defined separately
}
#[async_trait]
impl<C, B> ForwardRequest<B> for Forwarder<C, B>
where
B: HttpBody + Send + 'static,
B: HttpBody + Send + Sync + 'static,
B::Data: Send,
B::Error: Into<Box<dyn std::error::Error + Send + Sync>>,
C: Connect + Clone + Sync + Send + 'static,
{
type Error = RpxyError;
async fn request(&self, req: Request<B>) -> Result<Response<Body>, Self::Error> {
// TODO:
// TODO: Implement here a client that handles `h2c` requests
// TODO:
self.inner.request(req).await.map_err(RpxyError::Hyper)
// TODO: This 'match' condition is always evaluated at every 'request' invocation. So, it is inefficient.
// Needs to be reconsidered. Currently, this is a kind of work around.
// This possibly relates to https://github.com/hyperium/hyper/issues/2417.
match req.version() {
Version::HTTP_2 => self.inner_h2.request(req).await.map_err(RpxyError::Hyper), // handles `h2c` requests
_ => self.inner.request(req).await.map_err(RpxyError::Hyper),
}
}
}
@ -51,8 +56,14 @@ impl Forwarder<HttpsConnector<HttpConnector>, Body> {
.enable_http1()
.enable_http2()
.build();
let connector_h2 = hyper_rustls::HttpsConnectorBuilder::new()
.with_webpki_roots()
.https_or_http()
.enable_http1()
.build();
let inner = Client::builder().build::<_, Body>(connector);
Self { inner }
let inner_h2 = Client::builder().http2_only(true).build::<_, Body>(connector_h2);
Self { inner, inner_h2 }
}
}

@ -1 +1 @@
Subproject commit 8ef0a6b66a856dc9f34ce18159c617ac29154cc7
Subproject commit 1ff2cd230fdf46596fe77830966857c438a8b31a