#![cfg_attr(docsrs, feature(doc_cfg))]
mod error;
pub use error::Error;
#[cfg(any(feature = "http1", feature = "http2"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "http1", feature = "http2"))))]
pub mod client;
pub mod rewrite;
pub use rewrite::*;
mod future;
pub use future::RevProxyFuture;
#[cfg(any(feature = "http1", feature = "http2"))]
mod oneshot;
#[cfg(any(feature = "http1", feature = "http2"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "http1", feature = "http2"))))]
pub use oneshot::OneshotService;
#[cfg(any(feature = "http1", feature = "http2"))]
mod reused;
#[cfg(all(
any(feature = "http1", feature = "http2"),
any(feature = "https", feature = "nativetls")
))]
#[cfg_attr(
docsrs,
doc(cfg(all(
any(feature = "http1", feature = "http2"),
any(feature = "https", feature = "nativetls")
)))
)]
pub use reused::builder_https;
#[cfg(all(any(feature = "http1", feature = "http2"), feature = "nativetls"))]
#[cfg_attr(
docsrs,
doc(cfg(all(any(feature = "http1", feature = "http2"), feature = "nativetls")))
)]
pub use reused::builder_nativetls;
#[cfg(all(any(feature = "http1", feature = "http2"), feature = "__rustls"))]
#[cfg_attr(
docsrs,
doc(cfg(all(any(feature = "http1", feature = "http2"), feature = "rustls")))
)]
pub use reused::builder_rustls;
#[cfg(any(feature = "http1", feature = "http2"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "http1", feature = "http2"))))]
pub use reused::Builder as ReusedServiceBuilder;
#[cfg(any(feature = "http1", feature = "http2"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "http1", feature = "http2"))))]
pub use reused::ReusedService;
#[cfg(any(feature = "http1", feature = "http2"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "http1", feature = "http2"))))]
pub use reused::{builder, builder_http};
#[cfg(test)]
mod test_helper {
use super::{Error, RevProxyFuture};
use std::convert::Infallible;
use http::StatusCode;
use http::{Request, Response};
use hyper::body::Body;
use tower_service::Service;
use mockito::Matcher;
async fn call<S, B>(
svc: &mut S,
req: (&str, &str, Option<&str>, B),
expected: (StatusCode, &str),
) where
S: Service<
Request<String>,
Response = Result<Response<Body>, Error>,
Error = Infallible,
Future = RevProxyFuture,
>,
B: Into<String>,
{
let req = if let Some(content_type) = req.2 {
Request::builder()
.method(req.0)
.uri(format!("https://test.com{}", req.1))
.header("Content-Type", content_type)
.body(req.3.into())
} else {
Request::builder()
.method(req.0)
.uri(format!("https://test.com{}", req.1))
.uri(format!("https://test.com{}", req.1))
.body(req.3.into())
}
.unwrap();
let res = svc.call(req).await.unwrap();
assert!(res.is_ok());
let res = res.unwrap();
assert_eq!(res.status(), expected.0);
let res = hyper::body::to_bytes(res.into_body()).await;
assert!(res.is_ok());
assert_eq!(res.unwrap(), expected.1);
}
pub async fn match_path<S>(svc: &mut S)
where
S: Service<
Request<String>,
Response = Result<Response<Body>, Error>,
Error = Infallible,
Future = RevProxyFuture,
>,
{
let _mk = mockito::mock("GET", "/goo/bar/goo/baz/goo")
.with_body("ok")
.create();
call(
svc,
("GET", "/foo/bar/foo/baz/foo", None, ""),
(StatusCode::OK, "ok"),
)
.await;
call(
svc,
("GET", "/foo/bar/foo/baz", None, ""),
(StatusCode::NOT_IMPLEMENTED, ""),
)
.await;
}
pub async fn match_query<S>(svc: &mut S)
where
S: Service<
Request<String>,
Response = Result<Response<Body>, Error>,
Error = Infallible,
Future = RevProxyFuture,
>,
{
let _mk = mockito::mock("GET", "/goo")
.match_query(Matcher::UrlEncoded("greeting".into(), "good day".into()))
.with_body("ok")
.create();
call(
svc,
("GET", "/foo?greeting=good%20day", None, ""),
(StatusCode::OK, "ok"),
)
.await;
call(
svc,
("GET", "/foo", None, ""),
(StatusCode::NOT_IMPLEMENTED, ""),
)
.await;
}
pub async fn match_post<S>(svc: &mut S)
where
S: Service<
Request<String>,
Response = Result<Response<Body>, Error>,
Error = Infallible,
Future = RevProxyFuture,
>,
{
let _mk = mockito::mock("POST", "/goo")
.match_body("test")
.with_body("ok")
.create();
call(svc, ("POST", "/foo", None, "test"), (StatusCode::OK, "ok")).await;
call(
svc,
("PUT", "/foo", None, "test"),
(StatusCode::NOT_IMPLEMENTED, ""),
)
.await;
call(
svc,
("POST", "/foo", None, "tests"),
(StatusCode::NOT_IMPLEMENTED, ""),
)
.await;
}
pub async fn match_header<S>(svc: &mut S)
where
S: Service<
Request<String>,
Response = Result<Response<Body>, Error>,
Error = Infallible,
Future = RevProxyFuture,
>,
{
let _mk = mockito::mock("POST", "/goo")
.match_header("content-type", "application/json")
.match_body(r#"{"key":"value"}"#)
.with_body("ok")
.create();
call(
svc,
(
"POST",
"/foo",
Some("application/json"),
r#"{"key":"value"}"#,
),
(StatusCode::OK, "ok"),
)
.await;
call(
svc,
("POST", "/foo", None, r#"{"key":"value"}"#),
(StatusCode::NOT_IMPLEMENTED, ""),
)
.await;
call(
svc,
(
"POST",
"/foo",
Some("application/json"),
r#"{"key":"values"}"#,
),
(StatusCode::NOT_IMPLEMENTED, ""),
)
.await;
}
}