8 Commits

Author SHA1 Message Date
Ara Sadoyan
edadda803c version change 2026-06-27 14:20:06 +02:00
Ara Sadoyan
c5d0fe60a0 resolved possible divide by zero issue from #46 2026-06-27 13:38:59 +02:00
Ara Sadoyan
d7fe476b24 Merge pull request #47 from sadoyan/dev
Dev
2026-06-27 12:33:32 +02:00
Ara Sadoyan
aa22749393 Merge branch 'main' into dev 2026-06-27 12:32:41 +02:00
Ara Sadoyan
4b6a558b4b Merge branch 'main' into dev 2026-06-27 12:31:49 +02:00
Ara Sadoyan
6c9c7acf65 Merge pull request #46 from Taqman-probe/fix/sticky-session-404
Fix: Resolve 404/405 errors with sticky session cookie handling in /api routes
2026-06-27 12:31:29 +02:00
Taqman-probe
2845dc5923 fix 404 error on multipath and cleanup fn: clone_idmap_into 2026-06-27 13:51:12 +09:00
Ara Sadoyan
f2e07a8d70 resolved #44 2026-06-26 16:32:58 +02:00
7 changed files with 36 additions and 48 deletions

2
Cargo.lock generated
View File

@@ -127,7 +127,7 @@ checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
[[package]]
name = "aralez"
version = "0.92.11"
version = "0.92.12"
dependencies = [
"ahash",
"arc-swap",

View File

@@ -1,6 +1,6 @@
[package]
name = "aralez"
version = "0.92.11"
version = "0.92.12"
edition = "2021"
license = "Apache-2.0"
description = "Reverse proxy built on top of Cloudflare's Pingora"

View File

@@ -96,7 +96,7 @@ pub async fn load_configuration(d: &str, kind: &str) -> (Option<Configuration>,
}
info!("Reading upstreams from {}", d);
data
data // [2606:4700:2ff9::1]:443
}
"content" => {
info!("Reading upstreams from API post body");
@@ -157,7 +157,7 @@ async fn populate_headers_and_auth(config: &mut Configuration, parsed: &Config)
let mut ch: Vec<(String, Arc<str>)> = Vec::new();
if let Some(headers) = &parsed.client_headers {
for header in headers {
if let Some((key, val)) = header.split_once(':') {
if let Some((key, val)) = header.rsplit_once(':') {
ch.push((key.to_string(), Arc::from(val)));
}
}
@@ -170,7 +170,7 @@ async fn populate_headers_and_auth(config: &mut Configuration, parsed: &Config)
let mut sh: Vec<(String, Arc<str>)> = Vec::new();
if let Some(headers) = &parsed.server_headers {
for header in headers {
if let Some((key, val)) = header.split_once(':') {
if let Some((key, val)) = header.rsplit_once(':') {
sh.push((key.to_string(), Arc::from(val.trim())));
}
}
@@ -225,7 +225,8 @@ async fn populate_file_upstreams(config: &mut Configuration, parsed: &Config) {
}
let redirect_link = path_config.redirect_to.as_ref().map(|www| Arc::from(www.as_str()));
if let Some((ip, port_str)) = server.split_once(':') {
if let Some((ip, port_str)) = server.rsplit_once(':') {
if let Ok(port) = port_str.parse::<u16>() {
server_list.push(Arc::from(InnerMap {
address: Arc::from(ip),
@@ -271,18 +272,18 @@ pub fn parce_main_config(path: &str) -> AppConfig {
log_builder(&cfo, &cfo.log_file);
cfo.hc_method = cfo.hc_method.to_uppercase();
if let Some((ip, port_str)) = cfo.config_address.split_once(':') {
if let Some((ip, port_str)) = cfo.config_address.rsplit_once(':') {
if let Ok(port) = port_str.parse::<u16>() {
cfo.local_server = Option::from((ip.to_string(), port));
}
}
if let Some(tlsport_cfg) = cfo.proxy_address_tls.clone() {
if let Some((_, port_str)) = tlsport_cfg.split_once(':') {
if let Some((_, port_str)) = tlsport_cfg.rsplit_once(':') {
cfo.proxy_port_tls = Some(port_str.to_string());
}
};
if let Some((_, port_str)) = cfo.proxy_address_http.split_once(':') {
if let Some((_, port_str)) = cfo.proxy_address_http.rsplit_once(':') {
cfo.proxy_port = Some(port_str.to_string());
}
@@ -320,7 +321,7 @@ fn parce_tls_grades(what: Option<String>) -> Option<String> {
pub fn build_headers(path_config: &Option<Vec<String>>, _config: &Configuration, hl: &mut Vec<(String, Arc<str>)>) {
if let Some(headers) = &path_config {
for header in headers {
if let Some((key, val)) = header.split_once(':') {
if let Some((key, val)) = header.rsplit_once(':') {
hl.push((key.trim().to_string(), Arc::from(val.trim())));
}
}

View File

@@ -8,8 +8,6 @@ pub type UpstreamsDashMap = DashMap<Arc<str>, DashMap<Arc<str>, (Vec<Arc<InnerMa
pub type UpstreamsIdMap = DashMap<String, Arc<InnerMap>>;
pub type Headers = DashMap<Arc<str>, DashMap<Arc<str>, Vec<(String, Arc<str>)>>>;
// pub type UpstreamsSerDde = Option<HashMap<String, HostConfig>>;
// pub type UpstreamsSerDe = HashMap<String, HostConfig>;
#[derive(Clone, Debug, Default)]
pub struct Extraparams {

View File

@@ -1,6 +1,6 @@
use crate::tls::load;
use crate::tls::load::CertificateConfig;
use crate::utils::structs::{Extraparams, InnerMap, InnerMapForJson, UpstreamSnapshotForJson, UpstreamsDashMap, UpstreamsIdMap};
use crate::utils::structs::{Extraparams, InnerMapForJson, UpstreamSnapshotForJson, UpstreamsDashMap, UpstreamsIdMap};
use dashmap::DashMap;
use log::{error, info};
use notify::{event::ModifyKind, Config, EventKind, RecommendedWatcher, RecursiveMode, Watcher};
@@ -147,11 +147,8 @@ pub fn clone_idmap_into(original: &UpstreamsDashMap, cloned: &UpstreamsIdMap) {
cloned.clear();
for outer_entry in original.iter() {
let inner_map = outer_entry.value();
let new_inner_map = DashMap::new();
for inner_entry in inner_map.iter() {
let path = inner_entry.key();
let (vec, _) = inner_entry.value();
let new_vec = vec.clone();
for x in vec.iter() {
let mut id = String::new();
write!(
@@ -175,22 +172,8 @@ pub fn clone_idmap_into(original: &UpstreamsDashMap, cloned: &UpstreamsIdMap) {
let hash = hasher.finalize();
let hex_hash = base16ct::lower::encode_string(&hash);
let hh = hex_hash[0..50].to_string();
let to_add = InnerMap {
address: Arc::from("127.0.0.1"),
port: 0,
is_ssl: false,
is_http2: false,
to_https: false,
rate_limit: None,
x4xx_limit: None,
healthcheck: None,
redirect_to: None,
authorization: None,
};
cloned.insert(id, Arc::from(to_add));
cloned.insert(hh, x.to_owned());
}
new_inner_map.insert(path.clone(), new_vec);
}
}
info!("Upstreams are fully populated. Ready to server requests");

View File

@@ -1,7 +1,6 @@
use crate::utils::structs::InnerMap;
use crate::web::proxyhttp::LB;
use async_trait::async_trait;
use std::sync::atomic::Ordering;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
#[derive(Debug, Clone)]
@@ -10,30 +9,38 @@ pub struct GetHostsReturHeaders {
pub server_headers: Option<Vec<(String, Arc<str>)>>,
}
#[async_trait]
pub trait GetHost {
fn find_sticky_backend(&self, servers: &[Arc<InnerMap>], backend_id: Option<&str>) -> Option<Arc<InnerMap>>;
fn pick_backend(&self, servers: &[Arc<InnerMap>], index: &AtomicUsize, backend_id: Option<&str>) -> Option<Arc<InnerMap>>;
fn get_host(&self, peer: &str, path: &str, backend_id: Option<&str>) -> Option<Arc<InnerMap>>;
fn get_header(&self, peer: &str, path: &str) -> Option<GetHostsReturHeaders>;
// fn get_upstreams(&self) -> Arc<UpstreamsDashMap>;
}
#[async_trait]
impl GetHost for LB {
fn get_host(&self, peer: &str, path: &str, backend_id: Option<&str>) -> Option<Arc<InnerMap>> {
if let Some(b) = backend_id {
if let Some(bb) = self.ump_byid.get(b) {
return Some(bb.value().clone());
}
fn find_sticky_backend(&self, servers: &[Arc<InnerMap>], backend_id: Option<&str>) -> Option<Arc<InnerMap>> {
let b = backend_id?;
let bb = self.ump_byid.get(b)?;
let target = bb.value();
servers.iter().any(|s| s.address == target.address && s.port == target.port).then(|| target.clone())
}
fn pick_backend(&self, servers: &[Arc<InnerMap>], index: &AtomicUsize, backend_id: Option<&str>) -> Option<Arc<InnerMap>> {
if servers.is_empty() {
return None;
}
if let Some(target) = self.find_sticky_backend(servers, backend_id) {
return Some(target);
}
let idx = index.fetch_add(1, Ordering::Relaxed) % servers.len();
Some(servers[idx].clone())
}
fn get_host(&self, peer: &str, path: &str, backend_id: Option<&str>) -> Option<Arc<InnerMap>> {
let host_entry = self.ump_upst.get(peer)?;
let mut end = path.len();
loop {
let slice = &path[..end];
if let Some(entry) = host_entry.get(slice) {
let (servers, index) = entry.value();
if !servers.is_empty() {
let idx = index.fetch_add(1, Ordering::Relaxed) % servers.len();
return Some(servers[idx].clone());
if let Some(backend) = self.pick_backend(servers, index, backend_id) {
return Some(backend);
}
}
if let Some(pos) = slice.rfind('/') {
@@ -44,9 +51,8 @@ impl GetHost for LB {
}
if let Some(entry) = host_entry.get("/") {
let (servers, index) = entry.value();
if !servers.is_empty() {
let idx = index.fetch_add(1, Ordering::Relaxed) % servers.len();
return Some(servers[idx].clone());
if let Some(backend) = self.pick_backend(servers, index, backend_id) {
return Some(backend);
}
}
None

View File

@@ -283,7 +283,7 @@ impl ProxyHttp for LB {
buf.push_str("; Path=/; Max-Age=");
buf.push_str(&val.to_string());
buf.push_str("; HttpOnly; SameSite=Lax");
let _ = _upstream_response.insert_header("set-cookie", buf.as_str());
let _ = _upstream_response.append_header("set-cookie", buf.as_str());
}
}