Skip to content

Commit

Permalink
add new routing rules to configuration messages
Browse files Browse the repository at this point in the history
  • Loading branch information
Geal authored and FlorentinDUBOIS committed Jul 13, 2022
1 parent a9dd46e commit 043b928
Show file tree
Hide file tree
Showing 11 changed files with 143 additions and 52 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions command/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ time = "^0.2"
toml = "^0.5"
sha2 = "^0.9"
memchr = "2.3"
regex = "1.1"
serde = "^1.0.34"
serde_json = "^1.0.34"
serde_derive = "^1.0.34"
Expand Down
5 changes: 4 additions & 1 deletion command/assets/add_http_front.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@
"app_id": "xxx",
"address": "0.0.0.0:8080",
"hostname": "yyy",
"path_begin": "xxx"
"path": {
"PREFIX": "xxx"
},
"position": "TREE"
}
}
}
5 changes: 4 additions & 1 deletion command/assets/add_https_front.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@
"app_id": "xxx",
"address": "0.0.0.0:8443",
"hostname": "yyy",
"path_begin": "xxx"
"path": {
"PREFIX": "xxx"
},
"position": "TREE"
}
}
}
5 changes: 4 additions & 1 deletion command/assets/remove_http_front.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@
"app_id": "xxx",
"address": "0.0.0.0:8080",
"hostname": "yyy",
"path_begin": "xxx"
"path": {
"PREFIX": "xxx"
},
"position": "TREE"
}
}
}
5 changes: 4 additions & 1 deletion command/assets/remove_https_front.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@
"app_id": "xxx",
"address": "0.0.0.0:8443",
"hostname": "yyy",
"path_begin": "xxx"
"path": {
"PREFIX": "xxx"
},
"position": "TREE"
}
}
}
19 changes: 12 additions & 7 deletions command/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,19 +133,20 @@ mod tests {
use crate::proxy::{Application,CertificateAndKey,CertFingerprint,ProxyRequestData,HttpFront,Backend,
AppMetricsData,MetricsData,FilteredData,Percentiles,RemoveBackend,
AddCertificate,RemoveCertificate,LoadBalancingParams,TlsVersion,
LoadBalancingAlgorithms};
LoadBalancingAlgorithms,RulePosition,PathRule};
use crate::config::ProxyProtocolConfig;

#[test]
fn config_message_test() {
let raw_json = r#"{ "id": "ID_TEST", "version": 0, "type": "PROXY", "data":{"type": "ADD_HTTP_FRONT", "data": {"app_id": "xxx", "hostname": "yyy", "path_begin": "xxx", "address": "0.0.0.0:8080"}} }"#;
let raw_json = r#"{ "id": "ID_TEST", "version": 0, "type": "PROXY", "data":{"type": "ADD_HTTP_FRONT", "data": {"app_id": "xxx", "hostname": "yyy", "path": {"PREFIX": "xxx"}, "address": "0.0.0.0:8080"}} }"#;
let message: CommandRequest = serde_json::from_str(raw_json).unwrap();
println!("{:?}", message);
assert_eq!(message.data, CommandRequestData::Proxy(ProxyRequestData::AddHttpFront(HttpFront{
app_id: String::from("xxx"),
hostname: String::from("yyy"),
path_begin: String::from("xxx"),
path: PathRule::Prefix(String::from("xxx")),
address: "0.0.0.0:8080".parse().unwrap(),
position: RulePosition::Tree,
})));
}

