1 unstable release
0.2.0 | May 12, 2024 |
---|
#718 in HTTP server
96 downloads per month
24KB
216 lines
Upstream Module for Pingora
This crate helps configure Pingora’s upstream functionality. It is most useful in combination
with the virtual-hosts-module
crate that allows applying multiple upstream configurations
conditionally.
Currently only one configuration option is provided: upstream
(--upstream
as command line
option). The value should be a URL like http://127.0.0.1:8081
or https://example.com
.
Supported URL schemes are http://
and https://
. Other than the scheme, only host name and
port are considered. Other parts of the URL are ignored if present.
The UpstreamHandler
type has to be called in both request_filter
and upstream_peer
Pingora Proxy phases. The former selects an upstream peer and modifies the request by adding
the appropriate Host
header. The latter retrieves the previously selected upstream peer.
use async_trait::async_trait;
use upstream_module::UpstreamHandler;
use module_utils::RequestFilter;
use pingora_core::Error;
use pingora_core::upstreams::peer::HttpPeer;
use pingora_proxy::{ProxyHttp, Session};
pub struct MyServer {
upstream_handler: UpstreamHandler,
}
#[async_trait]
impl ProxyHttp for MyServer {
type CTX = <UpstreamHandler as RequestFilter>::CTX;
fn new_ctx(&self) -> Self::CTX {
UpstreamHandler::new_ctx()
}
async fn request_filter(
&self,
session: &mut Session,
ctx: &mut Self::CTX,
) -> Result<bool, Box<Error>> {
// Select upstream peer according to configuration. This could be called based on some
// conditions.
self.upstream_handler.handle(session, ctx).await
}
async fn upstream_peer(
&self,
session: &mut Session,
ctx: &mut Self::CTX,
) -> Result<Box<HttpPeer>, Box<Error>> {
// Return previously selected peer if any
UpstreamHandler::upstream_peer(session, ctx).await
}
}
To create a handler, you will typically read its configuration from a configuration file, optionally combined with command line options. The following code will extend Pingora's usual configuration file and command line options accordingly.
use upstream_module::{UpstreamConf, UpstreamHandler, UpstreamOpt};
use module_utils::{merge_conf, merge_opt, FromYaml};
use pingora_core::server::Server;
use pingora_core::server::configuration::{Opt as ServerOpt, ServerConf};
use structopt::StructOpt;
#[merge_opt]
struct Opt {
server: ServerOpt,
upstream: UpstreamOpt,
}
#[merge_conf]
struct Conf {
server: ServerConf,
upstream: UpstreamConf,
}
let opt = Opt::from_args();
let mut conf = opt
.server
.conf
.as_ref()
.and_then(|path| Conf::load_from_yaml(path).ok())
.unwrap_or_else(Conf::default);
conf.upstream.merge_with_opt(opt.upstream);
let mut server = Server::new_with_opt_and_conf(opt.server, conf.server);
server.bootstrap();
let upstream_handler: UpstreamHandler = conf.upstream.try_into().unwrap();
For complete and more realistic code see virtual-hosts
example in the repository.
Dependencies
~37–52MB
~1M SLoC