Skip to content

Commit 53ac3b0

Browse files
Merge pull request #208 from code0-tech/#207-manual-url-verfication
reworked matching logic
2 parents 7da396b + 03b4522 commit 53ac3b0

1 file changed

Lines changed: 161 additions & 51 deletions

File tree

adapter/rest/src/route.rs

Lines changed: 161 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -11,75 +11,185 @@ pub struct RequestRoute {
1111
// Only if both matched, it will return true
1212
impl IdentifiableFlow for RequestRoute {
1313
fn identify(&self, flow: &ValidationFlow) -> bool {
14-
// Get Method of the FlowSetting
15-
let method_str = flow
16-
.settings
17-
.iter()
18-
.find(|s| s.flow_setting_id == "httpMethod")
19-
.and_then(|s| s.value.as_ref())
20-
.and_then(|v| v.kind.as_ref())
21-
.and_then(|k| match k {
22-
Kind::StringValue(s) => Some(s.as_str()),
23-
_ => None,
24-
});
14+
log::debug!(
15+
"route identify start: flow_id={} project_slug={} request_method={} request_path={:?}",
16+
flow.flow_id,
17+
flow.project_slug,
18+
self.method.as_str(),
19+
self.url
20+
);
21+
22+
let Some(flow_method) = extract_flow_setting_as_string(flow, "httpMethod") else {
23+
log::debug!(
24+
"route identify reject: flow_id={} reason=missing_or_invalid_httpMethod",
25+
flow.flow_id
26+
);
27+
return false;
28+
};
2529

2630
log::debug!(
27-
"Comparing flows method: {:?} with request route: {}",
28-
method_str,
31+
"route identify method check: flow_id={} flow_method={} request_method={}",
32+
flow.flow_id,
33+
flow_method,
2934
self.method.as_str()
3035
);
3136

32-
if let Some(method) = method_str {
33-
if method != self.method.as_str() {
34-
log::debug!("Method didn't eq");
35-
return false;
36-
}
37-
} else {
38-
log::debug!("Method didn't eq");
37+
if flow_method != self.method.as_str() {
38+
log::debug!(
39+
"route identify reject: flow_id={} reason=method_mismatch flow_method={} request_method={}",
40+
flow.flow_id,
41+
flow_method,
42+
self.method.as_str()
43+
);
3944
return false;
4045
}
41-
// Get URL of the FlowSetting
42-
let regex_str_v = flow
43-
.settings
44-
.iter()
45-
.find(|s| s.flow_setting_id == "httpURL");
46-
47-
log::debug!("Extracted: {:?} as httpURL", &regex_str_v);
48-
49-
let regex_str = regex_str_v
50-
.and_then(|s| s.value.as_ref())
51-
.and_then(|v| v.kind.as_ref())
52-
.and_then(|k| match k {
53-
Kind::StringValue(s) => Some(s.as_str()),
54-
_ => None,
55-
});
56-
57-
let Some(regex_str) = regex_str else {
58-
log::debug!("Regex was empty");
46+
47+
let Some(flow_http_url) = extract_flow_setting_as_string(flow, "httpURL") else {
48+
log::debug!(
49+
"route identify reject: flow_id={} reason=missing_or_invalid_httpURL",
50+
flow.flow_id
51+
);
5952
return false;
6053
};
6154

55+
let route_pattern = format!("/{}{}", flow.project_slug, flow_http_url);
6256
log::debug!(
63-
"Comparing regex {} with literal route: {}",
64-
regex_str,
57+
"route identify route check: flow_id={} httpURL={:?} resolved_pattern={:?} request_path={:?}",
58+
flow.flow_id,
59+
flow_http_url,
60+
route_pattern,
6561
self.url
6662
);
6763

68-
// Check if the request is matching
69-
match regex::Regex::new(regex_str) {
70-
Ok(regex) => {
71-
log::debug!("Successfully compiled regex: {}", regex_str);
72-
regex.is_match(&self.url)
73-
}
74-
Err(err) => {
75-
log::error!("Failed to compile regex: {}", err);
76-
false
77-
}
78-
}
64+
let is_match = matches_route_pattern(&route_pattern, &self.url);
65+
log::debug!(
66+
"route identify result: flow_id={} matched={}",
67+
flow.flow_id,
68+
is_match
69+
);
70+
is_match
7971
}
8072
}
8173

8274
pub fn extract_slug_from_path(path: &str) -> Option<&str> {
8375
let trimmed = path.trim_start_matches('/');
8476
trimmed.split('/').next().filter(|s| !s.is_empty())
8577
}
78+
79+
fn matches_route_pattern(pattern: &str, route: &str) -> bool {
80+
let anchored_pattern = format!("^{}$", pattern);
81+
log::debug!(
82+
"route pattern eval: raw_pattern={:?} anchored_pattern={:?} route={:?}",
83+
pattern,
84+
anchored_pattern,
85+
route
86+
);
87+
88+
let regex = match regex::Regex::new(&anchored_pattern) {
89+
Ok(regex) => regex,
90+
Err(err) => {
91+
log::error!(
92+
"route pattern invalid regex: anchored_pattern={:?} error={}",
93+
anchored_pattern,
94+
err
95+
);
96+
return false;
97+
}
98+
};
99+
100+
let is_match = regex.is_match(route);
101+
log::debug!(
102+
"route pattern result: anchored_pattern={:?} route={:?} matched={}",
103+
anchored_pattern,
104+
route,
105+
is_match
106+
);
107+
is_match
108+
}
109+
110+
fn extract_flow_setting_as_string<'a>(
111+
flow: &'a ValidationFlow,
112+
flow_setting_id: &str,
113+
) -> Option<&'a str> {
114+
let setting = match flow
115+
.settings
116+
.iter()
117+
.find(|setting| setting.flow_setting_id == flow_setting_id)
118+
{
119+
Some(setting) => setting,
120+
None => {
121+
log::debug!(
122+
"flow setting is missing: flow_id={} flow_setting_id={}",
123+
flow.flow_id,
124+
flow_setting_id
125+
);
126+
return None;
127+
}
128+
};
129+
130+
let value = match setting.value.as_ref() {
131+
Some(value) => value,
132+
None => {
133+
log::debug!(
134+
"flow setting has no value: flow_id={} flow_setting_id={}",
135+
flow.flow_id,
136+
flow_setting_id
137+
);
138+
return None;
139+
}
140+
};
141+
142+
let kind = match value.kind.as_ref() {
143+
Some(kind) => kind,
144+
None => {
145+
log::debug!(
146+
"flow setting has no kind: flow_id={} flow_setting_id={}",
147+
flow.flow_id,
148+
flow_setting_id
149+
);
150+
return None;
151+
}
152+
};
153+
154+
match kind {
155+
Kind::StringValue(value) => Some(value.as_str()),
156+
_ => {
157+
log::debug!(
158+
"flow setting has non-string kind: flow_id={} flow_setting_id={} kind={:?}",
159+
flow.flow_id,
160+
flow_setting_id,
161+
kind
162+
);
163+
None
164+
}
165+
}
166+
}
167+
168+
#[cfg(test)]
169+
mod tests {
170+
use super::matches_route_pattern;
171+
172+
#[test]
173+
fn exact_literal_match_works() {
174+
assert!(matches_route_pattern("test2", "test2"));
175+
}
176+
177+
#[test]
178+
fn substring_match_is_rejected() {
179+
assert!(!matches_route_pattern("test", "test2"));
180+
}
181+
182+
#[test]
183+
fn nested_path_match_is_anchored() {
184+
assert!(matches_route_pattern("/api/v1/test2", "/api/v1/test2"));
185+
assert!(!matches_route_pattern(
186+
"/api/v1/test2",
187+
"/api/v1/test2/extra"
188+
));
189+
}
190+
191+
#[test]
192+
fn invalid_regex_returns_false() {
193+
assert!(!matches_route_pattern("(", "/test"));
194+
}
195+
}

0 commit comments

Comments
 (0)