mirror of https://github.com/fafhrd91/actix-web
Compare commits
14 Commits
6d3f082513
...
2f2d268192
Author | SHA1 | Date |
---|---|---|
|
2f2d268192 | |
|
b6ad483699 | |
|
c002fd783c | |
|
95ad1caa23 | |
|
eb906d077a | |
|
f08fa6b684 | |
|
5ad04e6de7 | |
|
6f4bdb31f9 | |
|
4e56ae0594 | |
|
9f2b207137 | |
|
b47530d66a | |
|
55c38a625f | |
|
934f68ebf6 | |
|
ffa95b7f60 |
|
@ -49,7 +49,7 @@ jobs:
|
||||||
toolchain: ${{ matrix.version.version }}
|
toolchain: ${{ matrix.version.version }}
|
||||||
|
|
||||||
- name: Install just, cargo-hack, cargo-nextest, cargo-ci-cache-clean
|
- name: Install just, cargo-hack, cargo-nextest, cargo-ci-cache-clean
|
||||||
uses: taiki-e/install-action@v2.54.3
|
uses: taiki-e/install-action@v2.56.13
|
||||||
with:
|
with:
|
||||||
tool: just,cargo-hack,cargo-nextest,cargo-ci-cache-clean
|
tool: just,cargo-hack,cargo-nextest,cargo-ci-cache-clean
|
||||||
|
|
||||||
|
@ -83,7 +83,7 @@ jobs:
|
||||||
uses: actions-rust-lang/setup-rust-toolchain@v1.13.0
|
uses: actions-rust-lang/setup-rust-toolchain@v1.13.0
|
||||||
|
|
||||||
- name: Install just, cargo-hack
|
- name: Install just, cargo-hack
|
||||||
uses: taiki-e/install-action@v2.54.3
|
uses: taiki-e/install-action@v2.56.13
|
||||||
with:
|
with:
|
||||||
tool: just,cargo-hack
|
tool: just,cargo-hack
|
||||||
|
|
||||||
|
|
|
@ -64,7 +64,7 @@ jobs:
|
||||||
toolchain: ${{ matrix.version.version }}
|
toolchain: ${{ matrix.version.version }}
|
||||||
|
|
||||||
- name: Install just, cargo-hack, cargo-nextest, cargo-ci-cache-clean
|
- name: Install just, cargo-hack, cargo-nextest, cargo-ci-cache-clean
|
||||||
uses: taiki-e/install-action@v2.54.3
|
uses: taiki-e/install-action@v2.56.13
|
||||||
with:
|
with:
|
||||||
tool: just,cargo-hack,cargo-nextest,cargo-ci-cache-clean
|
tool: just,cargo-hack,cargo-nextest,cargo-ci-cache-clean
|
||||||
|
|
||||||
|
@ -113,7 +113,7 @@ jobs:
|
||||||
toolchain: nightly
|
toolchain: nightly
|
||||||
|
|
||||||
- name: Install just
|
- name: Install just
|
||||||
uses: taiki-e/install-action@v2.54.3
|
uses: taiki-e/install-action@v2.56.13
|
||||||
with:
|
with:
|
||||||
tool: just
|
tool: just
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ jobs:
|
||||||
components: llvm-tools
|
components: llvm-tools
|
||||||
|
|
||||||
- name: Install just, cargo-llvm-cov, cargo-nextest
|
- name: Install just, cargo-llvm-cov, cargo-nextest
|
||||||
uses: taiki-e/install-action@v2.54.3
|
uses: taiki-e/install-action@v2.56.13
|
||||||
with:
|
with:
|
||||||
tool: just,cargo-llvm-cov,cargo-nextest
|
tool: just,cargo-llvm-cov,cargo-nextest
|
||||||
|
|
||||||
|
|
|
@ -77,7 +77,7 @@ jobs:
|
||||||
toolchain: ${{ vars.RUST_VERSION_EXTERNAL_TYPES }}
|
toolchain: ${{ vars.RUST_VERSION_EXTERNAL_TYPES }}
|
||||||
|
|
||||||
- name: Install just
|
- name: Install just
|
||||||
uses: taiki-e/install-action@v2.54.3
|
uses: taiki-e/install-action@v2.56.13
|
||||||
with:
|
with:
|
||||||
tool: just
|
tool: just
|
||||||
|
|
||||||
|
|
|
@ -147,7 +147,7 @@ dependencies = [
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_urlencoded",
|
"serde_urlencoded",
|
||||||
"slab",
|
"slab",
|
||||||
"socket2 0.5.10",
|
"socket2 0.6.0",
|
||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -393,7 +393,7 @@ dependencies = [
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_urlencoded",
|
"serde_urlencoded",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"socket2 0.5.10",
|
"socket2 0.6.0",
|
||||||
"static_assertions",
|
"static_assertions",
|
||||||
"time",
|
"time",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
@ -1509,9 +1509,9 @@ checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "h2"
|
name = "h2"
|
||||||
version = "0.3.26"
|
version = "0.3.27"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8"
|
checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"fnv",
|
"fnv",
|
||||||
|
@ -1785,6 +1785,17 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "io-uring"
|
||||||
|
version = "0.7.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b86e202f00093dcba4275d4636b93ef9dd75d025ae560d2521b45ea28ab49013"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.9.1",
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ipconfig"
|
name = "ipconfig"
|
||||||
version = "0.3.2"
|
version = "0.3.2"
|
||||||
|
@ -2794,9 +2805,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_spanned"
|
name = "serde_spanned"
|
||||||
version = "0.6.8"
|
version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1"
|
checksum = "40734c41988f7306bb04f0ecf60ec0f3f1caa34290e4e8ea471dcd3346483b83"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
@ -2882,6 +2893,16 @@ dependencies = [
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "socket2"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"windows-sys 0.59.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "spin"
|
name = "spin"
|
||||||
version = "0.5.2"
|
version = "0.5.2"
|
||||||
|
@ -3066,17 +3087,19 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "1.45.1"
|
version = "1.46.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779"
|
checksum = "0cc3a2344dafbe23a245241fe8b09735b521110d30fcefbbd5feb1797ca35d17"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"backtrace",
|
"backtrace",
|
||||||
"bytes",
|
"bytes",
|
||||||
|
"io-uring 0.7.8",
|
||||||
"libc",
|
"libc",
|
||||||
"mio",
|
"mio",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"signal-hook-registry",
|
"signal-hook-registry",
|
||||||
|
"slab",
|
||||||
"socket2 0.5.10",
|
"socket2 0.5.10",
|
||||||
"tokio-macros",
|
"tokio-macros",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
|
@ -3165,7 +3188,7 @@ checksum = "748482e3e13584a34664a710168ad5068e8cb1d968aa4ffa887e83ca6dd27967"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"io-uring",
|
"io-uring 0.6.4",
|
||||||
"libc",
|
"libc",
|
||||||
"slab",
|
"slab",
|
||||||
"socket2 0.4.10",
|
"socket2 0.4.10",
|
||||||
|
@ -3187,44 +3210,42 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml"
|
name = "toml"
|
||||||
version = "0.8.22"
|
version = "0.9.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae"
|
checksum = "ed0aee96c12fa71097902e0bb061a5e1ebd766a6636bb605ba401c45c1650eac"
|
||||||
dependencies = [
|
|
||||||
"serde",
|
|
||||||
"serde_spanned",
|
|
||||||
"toml_datetime",
|
|
||||||
"toml_edit",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "toml_datetime"
|
|
||||||
version = "0.6.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3"
|
|
||||||
dependencies = [
|
|
||||||
"serde",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "toml_edit"
|
|
||||||
version = "0.22.26"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_spanned",
|
"serde_spanned",
|
||||||
"toml_datetime",
|
"toml_datetime",
|
||||||
"toml_write",
|
"toml_parser",
|
||||||
|
"toml_writer",
|
||||||
"winnow",
|
"winnow",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_write"
|
name = "toml_datetime"
|
||||||
version = "0.1.1"
|
version = "0.7.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bfb942dfe1d8e29a7ee7fcbde5bd2b9a25fb89aa70caea2eba3bee836ff41076"
|
checksum = "bade1c3e902f58d73d3f294cd7f20391c1cb2fbcb643b73566bc773971df91e3"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml_parser"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "97200572db069e74c512a14117b296ba0a80a30123fbbb5aa1f4a348f639ca30"
|
||||||
|
dependencies = [
|
||||||
|
"winnow",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml_writer"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fcc842091f2def52017664b53082ecbbeb5c7731092bad69d2c63050401dfd64"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tracing"
|
name = "tracing"
|
||||||
|
@ -3306,9 +3327,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "trybuild"
|
name = "trybuild"
|
||||||
version = "1.0.105"
|
version = "1.0.106"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1c9bf9513a2f4aeef5fdac8677d7d349c79fdbcc03b9c86da6e9d254f1e43be2"
|
checksum = "65af40ad689f2527aebbd37a0a816aea88ff5f774ceabe99de5be02f2f91dae2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"glob",
|
"glob",
|
||||||
"serde",
|
"serde",
|
||||||
|
@ -3759,9 +3780,6 @@ name = "winnow"
|
||||||
version = "0.7.10"
|
version = "0.7.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec"
|
checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec"
|
||||||
dependencies = [
|
|
||||||
"memchr",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winreg"
|
name = "winreg"
|
||||||
|
|
|
@ -53,7 +53,7 @@ serde = "1"
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
serde_urlencoded = "0.7"
|
serde_urlencoded = "0.7"
|
||||||
slab = "0.4"
|
slab = "0.4"
|
||||||
socket2 = "0.5"
|
socket2 = "0.6"
|
||||||
tls-openssl = { version = "0.10.55", package = "openssl", optional = true }
|
tls-openssl = { version = "0.10.55", package = "openssl", optional = true }
|
||||||
tokio = { version = "1.38.2", features = ["sync"] }
|
tokio = { version = "1.38.2", features = ["sync"] }
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,14 @@
|
||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Add conflict path detection and handling to enhance routing performance.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Refactor capture_match_info_fn by splitting it into three distinct functions: capture_match_info(), resolve_path_if_match(), and resolve().
|
||||||
|
|
||||||
## 0.5.3
|
## 0.5.3
|
||||||
|
|
||||||
- Add `unicode` crate feature (on-by-default) to switch between `regex` and `regex-lite` as a trade-off between full unicode support and binary size.
|
- Add `unicode` crate feature (on-by-default) to switch between `regex` and `regex-lite` as a trade-off between full unicode support and binary size.
|
||||||
|
|
|
@ -179,6 +179,15 @@ fn compare_routers(c: &mut Criterion) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
group.bench_function("actix_guard_failures", |b| {
|
||||||
|
b.iter(|| {
|
||||||
|
for route in call() {
|
||||||
|
let mut path = actix_router::Path::new(route);
|
||||||
|
black_box(actix.recognize_fn(&mut path, |_, _| false));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
let regex_set = regex::RegexSet::new(register!(regex)).unwrap();
|
let regex_set = regex::RegexSet::new(register!(regex)).unwrap();
|
||||||
group.bench_function("regex", |b| {
|
group.bench_function("regex", |b| {
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
|
|
|
@ -662,13 +662,13 @@ mod tests {
|
||||||
let rdef = ResourceDef::new("/{key}");
|
let rdef = ResourceDef::new("/{key}");
|
||||||
|
|
||||||
let mut path = Path::new("/%25");
|
let mut path = Path::new("/%25");
|
||||||
rdef.capture_match_info(&mut path);
|
rdef.resolve_path_if_match(&mut path);
|
||||||
let de = PathDeserializer::new(&path);
|
let de = PathDeserializer::new(&path);
|
||||||
let segment: String = serde::Deserialize::deserialize(de).unwrap();
|
let segment: String = serde::Deserialize::deserialize(de).unwrap();
|
||||||
assert_eq!(segment, "%");
|
assert_eq!(segment, "%");
|
||||||
|
|
||||||
let mut path = Path::new("/%2F");
|
let mut path = Path::new("/%2F");
|
||||||
rdef.capture_match_info(&mut path);
|
rdef.resolve_path_if_match(&mut path);
|
||||||
let de = PathDeserializer::new(&path);
|
let de = PathDeserializer::new(&path);
|
||||||
let segment: String = serde::Deserialize::deserialize(de).unwrap();
|
let segment: String = serde::Deserialize::deserialize(de).unwrap();
|
||||||
assert_eq!(segment, "/")
|
assert_eq!(segment, "/")
|
||||||
|
@ -679,7 +679,7 @@ mod tests {
|
||||||
let rdef = ResourceDef::new("/{key}/{value}");
|
let rdef = ResourceDef::new("/{key}/{value}");
|
||||||
|
|
||||||
let mut path = Path::new("/%30%25/%30%2F");
|
let mut path = Path::new("/%30%25/%30%2F");
|
||||||
rdef.capture_match_info(&mut path);
|
rdef.resolve_path_if_match(&mut path);
|
||||||
let de = PathDeserializer::new(&path);
|
let de = PathDeserializer::new(&path);
|
||||||
let segment: (String, String) = serde::Deserialize::deserialize(de).unwrap();
|
let segment: (String, String) = serde::Deserialize::deserialize(de).unwrap();
|
||||||
assert_eq!(segment.0, "0%");
|
assert_eq!(segment.0, "0%");
|
||||||
|
@ -697,7 +697,7 @@ mod tests {
|
||||||
let rdef = ResourceDef::new("/{key}/{value}");
|
let rdef = ResourceDef::new("/{key}/{value}");
|
||||||
|
|
||||||
let mut path = Path::new("/%25/%2F");
|
let mut path = Path::new("/%25/%2F");
|
||||||
rdef.capture_match_info(&mut path);
|
rdef.resolve_path_if_match(&mut path);
|
||||||
let de = PathDeserializer::new(&path);
|
let de = PathDeserializer::new(&path);
|
||||||
let vals: Vals = serde::Deserialize::deserialize(de).unwrap();
|
let vals: Vals = serde::Deserialize::deserialize(de).unwrap();
|
||||||
assert_eq!(vals.key, "%");
|
assert_eq!(vals.key, "%");
|
||||||
|
@ -714,7 +714,7 @@ mod tests {
|
||||||
let rdef = ResourceDef::new("/{val}");
|
let rdef = ResourceDef::new("/{val}");
|
||||||
|
|
||||||
let mut path = Path::new("/X");
|
let mut path = Path::new("/X");
|
||||||
rdef.capture_match_info(&mut path);
|
rdef.resolve_path_if_match(&mut path);
|
||||||
let de = PathDeserializer::new(&path);
|
let de = PathDeserializer::new(&path);
|
||||||
let params: Params<'_> = serde::Deserialize::deserialize(de).unwrap();
|
let params: Params<'_> = serde::Deserialize::deserialize(de).unwrap();
|
||||||
assert_eq!(params.val, "X");
|
assert_eq!(params.val, "X");
|
||||||
|
@ -723,7 +723,7 @@ mod tests {
|
||||||
assert_eq!(params, "X");
|
assert_eq!(params, "X");
|
||||||
|
|
||||||
let mut path = Path::new("/%2F");
|
let mut path = Path::new("/%2F");
|
||||||
rdef.capture_match_info(&mut path);
|
rdef.resolve_path_if_match(&mut path);
|
||||||
let de = PathDeserializer::new(&path);
|
let de = PathDeserializer::new(&path);
|
||||||
assert!(<Params<'_> as serde::Deserialize>::deserialize(de).is_err());
|
assert!(<Params<'_> as serde::Deserialize>::deserialize(de).is_err());
|
||||||
let de = PathDeserializer::new(&path);
|
let de = PathDeserializer::new(&path);
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
use std::{
|
use std::{
|
||||||
borrow::Cow,
|
borrow::Cow,
|
||||||
|
mem,
|
||||||
ops::{DerefMut, Index},
|
ops::{DerefMut, Index},
|
||||||
};
|
};
|
||||||
|
|
||||||
use serde::{de, Deserialize};
|
use serde::{de, Deserialize};
|
||||||
|
|
||||||
use crate::{de::PathDeserializer, Resource, ResourcePath};
|
use crate::{de::PathDeserializer, resource::ResourceMatchInfo, Resource, ResourcePath};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub(crate) enum PathItem {
|
pub enum PathItem {
|
||||||
Static(Cow<'static, str>),
|
Static(Cow<'static, str>),
|
||||||
Segment(u16, u16),
|
Segment(u16, u16),
|
||||||
}
|
}
|
||||||
|
@ -106,6 +107,27 @@ impl<T: ResourcePath> Path<T> {
|
||||||
self.skip += n;
|
self.skip += n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Post-processes the path to resolve dynamic segments, if any, and determines the character offset to skip.
|
||||||
|
pub fn resolve(&mut self, match_info: ResourceMatchInfo<'_>) {
|
||||||
|
match match_info {
|
||||||
|
ResourceMatchInfo::Static { matched_len } => {
|
||||||
|
self.resource_path().skip(matched_len);
|
||||||
|
}
|
||||||
|
ResourceMatchInfo::Dynamic {
|
||||||
|
matched_len,
|
||||||
|
matched_vars,
|
||||||
|
mut segments,
|
||||||
|
} => {
|
||||||
|
for i in 0..matched_vars.len() {
|
||||||
|
self.resource_path()
|
||||||
|
.add(matched_vars[i], mem::take(&mut segments[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
self.resource_path().skip(matched_len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn add(&mut self, name: impl Into<Cow<'static, str>>, value: PathItem) {
|
pub(crate) fn add(&mut self, name: impl Into<Cow<'static, str>>, value: PathItem) {
|
||||||
match value {
|
match value {
|
||||||
PathItem::Static(seg) => self.segments.push((name.into(), PathItem::Static(seg))),
|
PathItem::Static(seg) => self.segments.push((name.into(), PathItem::Static(seg))),
|
||||||
|
@ -260,4 +282,49 @@ mod tests {
|
||||||
let foo = RefCell::new(foo);
|
let foo = RefCell::new(foo);
|
||||||
let _ = foo.borrow_mut().resource_path();
|
let _ = foo.borrow_mut().resource_path();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_dynamic_path_resolve() {
|
||||||
|
let mut path = Path::new("/foo/{var1}/{var2}");
|
||||||
|
|
||||||
|
assert_eq!(0, path.segments.len());
|
||||||
|
assert_eq!(0, path.skip);
|
||||||
|
|
||||||
|
let mut segments = <[PathItem; 16]>::default();
|
||||||
|
segments[0] = PathItem::Static(Cow::Borrowed("foo"));
|
||||||
|
segments[1] = PathItem::Segment(2, 5);
|
||||||
|
let match_info = ResourceMatchInfo::Dynamic {
|
||||||
|
matched_len: 3,
|
||||||
|
matched_vars: &["var1", "var2"],
|
||||||
|
segments,
|
||||||
|
};
|
||||||
|
|
||||||
|
path.resolve(match_info);
|
||||||
|
|
||||||
|
assert_eq!(2, path.segments.len());
|
||||||
|
assert_eq!(3, path.skip);
|
||||||
|
|
||||||
|
let (name, value) = path.segments.get(0).unwrap();
|
||||||
|
assert_eq!(name.as_ref(), "var1");
|
||||||
|
assert!(matches!(value, PathItem::Static(Cow::Borrowed("foo"))));
|
||||||
|
|
||||||
|
let (name, value) = path.segments.get(1).unwrap();
|
||||||
|
assert_eq!(name.as_ref(), "var2");
|
||||||
|
assert!(matches!(value, PathItem::Segment(2, 5)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_static_path_resolve() {
|
||||||
|
let mut path = Path::new("/foo");
|
||||||
|
|
||||||
|
assert_eq!(0, path.segments.len());
|
||||||
|
assert_eq!(0, path.skip);
|
||||||
|
|
||||||
|
let match_info = ResourceMatchInfo::Static { matched_len: 2 };
|
||||||
|
|
||||||
|
path.resolve(match_info);
|
||||||
|
|
||||||
|
assert_eq!(0, path.segments.len());
|
||||||
|
assert_eq!(2, path.skip);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@ use std::{
|
||||||
borrow::{Borrow, Cow},
|
borrow::{Borrow, Cow},
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
hash::{BuildHasher, Hash, Hasher},
|
hash::{BuildHasher, Hash, Hasher},
|
||||||
mem,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use tracing::error;
|
use tracing::error;
|
||||||
|
@ -10,7 +9,7 @@ use tracing::error;
|
||||||
use crate::{
|
use crate::{
|
||||||
path::PathItem,
|
path::PathItem,
|
||||||
regex_set::{escape, Regex, RegexSet},
|
regex_set::{escape, Regex, RegexSet},
|
||||||
IntoPatterns, Patterns, Resource, ResourcePath,
|
IntoPatterns, Patterns, Resource,
|
||||||
};
|
};
|
||||||
|
|
||||||
const MAX_DYNAMIC_SEGMENTS: usize = 16;
|
const MAX_DYNAMIC_SEGMENTS: usize = 16;
|
||||||
|
@ -80,8 +79,7 @@ const REGEX_FLAGS: &str = "(?s-m)";
|
||||||
/// `/rust-is-hard`.
|
/// `/rust-is-hard`.
|
||||||
///
|
///
|
||||||
/// For information on capturing segment values from paths or other custom resource types,
|
/// For information on capturing segment values from paths or other custom resource types,
|
||||||
/// see [`capture_match_info`][Self::capture_match_info]
|
/// see [`capture_match_info`][Self::capture_match_info].
|
||||||
/// and [`capture_match_info_fn`][Self::capture_match_info_fn].
|
|
||||||
///
|
///
|
||||||
/// A resource definition can contain at most 16 dynamic segments.
|
/// A resource definition can contain at most 16 dynamic segments.
|
||||||
///
|
///
|
||||||
|
@ -96,7 +94,7 @@ const REGEX_FLAGS: &str = "(?s-m)";
|
||||||
/// assert!(!resource.is_match("/user/"));
|
/// assert!(!resource.is_match("/user/"));
|
||||||
///
|
///
|
||||||
/// let mut path = Path::new("/user/123");
|
/// let mut path = Path::new("/user/123");
|
||||||
/// resource.capture_match_info(&mut path);
|
/// resource.resolve_path_if_match(&mut path);
|
||||||
/// assert_eq!(path.get("id").unwrap(), "123");
|
/// assert_eq!(path.get("id").unwrap(), "123");
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
@ -171,7 +169,7 @@ const REGEX_FLAGS: &str = "(?s-m)";
|
||||||
/// assert!(resource.is_match("/blob/HEAD/README.md"));
|
/// assert!(resource.is_match("/blob/HEAD/README.md"));
|
||||||
///
|
///
|
||||||
/// let mut path = Path::new("/blob/main/LICENSE");
|
/// let mut path = Path::new("/blob/main/LICENSE");
|
||||||
/// resource.capture_match_info(&mut path);
|
/// resource.resolve_path_if_match(&mut path);
|
||||||
/// assert_eq!(path.get("tail").unwrap(), "main/LICENSE");
|
/// assert_eq!(path.get("tail").unwrap(), "main/LICENSE");
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
@ -249,6 +247,18 @@ enum PatternType {
|
||||||
DynamicSet(RegexSet, Vec<(Regex, Vec<&'static str>)>),
|
DynamicSet(RegexSet, Vec<(Regex, Vec<&'static str>)>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Holds metadata and parameters used during path resolution.
|
||||||
|
pub enum ResourceMatchInfo<'a> {
|
||||||
|
Static {
|
||||||
|
matched_len: u16,
|
||||||
|
},
|
||||||
|
Dynamic {
|
||||||
|
matched_len: u16,
|
||||||
|
matched_vars: &'a [&'static str],
|
||||||
|
segments: [PathItem; MAX_DYNAMIC_SEGMENTS],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
impl ResourceDef {
|
impl ResourceDef {
|
||||||
/// Constructs a new resource definition from patterns.
|
/// Constructs a new resource definition from patterns.
|
||||||
///
|
///
|
||||||
|
@ -623,18 +633,24 @@ impl ResourceDef {
|
||||||
///
|
///
|
||||||
/// let resource = ResourceDef::prefix("/user/{id}");
|
/// let resource = ResourceDef::prefix("/user/{id}");
|
||||||
/// let mut path = Path::new("/user/123/stars");
|
/// let mut path = Path::new("/user/123/stars");
|
||||||
/// assert!(resource.capture_match_info(&mut path));
|
/// assert!(resource.resolve_path_if_match(&mut path));
|
||||||
/// assert_eq!(path.get("id").unwrap(), "123");
|
/// assert_eq!(path.get("id").unwrap(), "123");
|
||||||
/// assert_eq!(path.unprocessed(), "/stars");
|
/// assert_eq!(path.unprocessed(), "/stars");
|
||||||
///
|
///
|
||||||
/// let resource = ResourceDef::new("/blob/{path}*");
|
/// let resource = ResourceDef::new("/blob/{path}*");
|
||||||
/// let mut path = Path::new("/blob/HEAD/Cargo.toml");
|
/// let mut path = Path::new("/blob/HEAD/Cargo.toml");
|
||||||
/// assert!(resource.capture_match_info(&mut path));
|
/// assert!(resource.resolve_path_if_match(&mut path));
|
||||||
/// assert_eq!(path.get("path").unwrap(), "HEAD/Cargo.toml");
|
/// assert_eq!(path.get("path").unwrap(), "HEAD/Cargo.toml");
|
||||||
/// assert_eq!(path.unprocessed(), "");
|
/// assert_eq!(path.unprocessed(), "");
|
||||||
/// ```
|
/// ```
|
||||||
pub fn capture_match_info<R: Resource>(&self, resource: &mut R) -> bool {
|
pub fn resolve_path_if_match<R: Resource>(&self, resource: &mut R) -> bool {
|
||||||
self.capture_match_info_fn(resource, |_| true)
|
match self.capture_match_info(resource) {
|
||||||
|
None => false,
|
||||||
|
Some(match_info) => {
|
||||||
|
resource.resource_path().resolve(match_info);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Collects dynamic segment values into `resource` after matching paths and executing
|
/// Collects dynamic segment values into `resource` after matching paths and executing
|
||||||
|
@ -644,21 +660,22 @@ impl ResourceDef {
|
||||||
/// This is useful if you want to conditionally match on some non-path related aspect of the
|
/// This is useful if you want to conditionally match on some non-path related aspect of the
|
||||||
/// resource type.
|
/// resource type.
|
||||||
///
|
///
|
||||||
/// Returns `true` if resource path matches this resource definition _and_ satisfies the
|
/// Returns `ResourceMatchInfo` if the given resource path matches this resource definition,
|
||||||
/// given check function.
|
/// containing the information required to perform path resolution.
|
||||||
///
|
|
||||||
/// # Examples
|
/// # Examples
|
||||||
/// ```
|
/// ```
|
||||||
/// use actix_router::{Path, ResourceDef};
|
/// use actix_router::{Path, Resource, ResourceDef};
|
||||||
///
|
///
|
||||||
/// fn try_match(resource: &ResourceDef, path: &mut Path<&str>) -> bool {
|
/// fn try_match(resource: &ResourceDef, path: &mut Path<&str>) -> bool {
|
||||||
/// let admin_allowed = std::env::var("ADMIN_ALLOWED").is_ok();
|
|
||||||
///
|
///
|
||||||
/// resource.capture_match_info_fn(
|
/// let match_info = resource.capture_match_info(path);
|
||||||
/// path,
|
/// match match_info{
|
||||||
/// // when env var is not set, reject when path contains "admin"
|
/// None => {false}
|
||||||
/// |path| !(!admin_allowed && path.as_str().contains("admin")),
|
/// Some(match_info) => {
|
||||||
/// )
|
/// path.resource_path().resolve(match_info);
|
||||||
|
/// true
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// let resource = ResourceDef::prefix("/user/{id}");
|
/// let resource = ResourceDef::prefix("/user/{id}");
|
||||||
|
@ -669,85 +686,72 @@ impl ResourceDef {
|
||||||
/// assert_eq!(path.get("id").unwrap(), "james");
|
/// assert_eq!(path.get("id").unwrap(), "james");
|
||||||
/// assert_eq!(path.unprocessed(), "/stars");
|
/// assert_eq!(path.unprocessed(), "/stars");
|
||||||
///
|
///
|
||||||
/// // path matches but fails check function; no segments are collected
|
|
||||||
/// let mut path = Path::new("/user/admin/stars");
|
|
||||||
/// assert!(!try_match(&resource, &mut path));
|
|
||||||
/// assert_eq!(path.unprocessed(), "/user/admin/stars");
|
|
||||||
/// ```
|
/// ```
|
||||||
pub fn capture_match_info_fn<R, F>(&self, resource: &mut R, check_fn: F) -> bool
|
pub fn capture_match_info<R>(&self, resource: &mut R) -> Option<ResourceMatchInfo<'_>>
|
||||||
where
|
where
|
||||||
R: Resource,
|
R: Resource,
|
||||||
F: FnOnce(&R) -> bool,
|
|
||||||
{
|
{
|
||||||
let mut segments = <[PathItem; MAX_DYNAMIC_SEGMENTS]>::default();
|
|
||||||
let path = resource.resource_path();
|
let path = resource.resource_path();
|
||||||
let path_str = path.unprocessed();
|
let path_str = path.unprocessed();
|
||||||
|
match &self.pat_type {
|
||||||
let (matched_len, matched_vars) = match &self.pat_type {
|
|
||||||
PatternType::Static(pattern) => match self.static_match(pattern, path_str) {
|
PatternType::Static(pattern) => match self.static_match(pattern, path_str) {
|
||||||
Some(len) => (len, None),
|
Some(len) => Some(ResourceMatchInfo::Static {
|
||||||
None => return false,
|
matched_len: len as u16,
|
||||||
|
}),
|
||||||
|
None => return None,
|
||||||
},
|
},
|
||||||
|
|
||||||
PatternType::Dynamic(re, names) => {
|
PatternType::Dynamic(re, names) => {
|
||||||
let captures = match re.captures(path.unprocessed()) {
|
let captures = match re.captures(path_str) {
|
||||||
Some(captures) => captures,
|
Some(captures) => captures,
|
||||||
_ => return false,
|
_ => return None,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let mut segments = <[PathItem; MAX_DYNAMIC_SEGMENTS]>::default();
|
||||||
for (no, name) in names.iter().enumerate() {
|
for (no, name) in names.iter().enumerate() {
|
||||||
if let Some(m) = captures.name(name) {
|
if let Some(m) = captures.name(name) {
|
||||||
segments[no] = PathItem::Segment(m.start() as u16, m.end() as u16);
|
segments[no] = PathItem::Segment(m.start() as u16, m.end() as u16);
|
||||||
} else {
|
} else {
|
||||||
error!("Dynamic path match but not all segments found: {}", name);
|
error!("Dynamic path match but not all segments found: {}", name);
|
||||||
return false;
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(captures[1].len(), Some(names))
|
Some(ResourceMatchInfo::Dynamic {
|
||||||
|
matched_len: captures[1].len() as u16,
|
||||||
|
matched_vars: names,
|
||||||
|
segments,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
PatternType::DynamicSet(re, params) => {
|
PatternType::DynamicSet(re, params) => {
|
||||||
let path = path.unprocessed();
|
let (pattern, names) = match re.first_match_idx(path_str) {
|
||||||
let (pattern, names) = match re.first_match_idx(path) {
|
|
||||||
Some(idx) => ¶ms[idx],
|
Some(idx) => ¶ms[idx],
|
||||||
_ => return false,
|
_ => return None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let captures = match pattern.captures(path.path()) {
|
let captures = match pattern.captures(path_str) {
|
||||||
Some(captures) => captures,
|
Some(captures) => captures,
|
||||||
_ => return false,
|
_ => return None,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let mut segments = <[PathItem; MAX_DYNAMIC_SEGMENTS]>::default();
|
||||||
for (no, name) in names.iter().enumerate() {
|
for (no, name) in names.iter().enumerate() {
|
||||||
if let Some(m) = captures.name(name) {
|
if let Some(m) = captures.name(name) {
|
||||||
segments[no] = PathItem::Segment(m.start() as u16, m.end() as u16);
|
segments[no] = PathItem::Segment(m.start() as u16, m.end() as u16);
|
||||||
} else {
|
} else {
|
||||||
error!("Dynamic path match but not all segments found: {}", name);
|
error!("Dynamic path match but not all segments found: {}", name);
|
||||||
return false;
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(captures[1].len(), Some(names))
|
Some(ResourceMatchInfo::Dynamic {
|
||||||
}
|
matched_len: captures[1].len() as u16,
|
||||||
};
|
matched_vars: names,
|
||||||
|
segments,
|
||||||
if !check_fn(resource) {
|
})
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Modify `path` to skip matched part and store matched segments
|
|
||||||
let path = resource.resource_path();
|
|
||||||
|
|
||||||
if let Some(vars) = matched_vars {
|
|
||||||
for i in 0..vars.len() {
|
|
||||||
path.add(vars[i], mem::take(&mut segments[i]));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
path.skip(matched_len as u16);
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Assembles resource path using a closure that maps variable segment names to values.
|
/// Assembles resource path using a closure that maps variable segment names to values.
|
||||||
|
@ -1171,7 +1175,7 @@ mod tests {
|
||||||
assert!(!re.is_match("/name~"));
|
assert!(!re.is_match("/name~"));
|
||||||
|
|
||||||
let mut path = Path::new("/name");
|
let mut path = Path::new("/name");
|
||||||
assert!(re.capture_match_info(&mut path));
|
assert!(re.resolve_path_if_match(&mut path));
|
||||||
assert_eq!(path.unprocessed(), "");
|
assert_eq!(path.unprocessed(), "");
|
||||||
|
|
||||||
assert_eq!(re.find_match("/name"), Some(5));
|
assert_eq!(re.find_match("/name"), Some(5));
|
||||||
|
@ -1189,7 +1193,7 @@ mod tests {
|
||||||
assert!(!re.is_match("/user/profile/profile"));
|
assert!(!re.is_match("/user/profile/profile"));
|
||||||
|
|
||||||
let mut path = Path::new("/user/profile");
|
let mut path = Path::new("/user/profile");
|
||||||
assert!(re.capture_match_info(&mut path));
|
assert!(re.resolve_path_if_match(&mut path));
|
||||||
assert_eq!(path.unprocessed(), "");
|
assert_eq!(path.unprocessed(), "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1202,12 +1206,12 @@ mod tests {
|
||||||
assert!(!re.is_match("/user/2345/sdg"));
|
assert!(!re.is_match("/user/2345/sdg"));
|
||||||
|
|
||||||
let mut path = Path::new("/user/profile");
|
let mut path = Path::new("/user/profile");
|
||||||
assert!(re.capture_match_info(&mut path));
|
assert!(re.resolve_path_if_match(&mut path));
|
||||||
assert_eq!(path.get("id").unwrap(), "profile");
|
assert_eq!(path.get("id").unwrap(), "profile");
|
||||||
assert_eq!(path.unprocessed(), "");
|
assert_eq!(path.unprocessed(), "");
|
||||||
|
|
||||||
let mut path = Path::new("/user/1245125");
|
let mut path = Path::new("/user/1245125");
|
||||||
assert!(re.capture_match_info(&mut path));
|
assert!(re.resolve_path_if_match(&mut path));
|
||||||
assert_eq!(path.get("id").unwrap(), "1245125");
|
assert_eq!(path.get("id").unwrap(), "1245125");
|
||||||
assert_eq!(path.unprocessed(), "");
|
assert_eq!(path.unprocessed(), "");
|
||||||
|
|
||||||
|
@ -1217,7 +1221,7 @@ mod tests {
|
||||||
assert!(!re.is_match("/resource"));
|
assert!(!re.is_match("/resource"));
|
||||||
|
|
||||||
let mut path = Path::new("/v151/resource/adage32");
|
let mut path = Path::new("/v151/resource/adage32");
|
||||||
assert!(re.capture_match_info(&mut path));
|
assert!(re.resolve_path_if_match(&mut path));
|
||||||
assert_eq!(path.get("version").unwrap(), "151");
|
assert_eq!(path.get("version").unwrap(), "151");
|
||||||
assert_eq!(path.get("id").unwrap(), "adage32");
|
assert_eq!(path.get("id").unwrap(), "adage32");
|
||||||
assert_eq!(path.unprocessed(), "");
|
assert_eq!(path.unprocessed(), "");
|
||||||
|
@ -1229,7 +1233,7 @@ mod tests {
|
||||||
assert!(!re.is_match("/XXXXXX"));
|
assert!(!re.is_match("/XXXXXX"));
|
||||||
|
|
||||||
let mut path = Path::new("/012345");
|
let mut path = Path::new("/012345");
|
||||||
assert!(re.capture_match_info(&mut path));
|
assert!(re.resolve_path_if_match(&mut path));
|
||||||
assert_eq!(path.get("id").unwrap(), "012345");
|
assert_eq!(path.get("id").unwrap(), "012345");
|
||||||
assert_eq!(path.unprocessed(), "");
|
assert_eq!(path.unprocessed(), "");
|
||||||
}
|
}
|
||||||
|
@ -1249,12 +1253,12 @@ mod tests {
|
||||||
assert!(!re.is_match("/user/2345/sdg"));
|
assert!(!re.is_match("/user/2345/sdg"));
|
||||||
|
|
||||||
let mut path = Path::new("/user/profile");
|
let mut path = Path::new("/user/profile");
|
||||||
assert!(re.capture_match_info(&mut path));
|
assert!(re.resolve_path_if_match(&mut path));
|
||||||
assert_eq!(path.get("id").unwrap(), "profile");
|
assert_eq!(path.get("id").unwrap(), "profile");
|
||||||
assert_eq!(path.unprocessed(), "");
|
assert_eq!(path.unprocessed(), "");
|
||||||
|
|
||||||
let mut path = Path::new("/user/1245125");
|
let mut path = Path::new("/user/1245125");
|
||||||
assert!(re.capture_match_info(&mut path));
|
assert!(re.resolve_path_if_match(&mut path));
|
||||||
assert_eq!(path.get("id").unwrap(), "1245125");
|
assert_eq!(path.get("id").unwrap(), "1245125");
|
||||||
assert_eq!(path.unprocessed(), "");
|
assert_eq!(path.unprocessed(), "");
|
||||||
|
|
||||||
|
@ -1263,7 +1267,7 @@ mod tests {
|
||||||
assert!(!re.is_match("/resource"));
|
assert!(!re.is_match("/resource"));
|
||||||
|
|
||||||
let mut path = Path::new("/v151/resource/adage32");
|
let mut path = Path::new("/v151/resource/adage32");
|
||||||
assert!(re.capture_match_info(&mut path));
|
assert!(re.resolve_path_if_match(&mut path));
|
||||||
assert_eq!(path.get("version").unwrap(), "151");
|
assert_eq!(path.get("version").unwrap(), "151");
|
||||||
assert_eq!(path.get("id").unwrap(), "adage32");
|
assert_eq!(path.get("id").unwrap(), "adage32");
|
||||||
|
|
||||||
|
@ -1277,7 +1281,7 @@ mod tests {
|
||||||
assert!(!re.is_match("/static/a"));
|
assert!(!re.is_match("/static/a"));
|
||||||
|
|
||||||
let mut path = Path::new("/012345");
|
let mut path = Path::new("/012345");
|
||||||
assert!(re.capture_match_info(&mut path));
|
assert!(re.resolve_path_if_match(&mut path));
|
||||||
assert_eq!(path.get("id").unwrap(), "012345");
|
assert_eq!(path.get("id").unwrap(), "012345");
|
||||||
|
|
||||||
let re = ResourceDef::new([
|
let re = ResourceDef::new([
|
||||||
|
@ -1314,7 +1318,7 @@ mod tests {
|
||||||
assert_eq!(re.find_match("/12345"), None);
|
assert_eq!(re.find_match("/12345"), None);
|
||||||
|
|
||||||
let mut path = Path::new("/151/res");
|
let mut path = Path::new("/151/res");
|
||||||
assert!(re.capture_match_info(&mut path));
|
assert!(re.resolve_path_if_match(&mut path));
|
||||||
assert_eq!(path.get("id").unwrap(), "151");
|
assert_eq!(path.get("id").unwrap(), "151");
|
||||||
assert_eq!(path.unprocessed(), "/res");
|
assert_eq!(path.unprocessed(), "/res");
|
||||||
}
|
}
|
||||||
|
@ -1324,19 +1328,19 @@ mod tests {
|
||||||
let re = ResourceDef::new("/user/-{id}*");
|
let re = ResourceDef::new("/user/-{id}*");
|
||||||
|
|
||||||
let mut path = Path::new("/user/-profile");
|
let mut path = Path::new("/user/-profile");
|
||||||
assert!(re.capture_match_info(&mut path));
|
assert!(re.resolve_path_if_match(&mut path));
|
||||||
assert_eq!(path.get("id").unwrap(), "profile");
|
assert_eq!(path.get("id").unwrap(), "profile");
|
||||||
|
|
||||||
let mut path = Path::new("/user/-2345");
|
let mut path = Path::new("/user/-2345");
|
||||||
assert!(re.capture_match_info(&mut path));
|
assert!(re.resolve_path_if_match(&mut path));
|
||||||
assert_eq!(path.get("id").unwrap(), "2345");
|
assert_eq!(path.get("id").unwrap(), "2345");
|
||||||
|
|
||||||
let mut path = Path::new("/user/-2345/");
|
let mut path = Path::new("/user/-2345/");
|
||||||
assert!(re.capture_match_info(&mut path));
|
assert!(re.resolve_path_if_match(&mut path));
|
||||||
assert_eq!(path.get("id").unwrap(), "2345/");
|
assert_eq!(path.get("id").unwrap(), "2345/");
|
||||||
|
|
||||||
let mut path = Path::new("/user/-2345/sdg");
|
let mut path = Path::new("/user/-2345/sdg");
|
||||||
assert!(re.capture_match_info(&mut path));
|
assert!(re.resolve_path_if_match(&mut path));
|
||||||
assert_eq!(path.get("id").unwrap(), "2345/sdg");
|
assert_eq!(path.get("id").unwrap(), "2345/sdg");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1364,7 +1368,7 @@ mod tests {
|
||||||
let re = ResourceDef::new("/user/{id}/{tail}*");
|
let re = ResourceDef::new("/user/{id}/{tail}*");
|
||||||
assert!(!re.is_match("/user/2345"));
|
assert!(!re.is_match("/user/2345"));
|
||||||
let mut path = Path::new("/user/2345/sdg");
|
let mut path = Path::new("/user/2345/sdg");
|
||||||
assert!(re.capture_match_info(&mut path));
|
assert!(re.resolve_path_if_match(&mut path));
|
||||||
assert_eq!(path.get("id").unwrap(), "2345");
|
assert_eq!(path.get("id").unwrap(), "2345");
|
||||||
assert_eq!(path.get("tail").unwrap(), "sdg");
|
assert_eq!(path.get("tail").unwrap(), "sdg");
|
||||||
assert_eq!(path.unprocessed(), "");
|
assert_eq!(path.unprocessed(), "");
|
||||||
|
@ -1379,7 +1383,7 @@ mod tests {
|
||||||
|
|
||||||
let re = ResourceDef::new("/a{x}b/test/a{y}b");
|
let re = ResourceDef::new("/a{x}b/test/a{y}b");
|
||||||
let mut path = Path::new("/a\nb/test/a\nb");
|
let mut path = Path::new("/a\nb/test/a\nb");
|
||||||
assert!(re.capture_match_info(&mut path));
|
assert!(re.resolve_path_if_match(&mut path));
|
||||||
assert_eq!(path.get("x").unwrap(), "\n");
|
assert_eq!(path.get("x").unwrap(), "\n");
|
||||||
assert_eq!(path.get("y").unwrap(), "\n");
|
assert_eq!(path.get("y").unwrap(), "\n");
|
||||||
|
|
||||||
|
@ -1388,12 +1392,12 @@ mod tests {
|
||||||
|
|
||||||
let re = ResourceDef::new("/user/{id}*");
|
let re = ResourceDef::new("/user/{id}*");
|
||||||
let mut path = Path::new("/user/a\nb/a\nb");
|
let mut path = Path::new("/user/a\nb/a\nb");
|
||||||
assert!(re.capture_match_info(&mut path));
|
assert!(re.resolve_path_if_match(&mut path));
|
||||||
assert_eq!(path.get("id").unwrap(), "a\nb/a\nb");
|
assert_eq!(path.get("id").unwrap(), "a\nb/a\nb");
|
||||||
|
|
||||||
let re = ResourceDef::new("/user/{id:.*}");
|
let re = ResourceDef::new("/user/{id:.*}");
|
||||||
let mut path = Path::new("/user/a\nb/a\nb");
|
let mut path = Path::new("/user/a\nb/a\nb");
|
||||||
assert!(re.capture_match_info(&mut path));
|
assert!(re.resolve_path_if_match(&mut path));
|
||||||
assert_eq!(path.get("id").unwrap(), "a\nb/a\nb");
|
assert_eq!(path.get("id").unwrap(), "a\nb/a\nb");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1403,16 +1407,16 @@ mod tests {
|
||||||
let re = ResourceDef::new("/user/{id}/test");
|
let re = ResourceDef::new("/user/{id}/test");
|
||||||
|
|
||||||
let mut path = Path::new("/user/2345/test");
|
let mut path = Path::new("/user/2345/test");
|
||||||
assert!(re.capture_match_info(&mut path));
|
assert!(re.resolve_path_if_match(&mut path));
|
||||||
assert_eq!(path.get("id").unwrap(), "2345");
|
assert_eq!(path.get("id").unwrap(), "2345");
|
||||||
|
|
||||||
let mut path = Path::new("/user/qwe%25/test");
|
let mut path = Path::new("/user/qwe%25/test");
|
||||||
assert!(re.capture_match_info(&mut path));
|
assert!(re.resolve_path_if_match(&mut path));
|
||||||
assert_eq!(path.get("id").unwrap(), "qwe%25");
|
assert_eq!(path.get("id").unwrap(), "qwe%25");
|
||||||
|
|
||||||
let uri = http::Uri::try_from("/user/qwe%25/test").unwrap();
|
let uri = http::Uri::try_from("/user/qwe%25/test").unwrap();
|
||||||
let mut path = Path::new(uri);
|
let mut path = Path::new(uri);
|
||||||
assert!(re.capture_match_info(&mut path));
|
assert!(re.resolve_path_if_match(&mut path));
|
||||||
assert_eq!(path.get("id").unwrap(), "qwe%25");
|
assert_eq!(path.get("id").unwrap(), "qwe%25");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1429,11 +1433,11 @@ mod tests {
|
||||||
assert!(!re.is_match("/name~"));
|
assert!(!re.is_match("/name~"));
|
||||||
|
|
||||||
let mut path = Path::new("/name");
|
let mut path = Path::new("/name");
|
||||||
assert!(re.capture_match_info(&mut path));
|
assert!(re.resolve_path_if_match(&mut path));
|
||||||
assert_eq!(path.unprocessed(), "");
|
assert_eq!(path.unprocessed(), "");
|
||||||
|
|
||||||
let mut path = Path::new("/name/test");
|
let mut path = Path::new("/name/test");
|
||||||
assert!(re.capture_match_info(&mut path));
|
assert!(re.resolve_path_if_match(&mut path));
|
||||||
assert_eq!(path.unprocessed(), "/test");
|
assert_eq!(path.unprocessed(), "/test");
|
||||||
|
|
||||||
assert_eq!(re.find_match("/name"), Some(5));
|
assert_eq!(re.find_match("/name"), Some(5));
|
||||||
|
@ -1449,10 +1453,10 @@ mod tests {
|
||||||
assert!(!re.is_match("/name"));
|
assert!(!re.is_match("/name"));
|
||||||
|
|
||||||
let mut path = Path::new("/name/gs");
|
let mut path = Path::new("/name/gs");
|
||||||
assert!(!re.capture_match_info(&mut path));
|
assert!(!re.resolve_path_if_match(&mut path));
|
||||||
|
|
||||||
let mut path = Path::new("/name//gs");
|
let mut path = Path::new("/name//gs");
|
||||||
assert!(re.capture_match_info(&mut path));
|
assert!(re.resolve_path_if_match(&mut path));
|
||||||
assert_eq!(path.unprocessed(), "/gs");
|
assert_eq!(path.unprocessed(), "/gs");
|
||||||
|
|
||||||
let re = ResourceDef::root_prefix("name/");
|
let re = ResourceDef::root_prefix("name/");
|
||||||
|
@ -1462,7 +1466,7 @@ mod tests {
|
||||||
assert!(!re.is_match("/name"));
|
assert!(!re.is_match("/name"));
|
||||||
|
|
||||||
let mut path = Path::new("/name/gs");
|
let mut path = Path::new("/name/gs");
|
||||||
assert!(!re.capture_match_info(&mut path));
|
assert!(!re.resolve_path_if_match(&mut path));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1481,13 +1485,13 @@ mod tests {
|
||||||
assert_eq!(re.find_match(""), None);
|
assert_eq!(re.find_match(""), None);
|
||||||
|
|
||||||
let mut path = Path::new("/test2/");
|
let mut path = Path::new("/test2/");
|
||||||
assert!(re.capture_match_info(&mut path));
|
assert!(re.resolve_path_if_match(&mut path));
|
||||||
assert_eq!(&path["name"], "test2");
|
assert_eq!(&path["name"], "test2");
|
||||||
assert_eq!(&path[0], "test2");
|
assert_eq!(&path[0], "test2");
|
||||||
assert_eq!(path.unprocessed(), "/");
|
assert_eq!(path.unprocessed(), "/");
|
||||||
|
|
||||||
let mut path = Path::new("/test2/subpath1/subpath2/index.html");
|
let mut path = Path::new("/test2/subpath1/subpath2/index.html");
|
||||||
assert!(re.capture_match_info(&mut path));
|
assert!(re.resolve_path_if_match(&mut path));
|
||||||
assert_eq!(&path["name"], "test2");
|
assert_eq!(&path["name"], "test2");
|
||||||
assert_eq!(&path[0], "test2");
|
assert_eq!(&path[0], "test2");
|
||||||
assert_eq!(path.unprocessed(), "/subpath1/subpath2/index.html");
|
assert_eq!(path.unprocessed(), "/subpath1/subpath2/index.html");
|
||||||
|
@ -1543,7 +1547,7 @@ mod tests {
|
||||||
assert!(resource.resource_path_from_iter(
|
assert!(resource.resource_path_from_iter(
|
||||||
&mut s,
|
&mut s,
|
||||||
#[allow(clippy::useless_vec)]
|
#[allow(clippy::useless_vec)]
|
||||||
&mut vec!["item", "item2"].iter()
|
&mut vec!["item", "item2"].iter(),
|
||||||
));
|
));
|
||||||
assert_eq!(s, "/user/item/item2/");
|
assert_eq!(s, "/user/item/item2/");
|
||||||
}
|
}
|
||||||
|
@ -1561,22 +1565,22 @@ mod tests {
|
||||||
let resource = ResourceDef::new(["/user/{id}", "/profile/{id}"]);
|
let resource = ResourceDef::new(["/user/{id}", "/profile/{id}"]);
|
||||||
|
|
||||||
let mut path = Path::new("/user/123");
|
let mut path = Path::new("/user/123");
|
||||||
assert!(resource.capture_match_info(&mut path));
|
assert!(resource.resolve_path_if_match(&mut path));
|
||||||
assert!(path.get("id").is_some());
|
assert!(path.get("id").is_some());
|
||||||
|
|
||||||
let mut path = Path::new("/profile/123");
|
let mut path = Path::new("/profile/123");
|
||||||
assert!(resource.capture_match_info(&mut path));
|
assert!(resource.resolve_path_if_match(&mut path));
|
||||||
assert!(path.get("id").is_some());
|
assert!(path.get("id").is_some());
|
||||||
|
|
||||||
let resource = ResourceDef::new(["/user/{id}", "/profile/{uid}"]);
|
let resource = ResourceDef::new(["/user/{id}", "/profile/{uid}"]);
|
||||||
|
|
||||||
let mut path = Path::new("/user/123");
|
let mut path = Path::new("/user/123");
|
||||||
assert!(resource.capture_match_info(&mut path));
|
assert!(resource.resolve_path_if_match(&mut path));
|
||||||
assert!(path.get("id").is_some());
|
assert!(path.get("id").is_some());
|
||||||
assert!(path.get("uid").is_none());
|
assert!(path.get("uid").is_none());
|
||||||
|
|
||||||
let mut path = Path::new("/profile/123");
|
let mut path = Path::new("/profile/123");
|
||||||
assert!(resource.capture_match_info(&mut path));
|
assert!(resource.resolve_path_if_match(&mut path));
|
||||||
assert!(path.get("id").is_none());
|
assert!(path.get("id").is_none());
|
||||||
assert!(path.get("uid").is_some());
|
assert!(path.get("uid").is_some());
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,12 +13,16 @@ pub struct ResourceId(pub u16);
|
||||||
/// not required.
|
/// not required.
|
||||||
pub struct Router<T, U = ()> {
|
pub struct Router<T, U = ()> {
|
||||||
routes: Vec<(ResourceDef, T, U)>,
|
routes: Vec<(ResourceDef, T, U)>,
|
||||||
|
max_path_conflicts: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, U> Router<T, U> {
|
impl<T, U> Router<T, U> {
|
||||||
/// Constructs new `RouterBuilder` with empty route list.
|
/// Constructs new `RouterBuilder` with empty route list.
|
||||||
pub fn build() -> RouterBuilder<T, U> {
|
pub fn build() -> RouterBuilder<T, U> {
|
||||||
RouterBuilder { routes: Vec::new() }
|
RouterBuilder {
|
||||||
|
routes: Vec::new(),
|
||||||
|
path_conflicts: vec![],
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Finds the value in the router that matches a given [routing resource](Resource).
|
/// Finds the value in the router that matches a given [routing resource](Resource).
|
||||||
|
@ -46,14 +50,24 @@ impl<T, U> Router<T, U> {
|
||||||
/// the `check` closure is executed, passing the resource and each route's context data. If the
|
/// the `check` closure is executed, passing the resource and each route's context data. If the
|
||||||
/// closure returns true then the match result is stored into `resource` and a reference to
|
/// closure returns true then the match result is stored into `resource` and a reference to
|
||||||
/// the matched _value_ is returned.
|
/// the matched _value_ is returned.
|
||||||
pub fn recognize_fn<R, F>(&self, resource: &mut R, mut check: F) -> Option<(&T, ResourceId)>
|
pub fn recognize_fn<R, F>(&self, resource: &mut R, mut check_fn: F) -> Option<(&T, ResourceId)>
|
||||||
where
|
where
|
||||||
R: Resource,
|
R: Resource,
|
||||||
F: FnMut(&R, &U) -> bool,
|
F: FnMut(&R, &U) -> bool,
|
||||||
{
|
{
|
||||||
|
let mut next_resource_match_count = 1;
|
||||||
for (rdef, val, ctx) in self.routes.iter() {
|
for (rdef, val, ctx) in self.routes.iter() {
|
||||||
if rdef.capture_match_info_fn(resource, |res| check(res, ctx)) {
|
match rdef.capture_match_info(resource) {
|
||||||
return Some((val, ResourceId(rdef.id())));
|
None => {}
|
||||||
|
Some(match_info) => {
|
||||||
|
if check_fn(resource, ctx) {
|
||||||
|
resource.resource_path().resolve(match_info);
|
||||||
|
return Some((val, ResourceId(rdef.id())));
|
||||||
|
} else if next_resource_match_count == self.max_path_conflicts {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
next_resource_match_count += 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,15 +79,25 @@ impl<T, U> Router<T, U> {
|
||||||
pub fn recognize_mut_fn<R, F>(
|
pub fn recognize_mut_fn<R, F>(
|
||||||
&mut self,
|
&mut self,
|
||||||
resource: &mut R,
|
resource: &mut R,
|
||||||
mut check: F,
|
mut check_fn: F,
|
||||||
) -> Option<(&mut T, ResourceId)>
|
) -> Option<(&mut T, ResourceId)>
|
||||||
where
|
where
|
||||||
R: Resource,
|
R: Resource,
|
||||||
F: FnMut(&R, &U) -> bool,
|
F: FnMut(&R, &U) -> bool,
|
||||||
{
|
{
|
||||||
|
let mut matches = 0;
|
||||||
for (rdef, val, ctx) in self.routes.iter_mut() {
|
for (rdef, val, ctx) in self.routes.iter_mut() {
|
||||||
if rdef.capture_match_info_fn(resource, |res| check(res, ctx)) {
|
match rdef.capture_match_info(resource) {
|
||||||
return Some((val, ResourceId(rdef.id())));
|
None => {}
|
||||||
|
Some(match_info) => {
|
||||||
|
matches += 1;
|
||||||
|
if check_fn(resource, ctx) {
|
||||||
|
resource.resource_path().resolve(match_info);
|
||||||
|
return Some((val, ResourceId(rdef.id())));
|
||||||
|
} else if matches == self.max_path_conflicts {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,6 +108,7 @@ impl<T, U> Router<T, U> {
|
||||||
/// Builder for an ordered [routing](Router) list.
|
/// Builder for an ordered [routing](Router) list.
|
||||||
pub struct RouterBuilder<T, U = ()> {
|
pub struct RouterBuilder<T, U = ()> {
|
||||||
routes: Vec<(ResourceDef, T, U)>,
|
routes: Vec<(ResourceDef, T, U)>,
|
||||||
|
path_conflicts: Vec<(usize, u16)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, U> RouterBuilder<T, U> {
|
impl<T, U> RouterBuilder<T, U> {
|
||||||
|
@ -96,7 +121,18 @@ impl<T, U> RouterBuilder<T, U> {
|
||||||
val: T,
|
val: T,
|
||||||
ctx: U,
|
ctx: U,
|
||||||
) -> (&mut ResourceDef, &mut T, &mut U) {
|
) -> (&mut ResourceDef, &mut T, &mut U) {
|
||||||
|
if let Some((_, path_conflicts)) = self
|
||||||
|
.path_conflicts
|
||||||
|
.iter_mut()
|
||||||
|
.find(|(route_idx, _)| rdef.eq(&self.routes.get(*route_idx).unwrap().0))
|
||||||
|
{
|
||||||
|
*path_conflicts += 1;
|
||||||
|
} else {
|
||||||
|
self.path_conflicts.push((self.routes.len(), 1));
|
||||||
|
}
|
||||||
|
|
||||||
self.routes.push((rdef, val, ctx));
|
self.routes.push((rdef, val, ctx));
|
||||||
|
|
||||||
#[allow(clippy::map_identity)] // map is used to distribute &mut-ness to tuple elements
|
#[allow(clippy::map_identity)] // map is used to distribute &mut-ness to tuple elements
|
||||||
self.routes
|
self.routes
|
||||||
.last_mut()
|
.last_mut()
|
||||||
|
@ -106,8 +142,15 @@ impl<T, U> RouterBuilder<T, U> {
|
||||||
|
|
||||||
/// Finish configuration and create router instance.
|
/// Finish configuration and create router instance.
|
||||||
pub fn finish(self) -> Router<T, U> {
|
pub fn finish(self) -> Router<T, U> {
|
||||||
|
let max_path_conflicts = self
|
||||||
|
.path_conflicts
|
||||||
|
.iter()
|
||||||
|
.map(|(_, path_conflicts)| *path_conflicts)
|
||||||
|
.max()
|
||||||
|
.unwrap_or(1);
|
||||||
Router {
|
Router {
|
||||||
routes: self.routes,
|
routes: self.routes,
|
||||||
|
max_path_conflicts,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -280,4 +323,42 @@ mod tests {
|
||||||
assert_eq!(*h, 11);
|
assert_eq!(*h, 11);
|
||||||
assert_eq!(&path["val"], "ttt");
|
assert_eq!(&path["val"], "ttt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_max_path_conflicts() {
|
||||||
|
let mut router = Router::<usize>::build();
|
||||||
|
router.path("/test", 10).0.set_id(0);
|
||||||
|
router.path("/test/{val}", 11).0.set_id(1);
|
||||||
|
let router = router.finish();
|
||||||
|
|
||||||
|
assert_eq!(1, router.max_path_conflicts);
|
||||||
|
|
||||||
|
let mut router = Router::<usize>::build();
|
||||||
|
router.path("/test", 10).0.set_id(0);
|
||||||
|
router.path("/test", 11).0.set_id(1);
|
||||||
|
router.path("/test2", 11).0.set_id(1);
|
||||||
|
router.path("/test2", 11).0.set_id(1);
|
||||||
|
router.path("/test2", 11).0.set_id(1);
|
||||||
|
|
||||||
|
let router = router.finish();
|
||||||
|
|
||||||
|
assert_eq!(3, router.max_path_conflicts);
|
||||||
|
|
||||||
|
let failures_until_fn_builder = |mut num_failures: u16| {
|
||||||
|
move |_: &Path<&str>, _: &()| {
|
||||||
|
if num_failures == 0 {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
num_failures -= 1;
|
||||||
|
false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
assert!(router
|
||||||
|
.recognize_fn(&mut Path::new("/test2"), failures_until_fn_builder(3))
|
||||||
|
.is_none());
|
||||||
|
assert!(router
|
||||||
|
.recognize_fn(&mut Path::new("/test2"), failures_until_fn_builder(2))
|
||||||
|
.is_some());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,7 +75,7 @@ mod tests {
|
||||||
let re = ResourceDef::new(pattern);
|
let re = ResourceDef::new(pattern);
|
||||||
let uri = Uri::try_from(url.as_ref()).unwrap();
|
let uri = Uri::try_from(url.as_ref()).unwrap();
|
||||||
let mut path = Path::new(Url::new(uri));
|
let mut path = Path::new(Url::new(uri));
|
||||||
assert!(re.capture_match_info(&mut path));
|
assert!(re.resolve_path_if_match(&mut path));
|
||||||
path
|
path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -158,7 +158,7 @@ serde = "1.0"
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
serde_urlencoded = "0.7"
|
serde_urlencoded = "0.7"
|
||||||
smallvec = "1.6.1"
|
smallvec = "1.6.1"
|
||||||
socket2 = "0.5"
|
socket2 = "0.6"
|
||||||
time = { version = "0.3", default-features = false, features = ["formatting"] }
|
time = { version = "0.3", default-features = false, features = ["formatting"] }
|
||||||
tracing = "0.1.30"
|
tracing = "0.1.30"
|
||||||
url = "2.5.4"
|
url = "2.5.4"
|
||||||
|
|
|
@ -306,16 +306,16 @@ impl Service<ServiceRequest> for AppRouting {
|
||||||
actix_service::always_ready!();
|
actix_service::always_ready!();
|
||||||
|
|
||||||
fn call(&self, mut req: ServiceRequest) -> Self::Future {
|
fn call(&self, mut req: ServiceRequest) -> Self::Future {
|
||||||
let res = self.router.recognize_fn(&mut req, |req, guards| {
|
let guards_check_fn = |req: &ServiceRequest, guards: &Vec<Box<dyn Guard>>| {
|
||||||
let guard_ctx = req.guard_ctx();
|
let guard_ctx = req.guard_ctx();
|
||||||
guards.iter().all(|guard| guard.check(&guard_ctx))
|
guards.iter().all(|guard| guard.check(&guard_ctx))
|
||||||
});
|
};
|
||||||
|
|
||||||
|
let res = self.router.recognize_fn(&mut req, guards_check_fn);
|
||||||
if let Some((srv, _info)) = res {
|
if let Some((srv, _info)) = res {
|
||||||
srv.call(req)
|
return srv.call(req);
|
||||||
} else {
|
|
||||||
self.default.call(req)
|
|
||||||
}
|
}
|
||||||
|
self.default.call(req)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -510,16 +510,16 @@ impl Service<ServiceRequest> for ScopeService {
|
||||||
actix_service::always_ready!();
|
actix_service::always_ready!();
|
||||||
|
|
||||||
fn call(&self, mut req: ServiceRequest) -> Self::Future {
|
fn call(&self, mut req: ServiceRequest) -> Self::Future {
|
||||||
let res = self.router.recognize_fn(&mut req, |req, guards| {
|
let guards_check_fn = |req: &ServiceRequest, guards: &Vec<Box<dyn Guard>>| {
|
||||||
let guard_ctx = req.guard_ctx();
|
let guard_ctx = req.guard_ctx();
|
||||||
guards.iter().all(|guard| guard.check(&guard_ctx))
|
guards.iter().all(|guard| guard.check(&guard_ctx))
|
||||||
});
|
};
|
||||||
|
|
||||||
|
let res = self.router.recognize_fn(&mut req, guards_check_fn);
|
||||||
if let Some((srv, _info)) = res {
|
if let Some((srv, _info)) = res {
|
||||||
srv.call(req)
|
return srv.call(req);
|
||||||
} else {
|
|
||||||
self.default.call(req)
|
|
||||||
}
|
}
|
||||||
|
self.default.call(req)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -176,7 +176,7 @@ mod tests {
|
||||||
let resource = ResourceDef::new("/{value}/");
|
let resource = ResourceDef::new("/{value}/");
|
||||||
|
|
||||||
let mut req = TestRequest::with_uri("/32/").to_srv_request();
|
let mut req = TestRequest::with_uri("/32/").to_srv_request();
|
||||||
resource.capture_match_info(req.match_info_mut());
|
resource.resolve_path_if_match(req.match_info_mut());
|
||||||
|
|
||||||
let (req, mut pl) = req.into_parts();
|
let (req, mut pl) = req.into_parts();
|
||||||
assert_eq!(*Path::<i8>::from_request(&req, &mut pl).await.unwrap(), 32);
|
assert_eq!(*Path::<i8>::from_request(&req, &mut pl).await.unwrap(), 32);
|
||||||
|
@ -189,7 +189,7 @@ mod tests {
|
||||||
let resource = ResourceDef::new("/{key}/{value}/");
|
let resource = ResourceDef::new("/{key}/{value}/");
|
||||||
|
|
||||||
let mut req = TestRequest::with_uri("/name/user1/?id=test").to_srv_request();
|
let mut req = TestRequest::with_uri("/name/user1/?id=test").to_srv_request();
|
||||||
resource.capture_match_info(req.match_info_mut());
|
resource.resolve_path_if_match(req.match_info_mut());
|
||||||
|
|
||||||
let (req, mut pl) = req.into_parts();
|
let (req, mut pl) = req.into_parts();
|
||||||
let (Path(res),) = <(Path<(String, String)>,)>::from_request(&req, &mut pl)
|
let (Path(res),) = <(Path<(String, String)>,)>::from_request(&req, &mut pl)
|
||||||
|
@ -215,7 +215,7 @@ mod tests {
|
||||||
let mut req = TestRequest::with_uri("/name/user1/?id=test").to_srv_request();
|
let mut req = TestRequest::with_uri("/name/user1/?id=test").to_srv_request();
|
||||||
|
|
||||||
let resource = ResourceDef::new("/{key}/{value}/");
|
let resource = ResourceDef::new("/{key}/{value}/");
|
||||||
resource.capture_match_info(req.match_info_mut());
|
resource.resolve_path_if_match(req.match_info_mut());
|
||||||
|
|
||||||
let (req, mut pl) = req.into_parts();
|
let (req, mut pl) = req.into_parts();
|
||||||
let mut s = Path::<MyStruct>::from_request(&req, &mut pl).await.unwrap();
|
let mut s = Path::<MyStruct>::from_request(&req, &mut pl).await.unwrap();
|
||||||
|
@ -238,7 +238,7 @@ mod tests {
|
||||||
|
|
||||||
let mut req = TestRequest::with_uri("/name/32/").to_srv_request();
|
let mut req = TestRequest::with_uri("/name/32/").to_srv_request();
|
||||||
let resource = ResourceDef::new("/{key}/{value}/");
|
let resource = ResourceDef::new("/{key}/{value}/");
|
||||||
resource.capture_match_info(req.match_info_mut());
|
resource.resolve_path_if_match(req.match_info_mut());
|
||||||
|
|
||||||
let (req, mut pl) = req.into_parts();
|
let (req, mut pl) = req.into_parts();
|
||||||
let s = Path::<Test2>::from_request(&req, &mut pl).await.unwrap();
|
let s = Path::<Test2>::from_request(&req, &mut pl).await.unwrap();
|
||||||
|
@ -262,7 +262,7 @@ mod tests {
|
||||||
async fn paths_decoded() {
|
async fn paths_decoded() {
|
||||||
let resource = ResourceDef::new("/{key}/{value}");
|
let resource = ResourceDef::new("/{key}/{value}");
|
||||||
let mut req = TestRequest::with_uri("/na%2Bme/us%2Fer%254%32").to_srv_request();
|
let mut req = TestRequest::with_uri("/na%2Bme/us%2Fer%254%32").to_srv_request();
|
||||||
resource.capture_match_info(req.match_info_mut());
|
resource.resolve_path_if_match(req.match_info_mut());
|
||||||
|
|
||||||
let (req, mut pl) = req.into_parts();
|
let (req, mut pl) = req.into_parts();
|
||||||
let path_items = Path::<MyStruct>::from_request(&req, &mut pl).await.unwrap();
|
let path_items = Path::<MyStruct>::from_request(&req, &mut pl).await.unwrap();
|
||||||
|
|
Loading…
Reference in New Issue