Expand Down Expand Up @@ -211,8 +212,9 @@ mod tests {
data: CommandRequestData::Proxy(ProxyRequestData::AddHttpFront(HttpFront{
app_id: String::from("xxx"),
hostname: String::from("yyy"),
path_begin: String::from("xxx"),
path: PathRule::Prefix(String::from("xxx")),
address: "0.0.0.0:8080".parse().unwrap(),
position: RulePosition::Tree,
})),
worker_id: None
});
Expand All @@ -223,8 +225,9 @@ mod tests {
data: CommandRequestData::Proxy(ProxyRequestData::RemoveHttpFront(HttpFront{
app_id: String::from("xxx"),
hostname: String::from("yyy"),
path_begin: String::from("xxx"),
path: PathRule::Prefix(String::from("xxx")),
address: "0.0.0.0:8080".parse().unwrap(),
position: RulePosition::Tree,
})),
worker_id: None
});
Expand All @@ -235,8 +238,9 @@ mod tests {
data: CommandRequestData::Proxy(ProxyRequestData::AddHttpsFront(HttpFront{
app_id: String::from("xxx"),
hostname: String::from("yyy"),
path_begin: String::from("xxx"),
path: PathRule::Prefix(String::from("xxx")),
address: "0.0.0.0:8443".parse().unwrap(),
position: RulePosition::Tree,
})),
worker_id: None
});
Expand All @@ -247,8 +251,9 @@ mod tests {
data: CommandRequestData::Proxy(ProxyRequestData::RemoveHttpsFront(HttpFront{
app_id: String::from("xxx"),
hostname: String::from("yyy"),
path_begin: String::from("xxx"),
path: PathRule::Prefix(String::from("xxx")),
address: "0.0.0.0:8443".parse().unwrap(),
position: RulePosition::Tree,
})),
worker_id: None
});
Expand Down
41 changes: 33 additions & 8 deletions command/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ use toml;

use crate::proxy::{CertificateAndKey,ProxyRequestData,HttpFront,TcpFront,Backend,
HttpListener,HttpsListener,TcpListener,AddCertificate,TlsProvider,LoadBalancingParams,
LoadMetric, Application, TlsVersion,ActivateListener,ListenerType, LoadBalancingAlgorithms};
LoadMetric, Application, TlsVersion,ActivateListener,ListenerType,RulePosition,PathRule,
LoadBalancingAlgorithms};

use crate::command::{CommandRequestData,CommandRequest,PROTOCOL_VERSION};

Expand Down Expand Up @@ -272,26 +273,38 @@ pub enum ProxyProtocolConfig {
SendHeader,
RelayHeader,
}

#[derive(Debug,Clone,PartialEq,Eq,Hash,Serialize,Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
#[serde(deny_unknown_fields)]
pub enum PathRuleType {
Prefix,
Regex,
}

#[derive(Debug,Clone,PartialEq,Eq,Hash,Serialize,Deserialize)]
#[serde(deny_unknown_fields)]
pub struct FileAppFrontendConfig {
pub address: SocketAddr,
pub hostname: Option<String>,
pub path_begin: Option<String>,
pub path: Option<String>,
pub path_type: Option<PathRuleType>,
pub certificate: Option<String>,
pub key: Option<String>,
pub certificate_chain: Option<String>,
#[serde(default)]
pub tls_versions: Vec<TlsVersion>,
#[serde(default)]
pub position: RulePosition,
}

