mirror of
https://github.com/fafhrd91/actix-net
synced 2025-08-28 20:47:47 +02:00
Compare commits
5 Commits
bytestring
...
router-v0.
Author | SHA1 | Date | |
---|---|---|---|
|
a2a9d9764d | ||
|
bf0a9d2f6e | ||
|
119027f822 | ||
|
0fe8038d23 | ||
|
b599bc4a0c |
@@ -391,7 +391,7 @@ impl ServerBuilder {
|
|||||||
.await;
|
.await;
|
||||||
System::current().stop();
|
System::current().stop();
|
||||||
}
|
}
|
||||||
.boxed(),
|
.boxed(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
ready(())
|
ready(())
|
||||||
|
@@ -153,7 +153,7 @@ impl InternalServiceFactory for ConfiguredService {
|
|||||||
}
|
}
|
||||||
return Ok(res);
|
return Ok(res);
|
||||||
}
|
}
|
||||||
.boxed_local()
|
.boxed_local()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -280,6 +280,6 @@ where
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
.boxed_local()
|
.boxed_local()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -217,7 +217,7 @@ impl Worker {
|
|||||||
wrk.await
|
wrk.await
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
.boxed(),
|
.boxed(),
|
||||||
);
|
);
|
||||||
|
|
||||||
WorkerClient::new(idx, tx1, tx2, avail)
|
WorkerClient::new(idx, tx1, tx2, avail)
|
||||||
|
@@ -1,5 +1,12 @@
|
|||||||
# Changes
|
# Changes
|
||||||
|
|
||||||
|
## [1.0.1] - 2019-12-22
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
* `map_config()` and `unit_config()` accepts `IntoServiceFactory` type
|
||||||
|
|
||||||
|
|
||||||
## [1.0.0] - 2019-12-11
|
## [1.0.0] - 2019-12-11
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "actix-service"
|
name = "actix-service"
|
||||||
version = "1.0.0"
|
version = "1.0.1"
|
||||||
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
||||||
description = "Actix service"
|
description = "Actix service"
|
||||||
keywords = ["network", "framework", "async", "futures"]
|
keywords = ["network", "framework", "async", "futures"]
|
||||||
|
@@ -1,28 +1,30 @@
|
|||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use super::ServiceFactory;
|
use super::{IntoServiceFactory, ServiceFactory};
|
||||||
|
|
||||||
/// Adapt external config argument to a config for provided service factory
|
/// Adapt external config argument to a config for provided service factory
|
||||||
///
|
///
|
||||||
/// Note that this function consumes the receiving service factory and returns
|
/// Note that this function consumes the receiving service factory and returns
|
||||||
/// a wrapped version of it.
|
/// a wrapped version of it.
|
||||||
pub fn map_config<T, F, C>(factory: T, f: F) -> MapConfig<T, F, C>
|
pub fn map_config<T, U, F, C>(factory: U, f: F) -> MapConfig<T, F, C>
|
||||||
where
|
where
|
||||||
T: ServiceFactory,
|
T: ServiceFactory,
|
||||||
|
U: IntoServiceFactory<T>,
|
||||||
F: Fn(C) -> T::Config,
|
F: Fn(C) -> T::Config,
|
||||||
{
|
{
|
||||||
MapConfig::new(factory, f)
|
MapConfig::new(factory.into_factory(), f)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Replace config with unit
|
/// Replace config with unit
|
||||||
pub fn unit_config<T, C>(new_service: T) -> UnitConfig<T, C>
|
pub fn unit_config<T, U, C>(factory: U) -> UnitConfig<T, C>
|
||||||
where
|
where
|
||||||
T: ServiceFactory<Config = ()>,
|
T: ServiceFactory<Config = ()>,
|
||||||
|
U: IntoServiceFactory<T>,
|
||||||
{
|
{
|
||||||
UnitConfig::new(new_service)
|
UnitConfig::new(factory.into_factory())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `.map_config()` service combinator
|
/// `map_config()` adapter service factory
|
||||||
pub struct MapConfig<A, F, C> {
|
pub struct MapConfig<A, F, C> {
|
||||||
a: A,
|
a: A,
|
||||||
f: F,
|
f: F,
|
||||||
|
@@ -88,7 +88,7 @@ impl<T: AsyncRead + AsyncWrite + Unpin + 'static> Service for AcceptorService<T>
|
|||||||
let acc = acc;
|
let acc = acc;
|
||||||
tokio_openssl::accept(&acc, req).await
|
tokio_openssl::accept(&acc, req).await
|
||||||
}
|
}
|
||||||
.boxed_local(),
|
.boxed_local(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,11 @@
|
|||||||
# Changes
|
# Changes
|
||||||
|
|
||||||
|
## [0.2.1] - 2019-12-25
|
||||||
|
|
||||||
|
* Add `IntoPattern` trait
|
||||||
|
|
||||||
|
* Add multi-pattern resources
|
||||||
|
|
||||||
## [0.2.0] - 2019-12-07
|
## [0.2.0] - 2019-12-07
|
||||||
|
|
||||||
* Update http to 0.2
|
* Update http to 0.2
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "actix-router"
|
name = "actix-router"
|
||||||
version = "0.2.0"
|
version = "0.2.1"
|
||||||
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
||||||
description = "Path router"
|
description = "Path router"
|
||||||
keywords = ["actix"]
|
keywords = ["actix"]
|
||||||
@@ -8,9 +8,7 @@ homepage = "https://actix.rs"
|
|||||||
repository = "https://github.com/actix/actix-net.git"
|
repository = "https://github.com/actix/actix-net.git"
|
||||||
documentation = "https://docs.rs/actix-router/"
|
documentation = "https://docs.rs/actix-router/"
|
||||||
license = "MIT/Apache-2.0"
|
license = "MIT/Apache-2.0"
|
||||||
exclude = [".gitignore", ".travis.yml", ".cargo/config", "appveyor.yml"]
|
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
workspace = ".."
|
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
name = "actix_router"
|
name = "actix_router"
|
||||||
@@ -21,8 +19,8 @@ default = ["http"]
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
regex = "1.3.1"
|
regex = "1.3.1"
|
||||||
serde = "1.0.80"
|
serde = "1.0.104"
|
||||||
bytestring = "0.1.0"
|
bytestring = "0.1.2"
|
||||||
log = "0.4.8"
|
log = "0.4.8"
|
||||||
http = { version="0.2.0", optional=true }
|
http = { version="0.2.0", optional=true }
|
||||||
|
|
||||||
|
@@ -492,7 +492,7 @@ mod tests {
|
|||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct Id {
|
struct Id {
|
||||||
id: String,
|
_id: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
|
@@ -35,6 +35,90 @@ impl ResourcePath for bytestring::ByteString {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Helper trait for type that could be converted to path pattern
|
||||||
|
pub trait IntoPattern {
|
||||||
|
/// Signle patter
|
||||||
|
fn is_single(&self) -> bool;
|
||||||
|
|
||||||
|
fn patterns(&self) -> Vec<String>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoPattern for String {
|
||||||
|
fn is_single(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn patterns(&self) -> Vec<String> {
|
||||||
|
vec![self.clone()]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> IntoPattern for &'a str {
|
||||||
|
fn is_single(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn patterns(&self) -> Vec<String> {
|
||||||
|
vec![self.to_string()]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: AsRef<str>> IntoPattern for Vec<T> {
|
||||||
|
fn is_single(&self) -> bool {
|
||||||
|
self.len() == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn patterns(&self) -> Vec<String> {
|
||||||
|
self.into_iter().map(|v| v.as_ref().to_string()).collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! array_patterns (($tp:ty, $num:tt) => {
|
||||||
|
impl IntoPattern for [$tp; $num] {
|
||||||
|
fn is_single(&self) -> bool {
|
||||||
|
$num == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn patterns(&self) -> Vec<String> {
|
||||||
|
self.iter().map(|v| v.to_string()).collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
array_patterns!(&str, 1);
|
||||||
|
array_patterns!(&str, 2);
|
||||||
|
array_patterns!(&str, 3);
|
||||||
|
array_patterns!(&str, 4);
|
||||||
|
array_patterns!(&str, 5);
|
||||||
|
array_patterns!(&str, 6);
|
||||||
|
array_patterns!(&str, 7);
|
||||||
|
array_patterns!(&str, 8);
|
||||||
|
array_patterns!(&str, 9);
|
||||||
|
array_patterns!(&str, 10);
|
||||||
|
array_patterns!(&str, 11);
|
||||||
|
array_patterns!(&str, 12);
|
||||||
|
array_patterns!(&str, 13);
|
||||||
|
array_patterns!(&str, 14);
|
||||||
|
array_patterns!(&str, 15);
|
||||||
|
array_patterns!(&str, 16);
|
||||||
|
|
||||||
|
array_patterns!(String, 1);
|
||||||
|
array_patterns!(String, 2);
|
||||||
|
array_patterns!(String, 3);
|
||||||
|
array_patterns!(String, 4);
|
||||||
|
array_patterns!(String, 5);
|
||||||
|
array_patterns!(String, 6);
|
||||||
|
array_patterns!(String, 7);
|
||||||
|
array_patterns!(String, 8);
|
||||||
|
array_patterns!(String, 9);
|
||||||
|
array_patterns!(String, 10);
|
||||||
|
array_patterns!(String, 11);
|
||||||
|
array_patterns!(String, 12);
|
||||||
|
array_patterns!(String, 13);
|
||||||
|
array_patterns!(String, 14);
|
||||||
|
array_patterns!(String, 15);
|
||||||
|
array_patterns!(String, 16);
|
||||||
|
|
||||||
#[cfg(feature = "http")]
|
#[cfg(feature = "http")]
|
||||||
mod url;
|
mod url;
|
||||||
|
|
||||||
|
@@ -2,10 +2,10 @@ use std::cmp::min;
|
|||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use regex::{escape, Regex};
|
use regex::{escape, Regex, RegexSet};
|
||||||
|
|
||||||
use crate::path::{Path, PathItem};
|
use crate::path::{Path, PathItem};
|
||||||
use crate::{Resource, ResourcePath};
|
use crate::{IntoPattern, Resource, ResourcePath};
|
||||||
|
|
||||||
const MAX_DYNAMIC_SEGMENTS: usize = 16;
|
const MAX_DYNAMIC_SEGMENTS: usize = 16;
|
||||||
|
|
||||||
@@ -32,21 +32,53 @@ enum PatternType {
|
|||||||
Static(String),
|
Static(String),
|
||||||
Prefix(String),
|
Prefix(String),
|
||||||
Dynamic(Regex, Vec<Rc<String>>, usize),
|
Dynamic(Regex, Vec<Rc<String>>, usize),
|
||||||
|
DynamicSet(RegexSet, Vec<(Regex, Vec<Rc<String>>, usize)>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ResourceDef {
|
impl ResourceDef {
|
||||||
/// Parse path pattern and create new `Pattern` instance.
|
/// Parse path pattern and create new `Pattern` instance.
|
||||||
///
|
///
|
||||||
/// Panics if path pattern is wrong.
|
/// Panics if path pattern is malformed.
|
||||||
pub fn new(path: &str) -> Self {
|
pub fn new<T: IntoPattern>(path: T) -> Self {
|
||||||
ResourceDef::with_prefix(path, false)
|
if path.is_single() {
|
||||||
|
let patterns = path.patterns();
|
||||||
|
ResourceDef::with_prefix(&patterns[0], false)
|
||||||
|
} else {
|
||||||
|
let set = path.patterns();
|
||||||
|
let mut data = Vec::new();
|
||||||
|
let mut re_set = Vec::new();
|
||||||
|
|
||||||
|
for path in set {
|
||||||
|
let (pattern, _, _, len) = ResourceDef::parse(&path, false);
|
||||||
|
|
||||||
|
let re = match Regex::new(&pattern) {
|
||||||
|
Ok(re) => re,
|
||||||
|
Err(err) => panic!("Wrong path pattern: \"{}\" {}", path, err),
|
||||||
|
};
|
||||||
|
// actix creates one router per thread
|
||||||
|
let names: Vec<_> = re
|
||||||
|
.capture_names()
|
||||||
|
.filter_map(|name| name.map(|name| Rc::new(name.to_owned())))
|
||||||
|
.collect();
|
||||||
|
data.push((re, names, len));
|
||||||
|
re_set.push(pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
ResourceDef {
|
||||||
|
id: 0,
|
||||||
|
tp: PatternType::DynamicSet(RegexSet::new(re_set).unwrap(), data),
|
||||||
|
elements: Vec::new(),
|
||||||
|
name: String::new(),
|
||||||
|
pattern: "".to_owned(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse path pattern and create new `Pattern` instance.
|
/// Parse path pattern and create new `Pattern` instance.
|
||||||
///
|
///
|
||||||
/// Use `prefix` type instead of `static`.
|
/// Use `prefix` type instead of `static`.
|
||||||
///
|
///
|
||||||
/// Panics if path regex pattern is wrong.
|
/// Panics if path regex pattern is malformed.
|
||||||
pub fn prefix(path: &str) -> Self {
|
pub fn prefix(path: &str) -> Self {
|
||||||
ResourceDef::with_prefix(path, true)
|
ResourceDef::with_prefix(path, true)
|
||||||
}
|
}
|
||||||
@@ -57,7 +89,7 @@ impl ResourceDef {
|
|||||||
///
|
///
|
||||||
/// Use `prefix` type instead of `static`.
|
/// Use `prefix` type instead of `static`.
|
||||||
///
|
///
|
||||||
/// Panics if path regex pattern is wrong.
|
/// Panics if path regex pattern is malformed.
|
||||||
pub fn root_prefix(path: &str) -> Self {
|
pub fn root_prefix(path: &str) -> Self {
|
||||||
ResourceDef::with_prefix(&insert_slash(path), true)
|
ResourceDef::with_prefix(&insert_slash(path), true)
|
||||||
}
|
}
|
||||||
@@ -123,8 +155,9 @@ impl ResourceDef {
|
|||||||
pub fn is_match(&self, path: &str) -> bool {
|
pub fn is_match(&self, path: &str) -> bool {
|
||||||
match self.tp {
|
match self.tp {
|
||||||
PatternType::Static(ref s) => s == path,
|
PatternType::Static(ref s) => s == path,
|
||||||
PatternType::Dynamic(ref re, _, _) => re.is_match(path),
|
|
||||||
PatternType::Prefix(ref s) => path.starts_with(s),
|
PatternType::Prefix(ref s) => path.starts_with(s),
|
||||||
|
PatternType::Dynamic(ref re, _, _) => re.is_match(path),
|
||||||
|
PatternType::DynamicSet(ref re, _) => re.is_match(path),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,6 +209,30 @@ impl ResourceDef {
|
|||||||
};
|
};
|
||||||
Some(min(plen, len))
|
Some(min(plen, len))
|
||||||
}
|
}
|
||||||
|
PatternType::DynamicSet(ref re, ref params) => {
|
||||||
|
if let Some(idx) = re.matches(path).into_iter().next() {
|
||||||
|
let (ref pattern, _, len) = params[idx];
|
||||||
|
if let Some(captures) = pattern.captures(path) {
|
||||||
|
let mut pos = 0;
|
||||||
|
let mut passed = false;
|
||||||
|
for capture in captures.iter() {
|
||||||
|
if let Some(ref m) = capture {
|
||||||
|
if !passed {
|
||||||
|
passed = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
pos = m.end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(pos + len)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,6 +247,25 @@ impl ResourceDef {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
PatternType::Prefix(ref s) => {
|
||||||
|
let rpath = path.path();
|
||||||
|
let len = if s == rpath {
|
||||||
|
s.len()
|
||||||
|
} else if rpath.starts_with(s)
|
||||||
|
&& (s.ends_with('/') || rpath.split_at(s.len()).1.starts_with('/'))
|
||||||
|
{
|
||||||
|
if s.ends_with('/') {
|
||||||
|
s.len() - 1
|
||||||
|
} else {
|
||||||
|
s.len()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
let rpath_len = rpath.len();
|
||||||
|
path.skip(min(rpath_len, len) as u16);
|
||||||
|
true
|
||||||
|
}
|
||||||
PatternType::Dynamic(ref re, ref names, len) => {
|
PatternType::Dynamic(ref re, ref names, len) => {
|
||||||
let mut idx = 0;
|
let mut idx = 0;
|
||||||
let mut pos = 0;
|
let mut pos = 0;
|
||||||
@@ -219,24 +295,40 @@ impl ResourceDef {
|
|||||||
path.skip((pos + len) as u16);
|
path.skip((pos + len) as u16);
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
PatternType::Prefix(ref s) => {
|
PatternType::DynamicSet(ref re, ref params) => {
|
||||||
let rpath = path.path();
|
if let Some(idx) = re.matches(path.path()).into_iter().next() {
|
||||||
let len = if s == rpath {
|
let (ref pattern, ref names, len) = params[idx];
|
||||||
s.len()
|
let mut idx = 0;
|
||||||
} else if rpath.starts_with(s)
|
let mut pos = 0;
|
||||||
&& (s.ends_with('/') || rpath.split_at(s.len()).1.starts_with('/'))
|
let mut segments: [PathItem; MAX_DYNAMIC_SEGMENTS] =
|
||||||
{
|
[PathItem::Static(""); MAX_DYNAMIC_SEGMENTS];
|
||||||
if s.ends_with('/') {
|
|
||||||
s.len() - 1
|
if let Some(captures) = pattern.captures(path.path()) {
|
||||||
|
for (no, name) in names.iter().enumerate() {
|
||||||
|
if let Some(m) = captures.name(&name) {
|
||||||
|
idx += 1;
|
||||||
|
pos = m.end();
|
||||||
|
segments[no] =
|
||||||
|
PathItem::Segment(m.start() as u16, m.end() as u16);
|
||||||
|
} else {
|
||||||
|
log::error!(
|
||||||
|
"Dynamic path match but not all segments found: {}",
|
||||||
|
name
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
s.len()
|
return false;
|
||||||
}
|
}
|
||||||
|
for idx in 0..idx {
|
||||||
|
path.add(names[idx].clone(), segments[idx]);
|
||||||
|
}
|
||||||
|
path.skip((pos + len) as u16);
|
||||||
|
true
|
||||||
} else {
|
} else {
|
||||||
return false;
|
false
|
||||||
};
|
}
|
||||||
let rpath_len = rpath.len();
|
|
||||||
path.skip(min(rpath_len, len) as u16);
|
|
||||||
true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -263,6 +355,30 @@ impl ResourceDef {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
PatternType::Prefix(ref s) => {
|
||||||
|
let len = {
|
||||||
|
let rpath = res.resource_path().path();
|
||||||
|
if s == rpath {
|
||||||
|
s.len()
|
||||||
|
} else if rpath.starts_with(s)
|
||||||
|
&& (s.ends_with('/') || rpath.split_at(s.len()).1.starts_with('/'))
|
||||||
|
{
|
||||||
|
if s.ends_with('/') {
|
||||||
|
s.len() - 1
|
||||||
|
} else {
|
||||||
|
s.len()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if !check(res, user_data) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let path = res.resource_path();
|
||||||
|
path.skip(min(path.path().len(), len) as u16);
|
||||||
|
true
|
||||||
|
}
|
||||||
PatternType::Dynamic(ref re, ref names, len) => {
|
PatternType::Dynamic(ref re, ref names, len) => {
|
||||||
let mut idx = 0;
|
let mut idx = 0;
|
||||||
let mut pos = 0;
|
let mut pos = 0;
|
||||||
@@ -298,29 +414,47 @@ impl ResourceDef {
|
|||||||
path.skip((pos + len) as u16);
|
path.skip((pos + len) as u16);
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
PatternType::Prefix(ref s) => {
|
PatternType::DynamicSet(ref re, ref params) => {
|
||||||
let len = {
|
let path = res.resource_path().path();
|
||||||
let rpath = res.resource_path().path();
|
if let Some(idx) = re.matches(path).into_iter().next() {
|
||||||
if s == rpath {
|
let (ref pattern, ref names, len) = params[idx];
|
||||||
s.len()
|
let mut idx = 0;
|
||||||
} else if rpath.starts_with(s)
|
let mut pos = 0;
|
||||||
&& (s.ends_with('/') || rpath.split_at(s.len()).1.starts_with('/'))
|
let mut segments: [PathItem; MAX_DYNAMIC_SEGMENTS] =
|
||||||
{
|
[PathItem::Static(""); MAX_DYNAMIC_SEGMENTS];
|
||||||
if s.ends_with('/') {
|
|
||||||
s.len() - 1
|
if let Some(captures) = pattern.captures(path) {
|
||||||
} else {
|
for (no, name) in names.iter().enumerate() {
|
||||||
s.len()
|
if let Some(m) = captures.name(&name) {
|
||||||
|
idx += 1;
|
||||||
|
pos = m.end();
|
||||||
|
segments[no] =
|
||||||
|
PathItem::Segment(m.start() as u16, m.end() as u16);
|
||||||
|
} else {
|
||||||
|
log::error!(
|
||||||
|
"Dynamic path match but not all segments found: {}",
|
||||||
|
name
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
if !check(res, user_data) {
|
if !check(res, user_data) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let path = res.resource_path();
|
||||||
|
for idx in 0..idx {
|
||||||
|
path.add(names[idx].clone(), segments[idx]);
|
||||||
|
}
|
||||||
|
path.skip((pos + len) as u16);
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
}
|
}
|
||||||
let path = res.resource_path();
|
|
||||||
path.skip(min(path.path().len(), len) as u16);
|
|
||||||
true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -348,7 +482,10 @@ impl ResourceDef {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
PatternType::DynamicSet(..) => {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -476,7 +613,7 @@ impl<'a> From<&'a str> for ResourceDef {
|
|||||||
|
|
||||||
impl From<String> for ResourceDef {
|
impl From<String> for ResourceDef {
|
||||||
fn from(path: String) -> ResourceDef {
|
fn from(path: String) -> ResourceDef {
|
||||||
ResourceDef::new(&path)
|
ResourceDef::new(path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -558,6 +695,65 @@ mod tests {
|
|||||||
assert_eq!(path.get("id").unwrap(), "012345");
|
assert_eq!(path.get("id").unwrap(), "012345");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_dynamic_set() {
|
||||||
|
let re = ResourceDef::new(vec![
|
||||||
|
"/user/{id}",
|
||||||
|
"/v{version}/resource/{id}",
|
||||||
|
"/{id:[[:digit:]]{6}}",
|
||||||
|
]);
|
||||||
|
assert!(re.is_match("/user/profile"));
|
||||||
|
assert!(re.is_match("/user/2345"));
|
||||||
|
assert!(!re.is_match("/user/2345/"));
|
||||||
|
assert!(!re.is_match("/user/2345/sdg"));
|
||||||
|
|
||||||
|
let mut path = Path::new("/user/profile");
|
||||||
|
assert!(re.match_path(&mut path));
|
||||||
|
assert_eq!(path.get("id").unwrap(), "profile");
|
||||||
|
|
||||||
|
let mut path = Path::new("/user/1245125");
|
||||||
|
assert!(re.match_path(&mut path));
|
||||||
|
assert_eq!(path.get("id").unwrap(), "1245125");
|
||||||
|
|
||||||
|
assert!(re.is_match("/v1/resource/320120"));
|
||||||
|
assert!(!re.is_match("/v/resource/1"));
|
||||||
|
assert!(!re.is_match("/resource"));
|
||||||
|
|
||||||
|
let mut path = Path::new("/v151/resource/adahg32");
|
||||||
|
assert!(re.match_path(&mut path));
|
||||||
|
assert_eq!(path.get("version").unwrap(), "151");
|
||||||
|
assert_eq!(path.get("id").unwrap(), "adahg32");
|
||||||
|
|
||||||
|
assert!(re.is_match("/012345"));
|
||||||
|
assert!(!re.is_match("/012"));
|
||||||
|
assert!(!re.is_match("/01234567"));
|
||||||
|
assert!(!re.is_match("/XXXXXX"));
|
||||||
|
|
||||||
|
let mut path = Path::new("/012345");
|
||||||
|
assert!(re.match_path(&mut path));
|
||||||
|
assert_eq!(path.get("id").unwrap(), "012345");
|
||||||
|
|
||||||
|
let re = ResourceDef::new([
|
||||||
|
"/user/{id}",
|
||||||
|
"/v{version}/resource/{id}",
|
||||||
|
"/{id:[[:digit:]]{6}}",
|
||||||
|
]);
|
||||||
|
assert!(re.is_match("/user/profile"));
|
||||||
|
assert!(re.is_match("/user/2345"));
|
||||||
|
assert!(!re.is_match("/user/2345/"));
|
||||||
|
assert!(!re.is_match("/user/2345/sdg"));
|
||||||
|
|
||||||
|
let re = ResourceDef::new([
|
||||||
|
"/user/{id}".to_string(),
|
||||||
|
"/v{version}/resource/{id}".to_string(),
|
||||||
|
"/{id:[[:digit:]]{6}}".to_string(),
|
||||||
|
]);
|
||||||
|
assert!(re.is_match("/user/profile"));
|
||||||
|
assert!(re.is_match("/user/2345"));
|
||||||
|
assert!(!re.is_match("/user/2345/"));
|
||||||
|
assert!(!re.is_match("/user/2345/sdg"));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_tail() {
|
fn test_parse_tail() {
|
||||||
let re = ResourceDef::new("/user/-{id}*");
|
let re = ResourceDef::new("/user/-{id}*");
|
||||||
|
Reference in New Issue
Block a user