Skip to content

Commit 9ea8c8a

Browse files
committed
wip
1 parent a186b4f commit 9ea8c8a

File tree

19 files changed

+403
-335
lines changed

19 files changed

+403
-335
lines changed

__test__/rewriter.spec.mjs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,25 @@ test('rewrites URLs', (t) => {
1111
}
1212
})
1313

14+
const config = {
15+
condition: {
16+
$and: [
17+
{
18+
type: 'path',
19+
args: ['^/index.php$']
20+
},
21+
{
22+
type: 'header',
23+
args: ['TEST', '^foo$']
24+
}
25+
]
26+
},
27+
rewrite: {
28+
type: 'path',
29+
args: ['^(/index.php)$', '/foo$1']
30+
}
31+
}
32+
1433
const rewriter = new Rewriter([
1534
{
1635
operation: 'and',
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
use super::{Condition, Request};
2+
3+
/// Support plain functions as conditions
4+
impl<F> Condition for F
5+
where
6+
F: Fn(&Request) -> bool + Sync + Send,
7+
{
8+
fn matches(&self, request: &Request) -> bool {
9+
self(request)
10+
}
11+
}
12+
13+
#[cfg(test)]
14+
mod test {
15+
use super::*;
16+
17+
#[test]
18+
fn test_closure_condition() {
19+
let condition = |_: &Request| true;
20+
21+
let request = Request::builder()
22+
.url("http://example.com/index.php")
23+
.build()
24+
.expect("request should build");
25+
26+
assert!(condition.matches(&request));
27+
}
28+
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
use super::{Condition, Request};
2+
3+
/// This provides logical grouping of conditions using either AND or OR
4+
/// combination behaviours.
5+
pub enum ConditionGroup<'a> {
6+
Or(&'a dyn Condition, &'a dyn Condition),
7+
And(&'a dyn Condition, &'a dyn Condition),
8+
}
9+
10+
impl Condition for ConditionGroup<'_> {
11+
fn matches(&self, request: &Request) -> bool {
12+
match self {
13+
ConditionGroup::Or(a, b) => a.matches(request) || b.matches(request),
14+
ConditionGroup::And(a, b) => a.matches(request) && b.matches(request)
15+
}
16+
}
17+
}
18+
19+
#[cfg(test)]
20+
mod test {
21+
use super::*;
22+
use crate::rewrite::{HeaderCondition, PathCondition};
23+
24+
#[test]
25+
fn test_condition_group_and() {
26+
let header = HeaderCondition::new("TEST", "^foo$")
27+
.expect("should be valid regex");
28+
29+
let path = PathCondition::new("^/index\\.php$")
30+
.expect("should be valid regex");
31+
32+
let header_and_path = header.and(&path);
33+
34+
// Check it matches when all conditions match
35+
let request = Request::builder()
36+
.url("http://example.com/index.php")
37+
.header("TEST", "foo")
38+
.build()
39+
.expect("request should build");
40+
41+
assert!(header_and_path.matches(&request));
42+
43+
// Check it _does not_ match if either condition does not match
44+
let only_header = Request::builder()
45+
.url("http://example.com/nope.php")
46+
.header("TEST", "foo")
47+
.build()
48+
.expect("request should build");
49+
50+
assert!(!header_and_path.matches(&only_header));
51+
52+
let only_url = Request::builder()
53+
.url("http://example.com/index.php")
54+
.build()
55+
.expect("request should build");
56+
57+
assert!(!header_and_path.matches(&only_url));
58+
}
59+
60+
#[test]
61+
fn test_condition_group_or() {
62+
let header = HeaderCondition::new("TEST", "^foo$")
63+
.expect("should be valid regex");
64+
65+
let path = PathCondition::new("^/index\\.php$")
66+
.expect("should be valid regex");
67+
68+
let header_or_path = header.or(&path);
69+
70+
// Check it matches when either condition matches
71+
let request = Request::builder()
72+
.url("http://example.com/index.php")
73+
.header("TEST", "foo")
74+
.build()
75+
.expect("request should build");
76+
77+
assert!(header_or_path.matches(&request));
78+
79+
// Check it matches if either condition does not match
80+
let only_header = Request::builder()
81+
.url("http://example.com/nope.php")
82+
.header("TEST", "foo")
83+
.build()
84+
.expect("request should build");
85+
86+
assert!(!header_or_path.matches(&only_header));
87+
88+
let only_url = Request::builder()
89+
.url("http://example.com/index.php")
90+
.build()
91+
.expect("request should build");
92+
93+
assert!(!header_or_path.matches(&only_url));
94+
}
95+
}

crates/lang_handler/src/rewrite/condition/header.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use regex::{Error, Regex};
55
use super::Condition;
66
use crate::Request;
77

8-
/// Match request header to a regex pattern
8+
/// Matches a request header to a regex pattern
99
#[derive(Clone, Debug)]
1010
pub struct HeaderCondition {
1111
name: String,
@@ -45,7 +45,8 @@ mod test {
4545

4646
#[test]
4747
fn test_header_condition() {
48-
let condition = HeaderCondition::new("TEST", "^foo$").expect("regex should be valid");
48+
let condition = HeaderCondition::new("TEST", "^foo$")
49+
.expect("regex should be valid");
4950

5051
let request = Request::builder()
5152
.url("http://example.com/")
Lines changed: 59 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,75 @@
1+
mod closure;
2+
mod group;
13
mod header;
24
mod path;
3-
mod set;
45

5-
pub use header::*;
6-
pub use path::*;
7-
pub use set::*;
6+
use crate::Request;
87

9-
use super::Request;
10-
11-
///
12-
/// Conditions
13-
///
8+
pub use group::ConditionGroup;
9+
pub use header::HeaderCondition;
10+
pub use path::PathCondition;
1411

1512
/// A Condition is used to match against request state before deciding to apply
1613
/// a given Rewrite or set of Rewrites.
1714
pub trait Condition: Sync + Send {
1815
/// A Condition must implement a `matches(request) -> bool` method which
1916
/// receives a request object to determine if the condition is met.
2017
fn matches(&self, request: &Request) -> bool;
21-
}
2218

23-
/// Support plain functions as conditions
24-
impl<F> Condition for F
25-
where
26-
F: Fn(&Request) -> bool + Sync + Send,
27-
{
28-
fn matches(&self, request: &Request) -> bool {
29-
self(request)
19+
/// Make a new condition which must pass both conditions
20+
///
21+
/// # Examples
22+
///
23+
/// ```
24+
/// use lang_handler::rewrite::{PathCondition, HeaderCondition};
25+
///
26+
/// let path = PathCondition::new("^/index.php$")
27+
/// .expect("should be valid regex");
28+
///
29+
/// let header = HeaderCondition::new("TEST", "^foo$")
30+
/// .expect("should be valid regex");
31+
///
32+
/// let path_and_header = path.and(header);
33+
///
34+
/// let request = Request::builder()
35+
/// .url("http://example.com/index.php")
36+
/// .header("TEST", "foo")
37+
/// .build()
38+
/// .expect("should build request");
39+
///
40+
/// assert_eq!(path_and_header.matches(request));
41+
/// ```
42+
fn and<'a>(&'a self, other: &'a impl Condition) -> ConditionGroup<'a>
43+
where Self: std::marker::Sized
44+
{
45+
ConditionGroup::And(self, other)
3046
}
31-
}
32-
33-
#[cfg(test)]
34-
mod test {
35-
use super::*;
36-
37-
#[test]
38-
fn test_closure_condition() {
39-
let condition = |_: &Request| true;
40-
41-
let request = Request::builder()
42-
.url("http://example.com/index.php")
43-
.build()
44-
.expect("request should build");
4547

46-
assert!(condition.matches(&request));
48+
/// Make a new condition which must pass either condition
49+
///
50+
/// # Examples
51+
///
52+
/// ```
53+
/// use lang_handler::rewrite::{PathCondition, HeaderCondition};
54+
///
55+
/// let path = PathCondition::new("^/index.php$")
56+
/// .expect("should be valid regex");
57+
///
58+
/// let header = HeaderCondition::new("TEST", "^foo$")
59+
/// .expect("should be valid regex");
60+
///
61+
/// let path_or_header = path.or(header);
62+
///
63+
/// let request = Request::builder()
64+
/// .url("http://example.com/index.php")
65+
/// .build()
66+
/// .expect("should build request");
67+
///
68+
/// assert_eq!(path_or_header.matches(request));
69+
/// ```
70+
fn or<'a>(&'a self, other: &'a impl Condition) -> ConditionGroup<'a>
71+
where Self: std::marker::Sized
72+
{
73+
ConditionGroup::Or(self, other)
4774
}
4875
}

crates/lang_handler/src/rewrite/condition/path.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ mod test {
3737

3838
#[test]
3939
fn test_path_condition() {
40-
let condition = PathCondition::new("^/index.php$").expect("regex should be valid");
40+
let condition = PathCondition::new("^/index.php$")
41+
.expect("regex should be valid");
4142

4243
let request = Request::builder()
4344
.url("http://example.com/index.php")

crates/lang_handler/src/rewrite/condition/set.rs

Lines changed: 0 additions & 100 deletions
This file was deleted.

0 commit comments

Comments
 (0)