mirror of
https://github.com/actix/actix-extras.git
synced 2024-11-24 07:53:00 +01:00
HttpRequest::url_for is not working with scopes #429
This commit is contained in:
parent
3bd43090fb
commit
2071ea0532
@ -12,6 +12,8 @@
|
|||||||
|
|
||||||
* Gz streaming, use `flate2::write::GzDecoder` #228
|
* Gz streaming, use `flate2::write::GzDecoder` #228
|
||||||
|
|
||||||
|
* HttpRequest::url_for is not working with scopes #429
|
||||||
|
|
||||||
|
|
||||||
## [0.7.2] - 2018-07-26
|
## [0.7.2] - 2018-07-26
|
||||||
|
|
||||||
|
@ -140,7 +140,7 @@ where
|
|||||||
parts: Some(ApplicationParts {
|
parts: Some(ApplicationParts {
|
||||||
state,
|
state,
|
||||||
prefix: "".to_owned(),
|
prefix: "".to_owned(),
|
||||||
router: Router::new(),
|
router: Router::new(ResourceDef::prefix("")),
|
||||||
middlewares: Vec::new(),
|
middlewares: Vec::new(),
|
||||||
filters: Vec::new(),
|
filters: Vec::new(),
|
||||||
encoding: ContentEncoding::Auto,
|
encoding: ContentEncoding::Auto,
|
||||||
@ -198,6 +198,7 @@ where
|
|||||||
if !prefix.starts_with('/') {
|
if !prefix.starts_with('/') {
|
||||||
prefix.insert(0, '/')
|
prefix.insert(0, '/')
|
||||||
}
|
}
|
||||||
|
parts.router.set_prefix(&prefix);
|
||||||
parts.prefix = prefix;
|
parts.prefix = prefix;
|
||||||
}
|
}
|
||||||
self
|
self
|
||||||
|
@ -934,7 +934,7 @@ mod tests {
|
|||||||
fn test_request_extract() {
|
fn test_request_extract() {
|
||||||
let req = TestRequest::with_uri("/name/user1/?id=test").finish();
|
let req = TestRequest::with_uri("/name/user1/?id=test").finish();
|
||||||
|
|
||||||
let mut router = Router::<()>::new();
|
let mut router = Router::<()>::default();
|
||||||
router.register_resource(Resource::new(ResourceDef::new("/{key}/{value}/")));
|
router.register_resource(Resource::new(ResourceDef::new("/{key}/{value}/")));
|
||||||
let info = router.recognize(&req, &(), 0);
|
let info = router.recognize(&req, &(), 0);
|
||||||
let req = req.with_route_info(info);
|
let req = req.with_route_info(info);
|
||||||
@ -950,7 +950,7 @@ mod tests {
|
|||||||
let s = Query::<Id>::from_request(&req, &()).unwrap();
|
let s = Query::<Id>::from_request(&req, &()).unwrap();
|
||||||
assert_eq!(s.id, "test");
|
assert_eq!(s.id, "test");
|
||||||
|
|
||||||
let mut router = Router::<()>::new();
|
let mut router = Router::<()>::default();
|
||||||
router.register_resource(Resource::new(ResourceDef::new("/{key}/{value}/")));
|
router.register_resource(Resource::new(ResourceDef::new("/{key}/{value}/")));
|
||||||
let req = TestRequest::with_uri("/name/32/").finish();
|
let req = TestRequest::with_uri("/name/32/").finish();
|
||||||
let info = router.recognize(&req, &(), 0);
|
let info = router.recognize(&req, &(), 0);
|
||||||
@ -971,7 +971,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_extract_path_single() {
|
fn test_extract_path_single() {
|
||||||
let mut router = Router::<()>::new();
|
let mut router = Router::<()>::default();
|
||||||
router.register_resource(Resource::new(ResourceDef::new("/{value}/")));
|
router.register_resource(Resource::new(ResourceDef::new("/{value}/")));
|
||||||
|
|
||||||
let req = TestRequest::with_uri("/32/").finish();
|
let req = TestRequest::with_uri("/32/").finish();
|
||||||
@ -982,7 +982,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_tuple_extract() {
|
fn test_tuple_extract() {
|
||||||
let mut router = Router::<()>::new();
|
let mut router = Router::<()>::default();
|
||||||
router.register_resource(Resource::new(ResourceDef::new("/{key}/{value}/")));
|
router.register_resource(Resource::new(ResourceDef::new("/{key}/{value}/")));
|
||||||
|
|
||||||
let req = TestRequest::with_uri("/name/user1/?id=test").finish();
|
let req = TestRequest::with_uri("/name/user1/?id=test").finish();
|
||||||
|
@ -420,7 +420,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_request_match_info() {
|
fn test_request_match_info() {
|
||||||
let mut router = Router::<()>::new();
|
let mut router = Router::<()>::default();
|
||||||
router.register_resource(Resource::new(ResourceDef::new("/{key}/")));
|
router.register_resource(Resource::new(ResourceDef::new("/{key}/")));
|
||||||
|
|
||||||
let req = TestRequest::with_uri("/value/?id=test").finish();
|
let req = TestRequest::with_uri("/value/?id=test").finish();
|
||||||
@ -430,7 +430,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_url_for() {
|
fn test_url_for() {
|
||||||
let mut router = Router::<()>::new();
|
let mut router = Router::<()>::default();
|
||||||
let mut resource = Resource::new(ResourceDef::new("/user/{name}.{ext}"));
|
let mut resource = Resource::new(ResourceDef::new("/user/{name}.{ext}"));
|
||||||
resource.name("index");
|
resource.name("index");
|
||||||
router.register_resource(resource);
|
router.register_resource(resource);
|
||||||
@ -464,7 +464,8 @@ mod tests {
|
|||||||
fn test_url_for_with_prefix() {
|
fn test_url_for_with_prefix() {
|
||||||
let mut resource = Resource::new(ResourceDef::new("/user/{name}.html"));
|
let mut resource = Resource::new(ResourceDef::new("/user/{name}.html"));
|
||||||
resource.name("index");
|
resource.name("index");
|
||||||
let mut router = Router::<()>::new();
|
let mut router = Router::<()>::default();
|
||||||
|
router.set_prefix("/prefix");
|
||||||
router.register_resource(resource);
|
router.register_resource(resource);
|
||||||
|
|
||||||
let mut info = router.default_route_info();
|
let mut info = router.default_route_info();
|
||||||
@ -490,7 +491,8 @@ mod tests {
|
|||||||
fn test_url_for_static() {
|
fn test_url_for_static() {
|
||||||
let mut resource = Resource::new(ResourceDef::new("/index.html"));
|
let mut resource = Resource::new(ResourceDef::new("/index.html"));
|
||||||
resource.name("index");
|
resource.name("index");
|
||||||
let mut router = Router::<()>::new();
|
let mut router = Router::<()>::default();
|
||||||
|
router.set_prefix("/prefix");
|
||||||
router.register_resource(resource);
|
router.register_resource(resource);
|
||||||
|
|
||||||
let mut info = router.default_route_info();
|
let mut info = router.default_route_info();
|
||||||
@ -513,7 +515,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_url_for_external() {
|
fn test_url_for_external() {
|
||||||
let mut router = Router::<()>::new();
|
let mut router = Router::<()>::default();
|
||||||
router.register_external(
|
router.register_external(
|
||||||
"youtube",
|
"youtube",
|
||||||
ResourceDef::external("https://youtube.com/watch/{video_id}"),
|
ResourceDef::external("https://youtube.com/watch/{video_id}"),
|
||||||
|
297
src/router.rs
297
src/router.rs
@ -1,3 +1,4 @@
|
|||||||
|
use std::cell::RefCell;
|
||||||
use std::cmp::min;
|
use std::cmp::min;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
@ -111,9 +112,14 @@ impl ResourceInfo {
|
|||||||
U: IntoIterator<Item = I>,
|
U: IntoIterator<Item = I>,
|
||||||
I: AsRef<str>,
|
I: AsRef<str>,
|
||||||
{
|
{
|
||||||
if let Some(pattern) = self.rmap.named.get(name) {
|
let mut path = String::new();
|
||||||
let path =
|
let mut elements = elements.into_iter();
|
||||||
pattern.resource_path(elements, &req.path()[..(self.prefix as usize)])?;
|
|
||||||
|
if self
|
||||||
|
.rmap
|
||||||
|
.patterns_for(name, &mut path, &mut elements)?
|
||||||
|
.is_some()
|
||||||
|
{
|
||||||
if path.starts_with('/') {
|
if path.starts_with('/') {
|
||||||
let conn = req.connection_info();
|
let conn = req.connection_info();
|
||||||
Ok(Url::parse(&format!(
|
Ok(Url::parse(&format!(
|
||||||
@ -160,12 +166,15 @@ impl ResourceInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct ResourceMap {
|
pub(crate) struct ResourceMap {
|
||||||
|
root: ResourceDef,
|
||||||
|
parent: RefCell<Option<Rc<ResourceMap>>>,
|
||||||
named: HashMap<String, ResourceDef>,
|
named: HashMap<String, ResourceDef>,
|
||||||
patterns: Vec<(ResourceDef, Option<Rc<ResourceMap>>)>,
|
patterns: Vec<(ResourceDef, Option<Rc<ResourceMap>>)>,
|
||||||
|
nested: Vec<Rc<ResourceMap>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ResourceMap {
|
impl ResourceMap {
|
||||||
pub fn has_resource(&self, path: &str) -> bool {
|
fn has_resource(&self, path: &str) -> bool {
|
||||||
let path = if path.is_empty() { "/" } else { path };
|
let path = if path.is_empty() { "/" } else { path };
|
||||||
|
|
||||||
for (pattern, rmap) in &self.patterns {
|
for (pattern, rmap) in &self.patterns {
|
||||||
@ -179,20 +188,91 @@ impl ResourceMap {
|
|||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn patterns_for<U, I>(
|
||||||
|
&self, name: &str, path: &mut String, elements: &mut U,
|
||||||
|
) -> Result<Option<()>, UrlGenerationError>
|
||||||
|
where
|
||||||
|
U: Iterator<Item = I>,
|
||||||
|
I: AsRef<str>,
|
||||||
|
{
|
||||||
|
if self.pattern_for(name, path, elements)?.is_some() {
|
||||||
|
Ok(Some(()))
|
||||||
|
} else {
|
||||||
|
self.parent_pattern_for(name, path, elements)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pattern_for<U, I>(
|
||||||
|
&self, name: &str, path: &mut String, elements: &mut U,
|
||||||
|
) -> Result<Option<()>, UrlGenerationError>
|
||||||
|
where
|
||||||
|
U: Iterator<Item = I>,
|
||||||
|
I: AsRef<str>,
|
||||||
|
{
|
||||||
|
if let Some(pattern) = self.named.get(name) {
|
||||||
|
self.fill_root(path, elements)?;
|
||||||
|
pattern.resource_path(path, elements)?;
|
||||||
|
Ok(Some(()))
|
||||||
|
} else {
|
||||||
|
for rmap in &self.nested {
|
||||||
|
if rmap.pattern_for(name, path, elements)?.is_some() {
|
||||||
|
return Ok(Some(()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fill_root<U, I>(
|
||||||
|
&self, path: &mut String, elements: &mut U,
|
||||||
|
) -> Result<(), UrlGenerationError>
|
||||||
|
where
|
||||||
|
U: Iterator<Item = I>,
|
||||||
|
I: AsRef<str>,
|
||||||
|
{
|
||||||
|
if let Some(ref parent) = *self.parent.borrow() {
|
||||||
|
parent.fill_root(path, elements)?;
|
||||||
|
}
|
||||||
|
self.root.resource_path(path, elements)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parent_pattern_for<U, I>(
|
||||||
|
&self, name: &str, path: &mut String, elements: &mut U,
|
||||||
|
) -> Result<Option<()>, UrlGenerationError>
|
||||||
|
where
|
||||||
|
U: Iterator<Item = I>,
|
||||||
|
I: AsRef<str>,
|
||||||
|
{
|
||||||
|
if let Some(ref parent) = *self.parent.borrow() {
|
||||||
|
if let Some(pattern) = parent.named.get(name) {
|
||||||
|
self.fill_root(path, elements)?;
|
||||||
|
pattern.resource_path(path, elements)?;
|
||||||
|
Ok(Some(()))
|
||||||
|
} else {
|
||||||
|
parent.parent_pattern_for(name, path, elements)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: 'static> Default for Router<S> {
|
impl<S: 'static> Default for Router<S> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Router::new()
|
Router::new(ResourceDef::new(""))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: 'static> Router<S> {
|
impl<S: 'static> Router<S> {
|
||||||
pub(crate) fn new() -> Self {
|
pub(crate) fn new(root: ResourceDef) -> Self {
|
||||||
Router {
|
Router {
|
||||||
rmap: Rc::new(ResourceMap {
|
rmap: Rc::new(ResourceMap {
|
||||||
|
root,
|
||||||
|
parent: RefCell::new(None),
|
||||||
named: HashMap::new(),
|
named: HashMap::new(),
|
||||||
patterns: Vec::new(),
|
patterns: Vec::new(),
|
||||||
|
nested: Vec::new(),
|
||||||
}),
|
}),
|
||||||
resources: Vec::new(),
|
resources: Vec::new(),
|
||||||
patterns: Vec::new(),
|
patterns: Vec::new(),
|
||||||
@ -233,6 +313,10 @@ impl<S: 'static> Router<S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn set_prefix(&mut self, path: &str) {
|
||||||
|
Rc::get_mut(&mut self.rmap).unwrap().root = ResourceDef::new(path);
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn register_resource(&mut self, resource: Resource<S>) {
|
pub(crate) fn register_resource(&mut self, resource: Resource<S>) {
|
||||||
{
|
{
|
||||||
let rmap = Rc::get_mut(&mut self.rmap).unwrap();
|
let rmap = Rc::get_mut(&mut self.rmap).unwrap();
|
||||||
@ -258,6 +342,11 @@ impl<S: 'static> Router<S> {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.patterns
|
.patterns
|
||||||
.push((scope.rdef().clone(), Some(scope.router().rmap.clone())));
|
.push((scope.rdef().clone(), Some(scope.router().rmap.clone())));
|
||||||
|
Rc::get_mut(&mut self.rmap)
|
||||||
|
.unwrap()
|
||||||
|
.nested
|
||||||
|
.push(scope.router().rmap.clone());
|
||||||
|
|
||||||
let filters = scope.take_filters();
|
let filters = scope.take_filters();
|
||||||
self.patterns
|
self.patterns
|
||||||
.push(ResourcePattern::Scope(scope.rdef().clone(), filters));
|
.push(ResourcePattern::Scope(scope.rdef().clone(), filters));
|
||||||
@ -286,22 +375,25 @@ impl<S: 'static> Router<S> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn finish(&mut self) {
|
pub(crate) fn finish(&mut self) {
|
||||||
if let Some(ref default) = self.default {
|
for resource in &mut self.resources {
|
||||||
for resource in &mut self.resources {
|
match resource {
|
||||||
match resource {
|
ResourceItem::Resource(_) => (),
|
||||||
ResourceItem::Resource(_) => (),
|
ResourceItem::Scope(scope) => {
|
||||||
ResourceItem::Scope(scope) => {
|
if !scope.has_default_resource() {
|
||||||
if !scope.has_default_resource() {
|
if let Some(ref default) = self.default {
|
||||||
scope.default_resource(default.clone());
|
scope.default_resource(default.clone());
|
||||||
}
|
}
|
||||||
scope.finish()
|
|
||||||
}
|
}
|
||||||
ResourceItem::Handler(hnd) => {
|
*scope.router().rmap.parent.borrow_mut() = Some(self.rmap.clone());
|
||||||
if !hnd.has_default_resource() {
|
scope.finish();
|
||||||
|
}
|
||||||
|
ResourceItem::Handler(hnd) => {
|
||||||
|
if !hnd.has_default_resource() {
|
||||||
|
if let Some(ref default) = self.default {
|
||||||
hnd.default_resource(default.clone());
|
hnd.default_resource(default.clone());
|
||||||
}
|
}
|
||||||
hnd.finish()
|
|
||||||
}
|
}
|
||||||
|
hnd.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -459,35 +551,38 @@ pub struct ResourceDef {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ResourceDef {
|
impl ResourceDef {
|
||||||
/// Parse path pattern and create new `Resource` instance.
|
/// Parse path pattern and create new `ResourceDef` instance.
|
||||||
///
|
///
|
||||||
/// Panics if path pattern is wrong.
|
/// Panics if path pattern is wrong.
|
||||||
pub fn new(path: &str) -> Self {
|
pub fn new(path: &str) -> Self {
|
||||||
ResourceDef::with_prefix(path, if path.is_empty() { "" } else { "/" }, false)
|
ResourceDef::with_prefix(path, false, !path.is_empty())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse path pattern and create new `Resource` instance.
|
/// Parse path pattern and create new `ResourceDef` 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 wrong.
|
||||||
pub fn prefix(path: &str) -> Self {
|
pub fn prefix(path: &str) -> Self {
|
||||||
ResourceDef::with_prefix(path, "/", true)
|
ResourceDef::with_prefix(path, true, !path.is_empty())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct external resource
|
/// Construct external resource def
|
||||||
///
|
///
|
||||||
/// Panics if path pattern is wrong.
|
/// Panics if path pattern is wrong.
|
||||||
pub fn external(path: &str) -> Self {
|
pub fn external(path: &str) -> Self {
|
||||||
let mut resource = ResourceDef::with_prefix(path, "/", false);
|
let mut resource = ResourceDef::with_prefix(path, false, false);
|
||||||
resource.rtp = ResourceType::External;
|
resource.rtp = ResourceType::External;
|
||||||
resource
|
resource
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse path pattern and create new `Resource` instance with custom prefix
|
/// Parse path pattern and create new `ResourceDef` instance with custom prefix
|
||||||
pub fn with_prefix(path: &str, prefix: &str, for_prefix: bool) -> Self {
|
pub fn with_prefix(path: &str, for_prefix: bool, slash: bool) -> Self {
|
||||||
let (pattern, elements, is_dynamic, len) =
|
let mut path = path.to_owned();
|
||||||
ResourceDef::parse(path, prefix, for_prefix);
|
if slash && !path.starts_with('/') {
|
||||||
|
path.insert(0, '/');
|
||||||
|
}
|
||||||
|
let (pattern, elements, is_dynamic, len) = ResourceDef::parse(&path, for_prefix);
|
||||||
|
|
||||||
let tp = if is_dynamic {
|
let tp = if is_dynamic {
|
||||||
let re = match Regex::new(&pattern) {
|
let re = match Regex::new(&pattern) {
|
||||||
@ -705,23 +800,21 @@ impl ResourceDef {
|
|||||||
|
|
||||||
/// Build resource path.
|
/// Build resource path.
|
||||||
pub fn resource_path<U, I>(
|
pub fn resource_path<U, I>(
|
||||||
&self, elements: U, prefix: &str,
|
&self, path: &mut String, elements: &mut U,
|
||||||
) -> Result<String, UrlGenerationError>
|
) -> Result<(), UrlGenerationError>
|
||||||
where
|
where
|
||||||
U: IntoIterator<Item = I>,
|
U: Iterator<Item = I>,
|
||||||
I: AsRef<str>,
|
I: AsRef<str>,
|
||||||
{
|
{
|
||||||
let mut path = match self.tp {
|
match self.tp {
|
||||||
PatternType::Prefix(ref p) => p.to_owned(),
|
PatternType::Prefix(ref p) => path.push_str(p),
|
||||||
PatternType::Static(ref p) => p.to_owned(),
|
PatternType::Static(ref p) => path.push_str(p),
|
||||||
PatternType::Dynamic(..) => {
|
PatternType::Dynamic(..) => {
|
||||||
let mut path = String::new();
|
|
||||||
let mut iter = elements.into_iter();
|
|
||||||
for el in &self.elements {
|
for el in &self.elements {
|
||||||
match *el {
|
match *el {
|
||||||
PatternElement::Str(ref s) => path.push_str(s),
|
PatternElement::Str(ref s) => path.push_str(s),
|
||||||
PatternElement::Var(_) => {
|
PatternElement::Var(_) => {
|
||||||
if let Some(val) = iter.next() {
|
if let Some(val) = elements.next() {
|
||||||
path.push_str(val.as_ref())
|
path.push_str(val.as_ref())
|
||||||
} else {
|
} else {
|
||||||
return Err(UrlGenerationError::NotEnoughElements);
|
return Err(UrlGenerationError::NotEnoughElements);
|
||||||
@ -729,34 +822,18 @@ impl ResourceDef {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
path
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
Ok(())
|
||||||
if self.rtp != ResourceType::External {
|
|
||||||
if prefix.ends_with('/') {
|
|
||||||
if path.starts_with('/') {
|
|
||||||
path.insert_str(0, &prefix[..prefix.len() - 1]);
|
|
||||||
} else {
|
|
||||||
path.insert_str(0, prefix);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if !path.starts_with('/') {
|
|
||||||
path.insert(0, '/');
|
|
||||||
}
|
|
||||||
path.insert_str(0, prefix);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(path)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse(
|
fn parse(
|
||||||
pattern: &str, prefix: &str, for_prefix: bool,
|
pattern: &str, for_prefix: bool,
|
||||||
) -> (String, Vec<PatternElement>, bool, usize) {
|
) -> (String, Vec<PatternElement>, bool, usize) {
|
||||||
const DEFAULT_PATTERN: &str = "[^/]+";
|
const DEFAULT_PATTERN: &str = "[^/]+";
|
||||||
|
|
||||||
let mut re1 = String::from("^") + prefix;
|
let mut re1 = String::from("^");
|
||||||
let mut re2 = String::from(prefix);
|
let mut re2 = String::new();
|
||||||
let mut el = String::new();
|
let mut el = String::new();
|
||||||
let mut in_param = false;
|
let mut in_param = false;
|
||||||
let mut in_param_pattern = false;
|
let mut in_param_pattern = false;
|
||||||
@ -766,12 +843,7 @@ impl ResourceDef {
|
|||||||
let mut elems = Vec::new();
|
let mut elems = Vec::new();
|
||||||
let mut len = 0;
|
let mut len = 0;
|
||||||
|
|
||||||
for (index, ch) in pattern.chars().enumerate() {
|
for ch in pattern.chars() {
|
||||||
// All routes must have a leading slash so its optional to have one
|
|
||||||
if index == 0 && ch == '/' {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if in_param {
|
if in_param {
|
||||||
// In parameter segment: `{....}`
|
// In parameter segment: `{....}`
|
||||||
if ch == '}' {
|
if ch == '}' {
|
||||||
@ -846,7 +918,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_recognizer10() {
|
fn test_recognizer10() {
|
||||||
let mut router = Router::<()>::new();
|
let mut router = Router::<()>::default();
|
||||||
router.register_resource(Resource::new(ResourceDef::new("/name")));
|
router.register_resource(Resource::new(ResourceDef::new("/name")));
|
||||||
router.register_resource(Resource::new(ResourceDef::new("/name/{val}")));
|
router.register_resource(Resource::new(ResourceDef::new("/name/{val}")));
|
||||||
router.register_resource(Resource::new(ResourceDef::new(
|
router.register_resource(Resource::new(ResourceDef::new(
|
||||||
@ -858,7 +930,7 @@ mod tests {
|
|||||||
)));
|
)));
|
||||||
router.register_resource(Resource::new(ResourceDef::new("/v/{tail:.*}")));
|
router.register_resource(Resource::new(ResourceDef::new("/v/{tail:.*}")));
|
||||||
router.register_resource(Resource::new(ResourceDef::new("/test2/{test}.html")));
|
router.register_resource(Resource::new(ResourceDef::new("/test2/{test}.html")));
|
||||||
router.register_resource(Resource::new(ResourceDef::new("{test}/index.html")));
|
router.register_resource(Resource::new(ResourceDef::new("/{test}/index.html")));
|
||||||
|
|
||||||
let req = TestRequest::with_uri("/name").finish();
|
let req = TestRequest::with_uri("/name").finish();
|
||||||
let info = router.recognize(&req, &(), 0);
|
let info = router.recognize(&req, &(), 0);
|
||||||
@ -909,7 +981,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_recognizer_2() {
|
fn test_recognizer_2() {
|
||||||
let mut router = Router::<()>::new();
|
let mut router = Router::<()>::default();
|
||||||
router.register_resource(Resource::new(ResourceDef::new("/index.json")));
|
router.register_resource(Resource::new(ResourceDef::new("/index.json")));
|
||||||
router.register_resource(Resource::new(ResourceDef::new("/{source}.json")));
|
router.register_resource(Resource::new(ResourceDef::new("/{source}.json")));
|
||||||
|
|
||||||
@ -924,7 +996,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_recognizer_with_prefix() {
|
fn test_recognizer_with_prefix() {
|
||||||
let mut router = Router::<()>::new();
|
let mut router = Router::<()>::default();
|
||||||
router.register_resource(Resource::new(ResourceDef::new("/name")));
|
router.register_resource(Resource::new(ResourceDef::new("/name")));
|
||||||
router.register_resource(Resource::new(ResourceDef::new("/name/{val}")));
|
router.register_resource(Resource::new(ResourceDef::new("/name/{val}")));
|
||||||
|
|
||||||
@ -943,7 +1015,7 @@ mod tests {
|
|||||||
assert_eq!(&info.match_info()["val"], "value");
|
assert_eq!(&info.match_info()["val"], "value");
|
||||||
|
|
||||||
// same patterns
|
// same patterns
|
||||||
let mut router = Router::<()>::new();
|
let mut router = Router::<()>::default();
|
||||||
router.register_resource(Resource::new(ResourceDef::new("/name")));
|
router.register_resource(Resource::new(ResourceDef::new("/name")));
|
||||||
router.register_resource(Resource::new(ResourceDef::new("/name/{val}")));
|
router.register_resource(Resource::new(ResourceDef::new("/name/{val}")));
|
||||||
|
|
||||||
@ -1049,7 +1121,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_request_resource() {
|
fn test_request_resource() {
|
||||||
let mut router = Router::<()>::new();
|
let mut router = Router::<()>::default();
|
||||||
let mut resource = Resource::new(ResourceDef::new("/index.json"));
|
let mut resource = Resource::new(ResourceDef::new("/index.json"));
|
||||||
resource.name("r1");
|
resource.name("r1");
|
||||||
router.register_resource(resource);
|
router.register_resource(resource);
|
||||||
@ -1071,7 +1143,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_has_resource() {
|
fn test_has_resource() {
|
||||||
let mut router = Router::<()>::new();
|
let mut router = Router::<()>::default();
|
||||||
let scope = Scope::new("/test").resource("/name", |_| "done");
|
let scope = Scope::new("/test").resource("/name", |_| "done");
|
||||||
router.register_scope(scope);
|
router.register_scope(scope);
|
||||||
|
|
||||||
@ -1088,4 +1160,93 @@ mod tests {
|
|||||||
let info = router.default_route_info();
|
let info = router.default_route_info();
|
||||||
assert!(info.has_resource("/test2/test10/name"));
|
assert!(info.has_resource("/test2/test10/name"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_url_for() {
|
||||||
|
let mut router = Router::<()>::new(ResourceDef::prefix(""));
|
||||||
|
|
||||||
|
let mut resource = Resource::new(ResourceDef::new("/tttt"));
|
||||||
|
resource.name("r0");
|
||||||
|
router.register_resource(resource);
|
||||||
|
|
||||||
|
let scope = Scope::new("/test").resource("/name", |r| {
|
||||||
|
r.name("r1");
|
||||||
|
});
|
||||||
|
router.register_scope(scope);
|
||||||
|
|
||||||
|
let scope = Scope::new("/test2")
|
||||||
|
.nested("/test10", |s| s.resource("/name", |r| r.name("r2")));
|
||||||
|
router.register_scope(scope);
|
||||||
|
router.finish();
|
||||||
|
|
||||||
|
let req = TestRequest::with_uri("/test").request();
|
||||||
|
{
|
||||||
|
let info = router.default_route_info();
|
||||||
|
|
||||||
|
let res = info
|
||||||
|
.url_for(&req, "r0", Vec::<&'static str>::new())
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(res.as_str(), "http://localhost:8080/tttt");
|
||||||
|
|
||||||
|
let res = info
|
||||||
|
.url_for(&req, "r1", Vec::<&'static str>::new())
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(res.as_str(), "http://localhost:8080/test/name");
|
||||||
|
|
||||||
|
let res = info
|
||||||
|
.url_for(&req, "r2", Vec::<&'static str>::new())
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(res.as_str(), "http://localhost:8080/test2/test10/name");
|
||||||
|
}
|
||||||
|
|
||||||
|
let req = TestRequest::with_uri("/test/name").request();
|
||||||
|
let info = router.recognize(&req, &(), 0);
|
||||||
|
assert_eq!(info.resource, ResourceId::Normal(1));
|
||||||
|
|
||||||
|
let res = info
|
||||||
|
.url_for(&req, "r0", Vec::<&'static str>::new())
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(res.as_str(), "http://localhost:8080/tttt");
|
||||||
|
|
||||||
|
let res = info
|
||||||
|
.url_for(&req, "r1", Vec::<&'static str>::new())
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(res.as_str(), "http://localhost:8080/test/name");
|
||||||
|
|
||||||
|
let res = info
|
||||||
|
.url_for(&req, "r2", Vec::<&'static str>::new())
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(res.as_str(), "http://localhost:8080/test2/test10/name");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_url_for_dynamic() {
|
||||||
|
let mut router = Router::<()>::new(ResourceDef::prefix(""));
|
||||||
|
|
||||||
|
let mut resource = Resource::new(ResourceDef::new("/{name}/test/index.{ext}"));
|
||||||
|
resource.name("r0");
|
||||||
|
router.register_resource(resource);
|
||||||
|
|
||||||
|
let scope = Scope::new("/{name1}").nested("/{name2}", |s| {
|
||||||
|
s.resource("/{name3}/test/index.{ext}", |r| r.name("r2"))
|
||||||
|
});
|
||||||
|
router.register_scope(scope);
|
||||||
|
router.finish();
|
||||||
|
|
||||||
|
let req = TestRequest::with_uri("/test").request();
|
||||||
|
{
|
||||||
|
let info = router.default_route_info();
|
||||||
|
|
||||||
|
let res = info.url_for(&req, "r0", vec!["sec1", "html"]).unwrap();
|
||||||
|
assert_eq!(res.as_str(), "http://localhost:8080/sec1/test/index.html");
|
||||||
|
|
||||||
|
let res = info
|
||||||
|
.url_for(&req, "r2", vec!["sec1", "sec2", "sec3", "html"])
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
res.as_str(),
|
||||||
|
"http://localhost:8080/sec1/sec2/sec3/test/index.html"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
23
src/scope.rs
23
src/scope.rs
@ -58,11 +58,11 @@ pub struct Scope<S> {
|
|||||||
#[cfg_attr(feature = "cargo-clippy", allow(new_without_default_derive))]
|
#[cfg_attr(feature = "cargo-clippy", allow(new_without_default_derive))]
|
||||||
impl<S: 'static> Scope<S> {
|
impl<S: 'static> Scope<S> {
|
||||||
/// Create a new scope
|
/// Create a new scope
|
||||||
// TODO: Why is this not exactly the default impl?
|
|
||||||
pub fn new(path: &str) -> Scope<S> {
|
pub fn new(path: &str) -> Scope<S> {
|
||||||
|
let rdef = ResourceDef::prefix(path);
|
||||||
Scope {
|
Scope {
|
||||||
rdef: ResourceDef::prefix(path),
|
rdef: rdef.clone(),
|
||||||
router: Rc::new(Router::new()),
|
router: Rc::new(Router::new(rdef)),
|
||||||
filters: Vec::new(),
|
filters: Vec::new(),
|
||||||
middlewares: Rc::new(Vec::new()),
|
middlewares: Rc::new(Vec::new()),
|
||||||
}
|
}
|
||||||
@ -132,10 +132,11 @@ impl<S: 'static> Scope<S> {
|
|||||||
where
|
where
|
||||||
F: FnOnce(Scope<T>) -> Scope<T>,
|
F: FnOnce(Scope<T>) -> Scope<T>,
|
||||||
{
|
{
|
||||||
|
let rdef = ResourceDef::prefix(path);
|
||||||
let scope = Scope {
|
let scope = Scope {
|
||||||
rdef: ResourceDef::prefix(path),
|
rdef: rdef.clone(),
|
||||||
filters: Vec::new(),
|
filters: Vec::new(),
|
||||||
router: Rc::new(Router::new()),
|
router: Rc::new(Router::new(rdef)),
|
||||||
middlewares: Rc::new(Vec::new()),
|
middlewares: Rc::new(Vec::new()),
|
||||||
};
|
};
|
||||||
let mut scope = f(scope);
|
let mut scope = f(scope);
|
||||||
@ -178,10 +179,11 @@ impl<S: 'static> Scope<S> {
|
|||||||
where
|
where
|
||||||
F: FnOnce(Scope<S>) -> Scope<S>,
|
F: FnOnce(Scope<S>) -> Scope<S>,
|
||||||
{
|
{
|
||||||
|
let rdef = ResourceDef::prefix(&path);
|
||||||
let scope = Scope {
|
let scope = Scope {
|
||||||
rdef: ResourceDef::prefix(&path),
|
rdef: rdef.clone(),
|
||||||
filters: Vec::new(),
|
filters: Vec::new(),
|
||||||
router: Rc::new(Router::new()),
|
router: Rc::new(Router::new(rdef)),
|
||||||
middlewares: Rc::new(Vec::new()),
|
middlewares: Rc::new(Vec::new()),
|
||||||
};
|
};
|
||||||
Rc::get_mut(&mut self.router)
|
Rc::get_mut(&mut self.router)
|
||||||
@ -258,12 +260,7 @@ impl<S: 'static> Scope<S> {
|
|||||||
F: FnOnce(&mut Resource<S>) -> R + 'static,
|
F: FnOnce(&mut Resource<S>) -> R + 'static,
|
||||||
{
|
{
|
||||||
// add resource
|
// add resource
|
||||||
let pattern = ResourceDef::with_prefix(
|
let mut resource = Resource::new(ResourceDef::new(path));
|
||||||
path,
|
|
||||||
if path.is_empty() { "" } else { "/" },
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
let mut resource = Resource::new(pattern);
|
|
||||||
f(&mut resource);
|
f(&mut resource);
|
||||||
|
|
||||||
Rc::get_mut(&mut self.router)
|
Rc::get_mut(&mut self.router)
|
||||||
|
@ -147,13 +147,11 @@ impl TestServer {
|
|||||||
#[cfg(feature = "rust-tls")]
|
#[cfg(feature = "rust-tls")]
|
||||||
{
|
{
|
||||||
use rustls::ClientConfig;
|
use rustls::ClientConfig;
|
||||||
use std::io::BufReader;
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
|
use std::io::BufReader;
|
||||||
let mut config = ClientConfig::new();
|
let mut config = ClientConfig::new();
|
||||||
let pem_file = &mut BufReader::new(File::open("tests/cert.pem").unwrap());
|
let pem_file = &mut BufReader::new(File::open("tests/cert.pem").unwrap());
|
||||||
config
|
config.root_store.add_pem_file(pem_file).unwrap();
|
||||||
.root_store
|
|
||||||
.add_pem_file(pem_file).unwrap();
|
|
||||||
ClientConnector::with_connector(Arc::new(config)).start()
|
ClientConnector::with_connector(Arc::new(config)).start()
|
||||||
}
|
}
|
||||||
#[cfg(not(any(feature = "alpn", feature = "rust-tls")))]
|
#[cfg(not(any(feature = "alpn", feature = "rust-tls")))]
|
||||||
@ -574,7 +572,7 @@ impl<S: 'static> TestRequest<S> {
|
|||||||
payload,
|
payload,
|
||||||
prefix,
|
prefix,
|
||||||
} = self;
|
} = self;
|
||||||
let router = Router::<()>::new();
|
let router = Router::<()>::default();
|
||||||
|
|
||||||
let pool = RequestPool::pool(ServerSettings::default());
|
let pool = RequestPool::pool(ServerSettings::default());
|
||||||
let mut req = RequestPool::get(pool);
|
let mut req = RequestPool::get(pool);
|
||||||
|
Loading…
Reference in New Issue
Block a user