mirror of
https://github.com/rustfs/rustfs.git
synced 2026-07-26 16:28:15 +00:00
fix(notify): match filters against decoded event keys (#2921)
Co-authored-by: houseme <housemecn@gmail.com>
This commit is contained in:
Generated
+1
@@ -9836,6 +9836,7 @@ dependencies = [
|
||||
"chrono",
|
||||
"form_urlencoded",
|
||||
"hashbrown 0.17.1",
|
||||
"percent-encoding",
|
||||
"quick-xml 0.39.4",
|
||||
"rayon",
|
||||
"rustc-hash",
|
||||
|
||||
@@ -36,6 +36,7 @@ async-trait = { workspace = true }
|
||||
chrono = { workspace = true, features = ["serde"] }
|
||||
form_urlencoded = { workspace = true }
|
||||
hashbrown = { workspace = true }
|
||||
percent-encoding = { workspace = true }
|
||||
rayon = { workspace = true }
|
||||
rustc-hash = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
|
||||
@@ -12,8 +12,14 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::{error::NotificationError, event::Event, integration::NotificationMetrics, rules::RulesMap};
|
||||
use crate::{
|
||||
error::NotificationError,
|
||||
event::Event,
|
||||
integration::NotificationMetrics,
|
||||
rules::{RulesMap, TargetIdSet},
|
||||
};
|
||||
use hashbrown::HashMap;
|
||||
use percent_encoding::percent_decode_str;
|
||||
use rustfs_config::notify::{DEFAULT_NOTIFY_SEND_CONCURRENCY, ENV_NOTIFY_SEND_CONCURRENCY};
|
||||
use rustfs_s3_common::EventName;
|
||||
use rustfs_targets::Target;
|
||||
@@ -24,6 +30,23 @@ use std::sync::Arc;
|
||||
use tokio::sync::{RwLock, Semaphore};
|
||||
use tracing::{debug, error, info, instrument, warn};
|
||||
|
||||
fn decoded_object_key_for_matching(object_key: &str) -> Option<String> {
|
||||
if !object_key.contains('%') {
|
||||
return None;
|
||||
}
|
||||
|
||||
let decoded = percent_decode_str(object_key).decode_utf8().ok()?;
|
||||
(decoded != object_key).then(|| decoded.into_owned())
|
||||
}
|
||||
|
||||
fn match_event_targets(rules: &RulesMap, event_name: EventName, object_key: &str) -> TargetIdSet {
|
||||
let mut target_ids = rules.match_rules(event_name, object_key);
|
||||
if let Some(decoded_key) = decoded_object_key_for_matching(object_key) {
|
||||
target_ids.extend(rules.match_rules(event_name, &decoded_key));
|
||||
}
|
||||
target_ids
|
||||
}
|
||||
|
||||
/// Manages event notification to targets based on rules
|
||||
pub struct EventNotifier {
|
||||
metrics: Arc<NotificationMetrics>,
|
||||
@@ -188,7 +211,7 @@ impl EventNotifier {
|
||||
return;
|
||||
};
|
||||
|
||||
let target_ids = rules.match_rules(event_name, object_key);
|
||||
let target_ids = match_event_targets(&rules, event_name, object_key);
|
||||
if target_ids.is_empty() {
|
||||
debug!("No matching targets for event in bucket: {}", bucket_name);
|
||||
self.metrics.increment_skipped();
|
||||
@@ -422,6 +445,30 @@ mod tests {
|
||||
atomic::{AtomicUsize, Ordering},
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn encoded_event_key_matches_raw_prefix_suffix_filter() {
|
||||
let target_id = TargetID::new("primary".to_string(), "webhook".to_string());
|
||||
let mut rules_map = RulesMap::new();
|
||||
rules_map.add_rule_config(&[EventName::ObjectCreatedPut], "uploads/*.csv".to_string(), target_id.clone());
|
||||
|
||||
let targets = match_event_targets(&rules_map, EventName::ObjectCreatedPut, "uploads%2Freport.csv");
|
||||
|
||||
assert!(targets.contains(&target_id));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encoded_event_key_does_not_bypass_suffix_filter() {
|
||||
let target_id = TargetID::new("primary".to_string(), "webhook".to_string());
|
||||
let mut rules_map = RulesMap::new();
|
||||
rules_map.add_rule_config(&[EventName::ObjectCreatedPut], "uploads/*.csv".to_string(), target_id);
|
||||
|
||||
let root_targets = match_event_targets(&rules_map, EventName::ObjectCreatedPut, "report.csv");
|
||||
let suffix_targets = match_event_targets(&rules_map, EventName::ObjectCreatedPut, "uploads%2Freport.txt");
|
||||
|
||||
assert!(root_targets.is_empty());
|
||||
assert!(suffix_targets.is_empty());
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct TestTarget {
|
||||
id: TargetID,
|
||||
|
||||
Reference in New Issue
Block a user