97 lines
3.0 KiB
Rust
97 lines
3.0 KiB
Rust
use core::{
|
|
future::Future,
|
|
pin::Pin,
|
|
task::{Context, Poll},
|
|
};
|
|
use std::path::PathBuf;
|
|
|
|
use hyper::{
|
|
client::{Client, HttpConnector},
|
|
http::{
|
|
uri::{Authority, Parts, Scheme},
|
|
Request, Response,
|
|
},
|
|
service::Service,
|
|
Body, Uri,
|
|
};
|
|
use serde::Deserialize;
|
|
|
|
/// Represents a route that a ProxyServer can send requests to. This struct also implements the
|
|
/// `hyper::service::Service` trait, meaning it can be used as a service for a hyper server to
|
|
/// consume. This is used in combination with `crate::proxy::ProxyServer` to create a modular proxy
|
|
/// server.
|
|
///
|
|
/// # Fields
|
|
///
|
|
/// * `route` - Which prefix of route should be matched. This route prefix will then be replaced by
|
|
/// the provided prefix when routing.
|
|
/// * `host` - The host that request should be proxied to. This variable should also include the
|
|
/// port number if necessary.
|
|
/// * `prefix` - The prefix with which to replace the routed prefix. In practice, this means that
|
|
/// the proxy can use a completely different prefix for routes, e.g. `/api/posts` on the proxy site
|
|
/// & `/v1/api/posts` on the proxied server site.
|
|
/// * `timeout` - How long the proxy should wait before aborting the request.
|
|
#[derive(Deserialize)]
|
|
pub struct Route
|
|
{
|
|
route: PathBuf,
|
|
host: String,
|
|
prefix: PathBuf,
|
|
}
|
|
|
|
impl Route
|
|
{
|
|
pub fn new(route: PathBuf, host: String, prefix: PathBuf) -> Route
|
|
{
|
|
Route {
|
|
route,
|
|
host,
|
|
prefix,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Service<Request<Body>> for Route
|
|
{
|
|
type Response = Response<Body>;
|
|
type Error = hyper::http::Error;
|
|
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>>>>;
|
|
|
|
/// This function lets hyper know when the service is ready to process requests.
|
|
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>>
|
|
{
|
|
Poll::Ready(Ok(()))
|
|
}
|
|
|
|
/// Processes incoming requests by proxying them to other hosts.
|
|
fn call(&mut self, req: Request<Body>) -> Self::Future
|
|
{
|
|
let fut = async {
|
|
// Convert the request's uri to match the redirected one
|
|
let req_parts = req.uri().clone().into_parts();
|
|
let mut parts = Parts::default();
|
|
parts.scheme = req_parts.scheme.or_else(|| Some(Scheme::HTTP));
|
|
parts.authority = Some(Authority::from_static("localhost:5000"));
|
|
parts.path_and_query = req_parts.path_and_query;
|
|
|
|
let new_uri = Uri::from_parts(parts).unwrap();
|
|
*req.uri_mut() = new_uri;
|
|
|
|
// Create a new client that can send the requests
|
|
let client: Client<HttpConnector, Body> = Client::builder().build_http();
|
|
|
|
// match client.request
|
|
// NOTE: when should we return an Err here?
|
|
match client.request(req).await {
|
|
Ok(res) => Ok(res),
|
|
Err(_) => Ok(hyper::http::response::Builder::new()
|
|
.status(500)
|
|
.body(Body::empty())
|
|
.unwrap()),
|
|
}
|
|
};
|
|
|
|
Box::pin(fut)
|
|
}
|
|
}
|