impl FileAppFrontendConfig {
pub fn to_tcp_front(&self) -> Result<TcpFrontendConfig, String> {
if self.hostname.is_some() {
return Err(String::from("invalid 'hostname' field for TCP frontend"));
}
if self.path_begin.is_some() {
return Err(String::from("invalid 'path_begin' field for TCP frontend"));
if self.path.is_some() {
return Err(String::from("invalid 'path_prefix' field for TCP frontend"));
}
if self.certificate.is_some() {
return Err(String::from("invalid 'certificate' field for TCP frontend"));
Expand Down Expand Up @@ -327,14 +340,22 @@ impl FileAppFrontendConfig {
}).ok())
.map(split_certificate_chain);

let path = match (self.path.as_ref(), self.path_type.as_ref()) {
(None, _) => PathRule::Prefix("".to_string()),
(Some(s), Some(PathRuleType::Prefix)) => PathRule::Prefix(s.to_string()),
(Some(s), Some(PathRuleType::Regex)) => PathRule::Regex(s.to_string()),
(Some(s), None) => PathRule::Prefix(s.clone()),
};

Ok(HttpFrontendConfig {
address: self.address,
hostname: self.hostname.clone().unwrap(),
path_begin: self.path_begin.clone().unwrap_or_default(),
certificate: certificate_opt,
key: key_opt,
certificate_chain: chain_opt,
tls_versions: self.tls_versions.clone(),
position: self.position,
path
})
}
}
Expand Down Expand Up @@ -462,12 +483,14 @@ impl FileAppConfig {
pub struct HttpFrontendConfig {
pub address: SocketAddr,
pub hostname: String,
pub path_begin: String,
pub path: PathRule,
pub certificate: Option<String>,
pub key: Option<String>,
pub certificate_chain: Option<Vec<String>>,
#[serde(default)]
pub tls_versions: Vec<TlsVersion>,
#[serde(default)]
pub position: RulePosition,
}

impl HttpFrontendConfig {
Expand All @@ -491,15 +514,17 @@ impl HttpFrontendConfig {
app_id: app_id.to_string(),
address: self.address,
hostname: self.hostname.clone(),
path_begin: self.path_begin.clone(),
path: self.path.clone(),
position: self.position.clone(),
}));
} else {
//create the front both for HTTP and HTTPS if possible
v.push(ProxyRequestData::AddHttpFront(HttpFront {
app_id: app_id.to_string(),
address: self.address,
hostname: self.hostname.clone(),
path_begin: self.path_begin.clone(),
path: self.path.clone(),
position: self.position.clone(),
}));
}

Expand Down
1 change: 1 addition & 0 deletions command/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ extern crate serde_json;
extern crate libc;
extern crate time;
extern crate poule;
extern crate regex;

#[macro_use] pub mod logging;
pub mod certificate;
Expand Down
65 changes: 53 additions & 12 deletions command/src/proxy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,22 +250,59 @@ fn socketaddr_cmp(a: &SocketAddr, b: &SocketAddr) -> Ordering {
a.ip().cmp(&b.ip()).then(a.port().cmp(&b.port()))
}

#[derive(Debug,Clone,Copy,PartialEq,Eq,Hash,PartialOrd,Ord, Serialize, Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum RulePosition {
Pre,
Post,
Tree,
}

impl Default for RulePosition {
fn default() -> Self {
RulePosition::Tree
}
}

#[derive(Debug,Clone,PartialEq,Eq,Hash,PartialOrd,Ord, Serialize, Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum PathRule {
Prefix(String),
Regex(String),
}

impl Default for PathRule {
fn default() -> Self {
PathRule::Prefix(String::new())
}
}

fn is_default_path_rule(p: &PathRule) -> bool {
match p {
PathRule::Regex(_) => false,
PathRule::Prefix(s) => s.is_empty(),
}
}

#[derive(Debug,Clone,PartialEq,Eq,Hash, Serialize, Deserialize)]
pub struct HttpFront {
pub app_id: String,
pub address: SocketAddr,
pub hostname: String,
#[serde(default)]
#[serde(skip_serializing_if="String::is_empty")]
pub path_begin: String,
#[serde(skip_serializing_if="is_default_path_rule")]
pub path: PathRule,
#[serde(default)]
pub position: RulePosition,
}

impl Ord for HttpFront {
fn cmp(&self, o: &HttpFront) -> Ordering {
self.app_id.cmp(&o.app_id)
.then(self.hostname.cmp(&o.hostname))
.then(self.path_begin.cmp(&o.path_begin))
.then(self.path.cmp(&o.path))
.then(socketaddr_cmp(&self.address, &o.address))
.then(self.position.cmp(&o.position))
}
}

Expand Down Expand Up @@ -673,7 +710,7 @@ pub enum QueryApplicationType {
#[derive(Debug,Clone,PartialEq,Eq,Hash, Serialize, Deserialize)]
pub struct QueryApplicationDomain {
pub hostname: String,
pub path_begin: Option<String>
pub path: Option<String>
}

#[derive(Debug,Clone,PartialEq,Eq,Hash, Serialize, Deserialize)]
Expand Down Expand Up @@ -784,27 +821,29 @@ mod tests {

#[test]
fn add_front_test() {
let raw_json = r#"{"type": "ADD_HTTP_FRONT", "data": {"app_id": "xxx", "hostname": "yyy", "path_begin": "xxx", "address": "127.0.0.1:4242", "sticky_session": false}}"#;
let raw_json = r#"{"type": "ADD_HTTP_FRONT", "data": {"app_id": "xxx", "hostname": "yyy", "path": {"PREFIX": "xxx"}, "address": "127.0.0.1:4242", "sticky_session": false}}"#;
let command: ProxyRequestData = serde_json::from_str(raw_json).expect("could not parse json");
println!("{:?}", command);
assert!(command == ProxyRequestData::AddHttpFront(HttpFront{
app_id: String::from("xxx"),
hostname: String::from("yyy"),
path_begin: String::from("xxx"),
path: PathRule::Prefix(String::from("xxx")),
address: "127.0.0.1:4242".parse().unwrap(),
position: RulePosition::Tree,
}));
}

#[test]
fn remove_front_test() {
let raw_json = r#"{"type": "REMOVE_HTTP_FRONT", "data": {"app_id": "xxx", "hostname": "yyy", "path_begin": "xxx", "address": "127.0.0.1:4242"}}"#;
let raw_json = r#"{"type": "REMOVE_HTTP_FRONT", "data": {"app_id": "xxx", "hostname": "yyy", "path": {"PREFIX": "xxx"}, "address": "127.0.0.1:4242"}}"#;
let command: ProxyRequestData = serde_json::from_str(raw_json).expect("could not parse json");
println!("{:?}", command);
assert!(command == ProxyRequestData::RemoveHttpFront(HttpFront{
app_id: String::from("xxx"),
hostname: String::from("yyy"),
path_begin: String::from("xxx"),
path: PathRule::Prefix(String::from("xxx")),
address: "127.0.0.1:4242".parse().unwrap(),
position: RulePosition::Tree,
}));
}

Expand Down Expand Up @@ -838,27 +877,29 @@ mod tests {

#[test]
fn http_front_crash_test() {
let raw_json = r#"{"type": "ADD_HTTP_FRONT", "data": {"app_id": "aa", "hostname": "cltdl.fr", "path_begin": "", "address": "127.0.0.1:4242"}}"#;
let raw_json = r#"{"type": "ADD_HTTP_FRONT", "data": {"app_id": "aa", "hostname": "cltdl.fr", "path": {"PREFIX": ""}, "address": "127.0.0.1:4242"}}"#;
let command: ProxyRequestData = serde_json::from_str(raw_json).expect("could not parse json");
println!("{:?}", command);
assert!(command == ProxyRequestData::AddHttpFront(HttpFront{
app_id: String::from("aa"),
hostname: String::from("cltdl.fr"),
path_begin: String::from(""),
path: PathRule::Prefix(String::from("")),
address: "127.0.0.1:4242".parse().unwrap(),
position: RulePosition::Tree,
}));
}

#[test]
fn http_front_crash_test2() {
let raw_json = r#"{"app_id": "aa", "hostname": "cltdl.fr", "path_begin": "", "address": "127.0.0.1:4242" }"#;
let raw_json = r#"{"app_id": "aa", "hostname": "cltdl.fr", "path": {"PREFIX": ""}, "address": "127.0.0.1:4242" }"#;
let front: HttpFront = serde_json::from_str(raw_json).expect("could not parse json");
println!("{:?}",front);
assert!(front == HttpFront{
app_id: String::from("aa"),
hostname: String::from("cltdl.fr"),
path_begin: String::from(""),
path: PathRule::Prefix(String::from("")),
address: "127.0.0.1:4242".parse().unwrap(),
position: RulePosition::Tree,
});
}
}

0 comments on commit 043b928

Please sign in to comment.