mirror of
https://github.com/actix/actix-extras.git
synced 2024-11-30 18:34:36 +01:00
HttpRequest::resource() returns current matched resource
This commit is contained in:
parent
b2e771df2c
commit
17c27ef42d
@ -9,6 +9,8 @@
|
|||||||
|
|
||||||
* Use more ergonomic `actix_web::Error` instead of `http::Error` for `ClientRequestBuilder::body()`
|
* Use more ergonomic `actix_web::Error` instead of `http::Error` for `ClientRequestBuilder::body()`
|
||||||
|
|
||||||
|
* Add `HttpRequest::resource()`, returns current matched resource
|
||||||
|
|
||||||
* Router cannot parse Non-ASCII characters in URL #137
|
* Router cannot parse Non-ASCII characters in URL #137
|
||||||
|
|
||||||
* Fix long client urls #129
|
* Fix long client urls #129
|
||||||
|
@ -68,6 +68,7 @@ smallvec = "0.6"
|
|||||||
time = "0.1"
|
time = "0.1"
|
||||||
encoding = "0.2"
|
encoding = "0.2"
|
||||||
language-tags = "0.2"
|
language-tags = "0.2"
|
||||||
|
lazy_static = "1.0"
|
||||||
url = { version="1.7", features=["query_encoding"] }
|
url = { version="1.7", features=["query_encoding"] }
|
||||||
cookie = { version="0.10", features=["percent-encode"] }
|
cookie = { version="0.10", features=["percent-encode"] }
|
||||||
brotli2 = { version="^0.3.2", optional = true }
|
brotli2 = { version="^0.3.2", optional = true }
|
||||||
|
@ -34,16 +34,14 @@ use db::{CreateUser, DbExecutor};
|
|||||||
|
|
||||||
|
|
||||||
/// State with DbExecutor address
|
/// State with DbExecutor address
|
||||||
struct State {
|
struct App {
|
||||||
db: Addr<Syn, DbExecutor>,
|
db: Addr<Syn, DbExecutor>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Async request handler
|
/// Async request handler
|
||||||
fn index(req: HttpRequest<State>) -> Box<Future<Item=HttpResponse, Error=Error>> {
|
fn index(name: Path<(String,)>, state: State<App>) -> FutureResponse<HttpResponse> {
|
||||||
let name = &req.match_info()["name"];
|
|
||||||
|
|
||||||
// send async `CreateUser` message to a `DbExecutor`
|
// send async `CreateUser` message to a `DbExecutor`
|
||||||
req.state().db.send(CreateUser{name: name.to_owned()})
|
state.db.send(CreateUser{name: name.into_inner()})
|
||||||
.from_err()
|
.from_err()
|
||||||
.and_then(|res| {
|
.and_then(|res| {
|
||||||
match res {
|
match res {
|
||||||
@ -72,7 +70,7 @@ fn main() {
|
|||||||
App::with_state(State{db: addr.clone()})
|
App::with_state(State{db: addr.clone()})
|
||||||
// enable logger
|
// enable logger
|
||||||
.middleware(middleware::Logger::default())
|
.middleware(middleware::Logger::default())
|
||||||
.resource("/{name}", |r| r.method(http::Method::GET).a(index))})
|
.resource("/{name}", |r| r.method(http::Method::GET).with2(index))})
|
||||||
.bind("127.0.0.1:8080").unwrap()
|
.bind("127.0.0.1:8080").unwrap()
|
||||||
.start();
|
.start();
|
||||||
|
|
||||||
|
@ -4,8 +4,8 @@ use std::cell::RefCell;
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use handler::Reply;
|
use handler::Reply;
|
||||||
use router::{Router, Pattern};
|
use router::{Router, Resource};
|
||||||
use resource::Resource;
|
use resource::{ResourceHandler};
|
||||||
use header::ContentEncoding;
|
use header::ContentEncoding;
|
||||||
use handler::{Handler, RouteHandler, WrapHandler};
|
use handler::{Handler, RouteHandler, WrapHandler};
|
||||||
use httprequest::HttpRequest;
|
use httprequest::HttpRequest;
|
||||||
@ -27,10 +27,10 @@ pub struct HttpApplication<S=()> {
|
|||||||
|
|
||||||
pub(crate) struct Inner<S> {
|
pub(crate) struct Inner<S> {
|
||||||
prefix: usize,
|
prefix: usize,
|
||||||
default: Resource<S>,
|
default: ResourceHandler<S>,
|
||||||
encoding: ContentEncoding,
|
encoding: ContentEncoding,
|
||||||
router: Router,
|
router: Router,
|
||||||
resources: Vec<Resource<S>>,
|
resources: Vec<ResourceHandler<S>>,
|
||||||
handlers: Vec<(String, Box<RouteHandler<S>>)>,
|
handlers: Vec<(String, Box<RouteHandler<S>>)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,10 +103,10 @@ struct ApplicationParts<S> {
|
|||||||
state: S,
|
state: S,
|
||||||
prefix: String,
|
prefix: String,
|
||||||
settings: ServerSettings,
|
settings: ServerSettings,
|
||||||
default: Resource<S>,
|
default: ResourceHandler<S>,
|
||||||
resources: Vec<(Pattern, Option<Resource<S>>)>,
|
resources: Vec<(Resource, Option<ResourceHandler<S>>)>,
|
||||||
handlers: Vec<(String, Box<RouteHandler<S>>)>,
|
handlers: Vec<(String, Box<RouteHandler<S>>)>,
|
||||||
external: HashMap<String, Pattern>,
|
external: HashMap<String, Resource>,
|
||||||
encoding: ContentEncoding,
|
encoding: ContentEncoding,
|
||||||
middlewares: Vec<Box<Middleware<S>>>,
|
middlewares: Vec<Box<Middleware<S>>>,
|
||||||
}
|
}
|
||||||
@ -126,7 +126,7 @@ impl App<()> {
|
|||||||
state: (),
|
state: (),
|
||||||
prefix: "/".to_owned(),
|
prefix: "/".to_owned(),
|
||||||
settings: ServerSettings::default(),
|
settings: ServerSettings::default(),
|
||||||
default: Resource::default_not_found(),
|
default: ResourceHandler::default_not_found(),
|
||||||
resources: Vec::new(),
|
resources: Vec::new(),
|
||||||
handlers: Vec::new(),
|
handlers: Vec::new(),
|
||||||
external: HashMap::new(),
|
external: HashMap::new(),
|
||||||
@ -156,7 +156,7 @@ impl<S> App<S> where S: 'static {
|
|||||||
state,
|
state,
|
||||||
prefix: "/".to_owned(),
|
prefix: "/".to_owned(),
|
||||||
settings: ServerSettings::default(),
|
settings: ServerSettings::default(),
|
||||||
default: Resource::default_not_found(),
|
default: ResourceHandler::default_not_found(),
|
||||||
resources: Vec::new(),
|
resources: Vec::new(),
|
||||||
handlers: Vec::new(),
|
handlers: Vec::new(),
|
||||||
external: HashMap::new(),
|
external: HashMap::new(),
|
||||||
@ -236,16 +236,16 @@ impl<S> App<S> where S: 'static {
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn resource<F>(mut self, path: &str, f: F) -> App<S>
|
pub fn resource<F>(mut self, path: &str, f: F) -> App<S>
|
||||||
where F: FnOnce(&mut Resource<S>) + 'static
|
where F: FnOnce(&mut ResourceHandler<S>) + 'static
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
let parts = self.parts.as_mut().expect("Use after finish");
|
let parts = self.parts.as_mut().expect("Use after finish");
|
||||||
|
|
||||||
// add resource
|
// add resource
|
||||||
let mut resource = Resource::default();
|
let mut resource = ResourceHandler::default();
|
||||||
f(&mut resource);
|
f(&mut resource);
|
||||||
|
|
||||||
let pattern = Pattern::new(resource.get_name(), path);
|
let pattern = Resource::new(resource.get_name(), path);
|
||||||
parts.resources.push((pattern, Some(resource)));
|
parts.resources.push((pattern, Some(resource)));
|
||||||
}
|
}
|
||||||
self
|
self
|
||||||
@ -253,7 +253,7 @@ impl<S> App<S> where S: 'static {
|
|||||||
|
|
||||||
/// Default resource is used if no matched route could be found.
|
/// Default resource is used if no matched route could be found.
|
||||||
pub fn default_resource<F>(mut self, f: F) -> App<S>
|
pub fn default_resource<F>(mut self, f: F) -> App<S>
|
||||||
where F: FnOnce(&mut Resource<S>) + 'static
|
where F: FnOnce(&mut ResourceHandler<S>) + 'static
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
let parts = self.parts.as_mut().expect("Use after finish");
|
let parts = self.parts.as_mut().expect("Use after finish");
|
||||||
@ -305,7 +305,8 @@ impl<S> App<S> where S: 'static {
|
|||||||
panic!("External resource {:?} is registered.", name.as_ref());
|
panic!("External resource {:?} is registered.", name.as_ref());
|
||||||
}
|
}
|
||||||
parts.external.insert(
|
parts.external.insert(
|
||||||
String::from(name.as_ref()), Pattern::new(name.as_ref(), url.as_ref()));
|
String::from(name.as_ref()),
|
||||||
|
Resource::external(name.as_ref(), url.as_ref()));
|
||||||
}
|
}
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
12
src/de.rs
12
src/de.rs
@ -554,8 +554,8 @@ impl<'de> de::VariantAccess<'de> for UnitVariant {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use futures::{Async, Future};
|
use futures::{Async, Future};
|
||||||
use super::*;
|
use super::*;
|
||||||
use router::{Router, Pattern};
|
use router::{Router, Resource};
|
||||||
use resource::Resource;
|
use resource::ResourceHandler;
|
||||||
use test::TestRequest;
|
use test::TestRequest;
|
||||||
use server::ServerSettings;
|
use server::ServerSettings;
|
||||||
|
|
||||||
@ -580,10 +580,10 @@ mod tests {
|
|||||||
fn test_request_extract() {
|
fn test_request_extract() {
|
||||||
let mut req = TestRequest::with_uri("/name/user1/?id=test").finish();
|
let mut req = TestRequest::with_uri("/name/user1/?id=test").finish();
|
||||||
|
|
||||||
let mut resource = Resource::<()>::default();
|
let mut resource = ResourceHandler::<()>::default();
|
||||||
resource.name("index");
|
resource.name("index");
|
||||||
let mut routes = Vec::new();
|
let mut routes = Vec::new();
|
||||||
routes.push((Pattern::new("index", "/{key}/{value}/"), Some(resource)));
|
routes.push((Resource::new("index", "/{key}/{value}/"), Some(resource)));
|
||||||
let (router, _) = Router::new("", ServerSettings::default(), routes);
|
let (router, _) = Router::new("", ServerSettings::default(), routes);
|
||||||
assert!(router.recognize(&mut req).is_some());
|
assert!(router.recognize(&mut req).is_some());
|
||||||
|
|
||||||
@ -639,10 +639,10 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_extract_path_signle() {
|
fn test_extract_path_signle() {
|
||||||
let mut resource = Resource::<()>::default();
|
let mut resource = ResourceHandler::<()>::default();
|
||||||
resource.name("index");
|
resource.name("index");
|
||||||
let mut routes = Vec::new();
|
let mut routes = Vec::new();
|
||||||
routes.push((Pattern::new("index", "/{value}/"), Some(resource)));
|
routes.push((Resource::new("index", "/{value}/"), Some(resource)));
|
||||||
let (router, _) = Router::new("", ServerSettings::default(), routes);
|
let (router, _) = Router::new("", ServerSettings::default(), routes);
|
||||||
|
|
||||||
let mut req = TestRequest::with_uri("/32/").finish();
|
let mut req = TestRequest::with_uri("/32/").finish();
|
||||||
|
@ -17,7 +17,7 @@ use percent_encoding::percent_decode;
|
|||||||
use body::Body;
|
use body::Body;
|
||||||
use info::ConnectionInfo;
|
use info::ConnectionInfo;
|
||||||
use param::Params;
|
use param::Params;
|
||||||
use router::Router;
|
use router::{Router, Resource};
|
||||||
use payload::Payload;
|
use payload::Payload;
|
||||||
use handler::FromRequest;
|
use handler::FromRequest;
|
||||||
use httpmessage::HttpMessage;
|
use httpmessage::HttpMessage;
|
||||||
@ -39,6 +39,7 @@ pub struct HttpInnerMessage {
|
|||||||
pub addr: Option<SocketAddr>,
|
pub addr: Option<SocketAddr>,
|
||||||
pub payload: Option<Payload>,
|
pub payload: Option<Payload>,
|
||||||
pub info: Option<ConnectionInfo<'static>>,
|
pub info: Option<ConnectionInfo<'static>>,
|
||||||
|
pub resource: i16,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for HttpInnerMessage {
|
impl Default for HttpInnerMessage {
|
||||||
@ -57,6 +58,7 @@ impl Default for HttpInnerMessage {
|
|||||||
payload: None,
|
payload: None,
|
||||||
extensions: Extensions::new(),
|
extensions: Extensions::new(),
|
||||||
info: None,
|
info: None,
|
||||||
|
resource: -1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -93,9 +95,15 @@ impl HttpInnerMessage {
|
|||||||
self.addr = None;
|
self.addr = None;
|
||||||
self.info = None;
|
self.info = None;
|
||||||
self.payload = None;
|
self.payload = None;
|
||||||
|
self.resource = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lazy_static!{
|
||||||
|
static ref RESOURCE: Resource = Resource::default();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// An HTTP Request
|
/// An HTTP Request
|
||||||
pub struct HttpRequest<S=()>(SharedHttpInnerMessage, Option<Rc<S>>, Option<Router>);
|
pub struct HttpRequest<S=()>(SharedHttpInnerMessage, Option<Rc<S>>, Option<Router>);
|
||||||
|
|
||||||
@ -120,6 +128,7 @@ impl HttpRequest<()> {
|
|||||||
addr: None,
|
addr: None,
|
||||||
extensions: Extensions::new(),
|
extensions: Extensions::new(),
|
||||||
info: None,
|
info: None,
|
||||||
|
resource: -1,
|
||||||
}),
|
}),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
@ -318,6 +327,22 @@ impl<S> HttpRequest<S> {
|
|||||||
self.2.as_ref()
|
self.2.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This method returns reference to matched `Resource` object.
|
||||||
|
#[inline]
|
||||||
|
pub fn resource(&self) -> &Resource {
|
||||||
|
let idx = self.as_ref().resource;
|
||||||
|
if idx >= 0 {
|
||||||
|
if let Some(ref router) = self.2 {
|
||||||
|
return router.get_resource(idx as usize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&*RESOURCE
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn set_resource(&mut self, idx: usize) {
|
||||||
|
self.as_mut().resource = idx as i16;
|
||||||
|
}
|
||||||
|
|
||||||
/// Peer socket address
|
/// Peer socket address
|
||||||
///
|
///
|
||||||
/// Peer address is actual socket address, if proxy is used in front of
|
/// Peer address is actual socket address, if proxy is used in front of
|
||||||
@ -544,8 +569,8 @@ impl<S> fmt::Debug for HttpRequest<S> {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use http::{Uri, HttpTryFrom};
|
use http::{Uri, HttpTryFrom};
|
||||||
use router::Pattern;
|
use router::Resource;
|
||||||
use resource::Resource;
|
use resource::ResourceHandler;
|
||||||
use test::TestRequest;
|
use test::TestRequest;
|
||||||
use server::ServerSettings;
|
use server::ServerSettings;
|
||||||
|
|
||||||
@ -607,10 +632,10 @@ mod tests {
|
|||||||
fn test_request_match_info() {
|
fn test_request_match_info() {
|
||||||
let mut req = TestRequest::with_uri("/value/?id=test").finish();
|
let mut req = TestRequest::with_uri("/value/?id=test").finish();
|
||||||
|
|
||||||
let mut resource = Resource::<()>::default();
|
let mut resource = ResourceHandler::<()>::default();
|
||||||
resource.name("index");
|
resource.name("index");
|
||||||
let mut routes = Vec::new();
|
let mut routes = Vec::new();
|
||||||
routes.push((Pattern::new("index", "/{key}/"), Some(resource)));
|
routes.push((Resource::new("index", "/{key}/"), Some(resource)));
|
||||||
let (router, _) = Router::new("", ServerSettings::default(), routes);
|
let (router, _) = Router::new("", ServerSettings::default(), routes);
|
||||||
assert!(router.recognize(&mut req).is_some());
|
assert!(router.recognize(&mut req).is_some());
|
||||||
|
|
||||||
@ -623,9 +648,9 @@ mod tests {
|
|||||||
assert_eq!(req2.url_for("unknown", &["test"]),
|
assert_eq!(req2.url_for("unknown", &["test"]),
|
||||||
Err(UrlGenerationError::RouterNotAvailable));
|
Err(UrlGenerationError::RouterNotAvailable));
|
||||||
|
|
||||||
let mut resource = Resource::<()>::default();
|
let mut resource = ResourceHandler::<()>::default();
|
||||||
resource.name("index");
|
resource.name("index");
|
||||||
let routes = vec!((Pattern::new("index", "/user/{name}.{ext}"), Some(resource)));
|
let routes = vec!((Resource::new("index", "/user/{name}.{ext}"), Some(resource)));
|
||||||
let (router, _) = Router::new("/", ServerSettings::default(), routes);
|
let (router, _) = Router::new("/", ServerSettings::default(), routes);
|
||||||
assert!(router.has_route("/user/test.html"));
|
assert!(router.has_route("/user/test.html"));
|
||||||
assert!(!router.has_route("/test/unknown"));
|
assert!(!router.has_route("/test/unknown"));
|
||||||
@ -645,26 +670,27 @@ mod tests {
|
|||||||
fn test_url_for_with_prefix() {
|
fn test_url_for_with_prefix() {
|
||||||
let req = TestRequest::with_header(header::HOST, "www.rust-lang.org").finish();
|
let req = TestRequest::with_header(header::HOST, "www.rust-lang.org").finish();
|
||||||
|
|
||||||
let mut resource = Resource::<()>::default();
|
let mut resource = ResourceHandler::<()>::default();
|
||||||
resource.name("index");
|
resource.name("index");
|
||||||
let routes = vec![(Pattern::new("index", "/user/{name}.{ext}"), Some(resource))];
|
let routes = vec![(Resource::new("index", "/user/{name}.{ext}"), Some(resource))];
|
||||||
let (router, _) = Router::new("/prefix/", ServerSettings::default(), routes);
|
let (router, _) = Router::new("/prefix/", ServerSettings::default(), routes);
|
||||||
assert!(router.has_route("/user/test.html"));
|
assert!(router.has_route("/user/test.html"));
|
||||||
assert!(!router.has_route("/prefix/user/test.html"));
|
assert!(!router.has_route("/prefix/user/test.html"));
|
||||||
|
|
||||||
let req = req.with_state(Rc::new(()), router);
|
let req = req.with_state(Rc::new(()), router);
|
||||||
let url = req.url_for("index", &["test", "html"]);
|
let url = req.url_for("index", &["test", "html"]);
|
||||||
assert_eq!(url.ok().unwrap().as_str(), "http://www.rust-lang.org/prefix/user/test.html");
|
assert_eq!(url.ok().unwrap().as_str(),
|
||||||
|
"http://www.rust-lang.org/prefix/user/test.html");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_url_for_external() {
|
fn test_url_for_external() {
|
||||||
let req = HttpRequest::default();
|
let req = HttpRequest::default();
|
||||||
|
|
||||||
let mut resource = Resource::<()>::default();
|
let mut resource = ResourceHandler::<()>::default();
|
||||||
resource.name("index");
|
resource.name("index");
|
||||||
let routes = vec![
|
let routes = vec![
|
||||||
(Pattern::new("youtube", "https://youtube.com/watch/{video_id}"), None)];
|
(Resource::external("youtube", "https://youtube.com/watch/{video_id}"), None)];
|
||||||
let (router, _) = Router::new::<()>("", ServerSettings::default(), routes);
|
let (router, _) = Router::new::<()>("", ServerSettings::default(), routes);
|
||||||
assert!(!router.has_route("https://youtube.com/watch/unknown"));
|
assert!(!router.has_route("https://youtube.com/watch/unknown"));
|
||||||
|
|
||||||
|
@ -60,6 +60,8 @@ extern crate bitflags;
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate failure;
|
extern crate failure;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
extern crate lazy_static;
|
||||||
|
#[macro_use]
|
||||||
extern crate futures;
|
extern crate futures;
|
||||||
extern crate futures_cpupool;
|
extern crate futures_cpupool;
|
||||||
extern crate tokio_io;
|
extern crate tokio_io;
|
||||||
@ -174,12 +176,12 @@ pub mod dev {
|
|||||||
|
|
||||||
pub use body::BodyStream;
|
pub use body::BodyStream;
|
||||||
pub use context::Drain;
|
pub use context::Drain;
|
||||||
|
pub use json::JsonBody;
|
||||||
pub use info::ConnectionInfo;
|
pub use info::ConnectionInfo;
|
||||||
pub use handler::{Handler, Reply, FromRequest};
|
pub use handler::{Handler, Reply, FromRequest};
|
||||||
pub use route::Route;
|
pub use route::Route;
|
||||||
pub use resource::Resource;
|
pub use router::{Router, Resource};
|
||||||
pub use json::JsonBody;
|
pub use resource::ResourceHandler;
|
||||||
pub use router::{Router, Pattern};
|
|
||||||
pub use param::{FromParam, Params};
|
pub use param::{FromParam, Params};
|
||||||
pub use httpmessage::{UrlEncoded, MessageBody};
|
pub use httpmessage::{UrlEncoded, MessageBody};
|
||||||
pub use httpresponse::HttpResponseBuilder;
|
pub use httpresponse::HttpResponseBuilder;
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
//! 3. Call [finish](struct.Cors.html#method.finish) to retrieve the constructed backend.
|
//! 3. Call [finish](struct.Cors.html#method.finish) to retrieve the constructed backend.
|
||||||
//!
|
//!
|
||||||
//! Cors middleware could be used as parameter for `App::middleware()` or
|
//! Cors middleware could be used as parameter for `App::middleware()` or
|
||||||
//! `Resource::middleware()` methods. But you have to use `Cors::register()` method to
|
//! `ResourceHandler::middleware()` methods. But you have to use `Cors::register()` method to
|
||||||
//! support *preflight* OPTIONS request.
|
//! support *preflight* OPTIONS request.
|
||||||
//!
|
//!
|
||||||
//!
|
//!
|
||||||
@ -52,7 +52,7 @@ use http::{self, Method, HttpTryFrom, Uri, StatusCode};
|
|||||||
use http::header::{self, HeaderName, HeaderValue};
|
use http::header::{self, HeaderName, HeaderValue};
|
||||||
|
|
||||||
use error::{Result, ResponseError};
|
use error::{Result, ResponseError};
|
||||||
use resource::Resource;
|
use resource::ResourceHandler;
|
||||||
use httpmessage::HttpMessage;
|
use httpmessage::HttpMessage;
|
||||||
use httprequest::HttpRequest;
|
use httprequest::HttpRequest;
|
||||||
use httpresponse::HttpResponse;
|
use httpresponse::HttpResponse;
|
||||||
@ -212,10 +212,10 @@ impl Cors {
|
|||||||
/// This method register cors middleware with resource and
|
/// This method register cors middleware with resource and
|
||||||
/// adds route for *OPTIONS* preflight requests.
|
/// adds route for *OPTIONS* preflight requests.
|
||||||
///
|
///
|
||||||
/// It is possible to register *Cors* middleware with `Resource::middleware()`
|
/// It is possible to register *Cors* middleware with `ResourceHandler::middleware()`
|
||||||
/// method, but in that case *Cors* middleware wont be able to handle *OPTIONS*
|
/// method, but in that case *Cors* middleware wont be able to handle *OPTIONS*
|
||||||
/// requests.
|
/// requests.
|
||||||
pub fn register<S: 'static>(self, resource: &mut Resource<S>) {
|
pub fn register<S: 'static>(self, resource: &mut ResourceHandler<S>) {
|
||||||
resource.method(Method::OPTIONS).h(|_| HttpResponse::Ok());
|
resource.method(Method::OPTIONS).h(|_| HttpResponse::Ok());
|
||||||
resource.middleware(self);
|
resource.middleware(self);
|
||||||
}
|
}
|
||||||
|
@ -31,16 +31,16 @@ use httpresponse::HttpResponse;
|
|||||||
/// "/", |r| r.method(http::Method::GET).f(|r| HttpResponse::Ok()))
|
/// "/", |r| r.method(http::Method::GET).f(|r| HttpResponse::Ok()))
|
||||||
/// .finish();
|
/// .finish();
|
||||||
/// }
|
/// }
|
||||||
pub struct Resource<S=()> {
|
pub struct ResourceHandler<S=()> {
|
||||||
name: String,
|
name: String,
|
||||||
state: PhantomData<S>,
|
state: PhantomData<S>,
|
||||||
routes: SmallVec<[Route<S>; 3]>,
|
routes: SmallVec<[Route<S>; 3]>,
|
||||||
middlewares: Rc<Vec<Box<Middleware<S>>>>,
|
middlewares: Rc<Vec<Box<Middleware<S>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> Default for Resource<S> {
|
impl<S> Default for ResourceHandler<S> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Resource {
|
ResourceHandler {
|
||||||
name: String::new(),
|
name: String::new(),
|
||||||
state: PhantomData,
|
state: PhantomData,
|
||||||
routes: SmallVec::new(),
|
routes: SmallVec::new(),
|
||||||
@ -48,10 +48,10 @@ impl<S> Default for Resource<S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> Resource<S> {
|
impl<S> ResourceHandler<S> {
|
||||||
|
|
||||||
pub(crate) fn default_not_found() -> Self {
|
pub(crate) fn default_not_found() -> Self {
|
||||||
Resource {
|
ResourceHandler {
|
||||||
name: String::new(),
|
name: String::new(),
|
||||||
state: PhantomData,
|
state: PhantomData,
|
||||||
routes: SmallVec::new(),
|
routes: SmallVec::new(),
|
||||||
@ -68,7 +68,7 @@ impl<S> Resource<S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: 'static> Resource<S> {
|
impl<S: 'static> ResourceHandler<S> {
|
||||||
|
|
||||||
/// Register a new route and return mutable reference to *Route* object.
|
/// Register a new route and return mutable reference to *Route* object.
|
||||||
/// *Route* is used for route configuration, i.e. adding predicates, setting up handler.
|
/// *Route* is used for route configuration, i.e. adding predicates, setting up handler.
|
||||||
@ -97,7 +97,7 @@ impl<S: 'static> Resource<S> {
|
|||||||
/// This is shortcut for:
|
/// This is shortcut for:
|
||||||
///
|
///
|
||||||
/// ```rust,ignore
|
/// ```rust,ignore
|
||||||
/// Resource::resource("/", |r| r.route().filter(pred::Get()).f(index)
|
/// Application::resource("/", |r| r.route().filter(pred::Get()).f(index)
|
||||||
/// ```
|
/// ```
|
||||||
pub fn method(&mut self, method: Method) -> &mut Route<S> {
|
pub fn method(&mut self, method: Method) -> &mut Route<S> {
|
||||||
self.routes.push(Route::default());
|
self.routes.push(Route::default());
|
||||||
@ -109,7 +109,7 @@ impl<S: 'static> Resource<S> {
|
|||||||
/// This is shortcut for:
|
/// This is shortcut for:
|
||||||
///
|
///
|
||||||
/// ```rust,ignore
|
/// ```rust,ignore
|
||||||
/// Resource::resource("/", |r| r.route().h(handler)
|
/// Application::resource("/", |r| r.route().h(handler)
|
||||||
/// ```
|
/// ```
|
||||||
pub fn h<H: Handler<S>>(&mut self, handler: H) {
|
pub fn h<H: Handler<S>>(&mut self, handler: H) {
|
||||||
self.routes.push(Route::default());
|
self.routes.push(Route::default());
|
||||||
@ -121,7 +121,7 @@ impl<S: 'static> Resource<S> {
|
|||||||
/// This is shortcut for:
|
/// This is shortcut for:
|
||||||
///
|
///
|
||||||
/// ```rust,ignore
|
/// ```rust,ignore
|
||||||
/// Resource::resource("/", |r| r.route().f(index)
|
/// Application::resource("/", |r| r.route().f(index)
|
||||||
/// ```
|
/// ```
|
||||||
pub fn f<F, R>(&mut self, handler: F)
|
pub fn f<F, R>(&mut self, handler: F)
|
||||||
where F: Fn(HttpRequest<S>) -> R + 'static,
|
where F: Fn(HttpRequest<S>) -> R + 'static,
|
||||||
@ -136,7 +136,7 @@ impl<S: 'static> Resource<S> {
|
|||||||
/// This is shortcut for:
|
/// This is shortcut for:
|
||||||
///
|
///
|
||||||
/// ```rust,ignore
|
/// ```rust,ignore
|
||||||
/// Resource::resource("/", |r| r.route().with(index)
|
/// Application::resource("/", |r| r.route().with(index)
|
||||||
/// ```
|
/// ```
|
||||||
pub fn with<T, F, R>(&mut self, handler: F)
|
pub fn with<T, F, R>(&mut self, handler: F)
|
||||||
where F: Fn(T) -> R + 'static,
|
where F: Fn(T) -> R + 'static,
|
||||||
@ -147,7 +147,7 @@ impl<S: 'static> Resource<S> {
|
|||||||
self.routes.last_mut().unwrap().with(handler)
|
self.routes.last_mut().unwrap().with(handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Register a middleware
|
/// Register a resource middleware
|
||||||
///
|
///
|
||||||
/// This is similar to `App's` middlewares, but
|
/// This is similar to `App's` middlewares, but
|
||||||
/// middlewares get invoked on resource level.
|
/// middlewares get invoked on resource level.
|
||||||
@ -157,7 +157,7 @@ impl<S: 'static> Resource<S> {
|
|||||||
|
|
||||||
pub(crate) fn handle(&mut self,
|
pub(crate) fn handle(&mut self,
|
||||||
mut req: HttpRequest<S>,
|
mut req: HttpRequest<S>,
|
||||||
default: Option<&mut Resource<S>>) -> Reply
|
default: Option<&mut ResourceHandler<S>>) -> Reply
|
||||||
{
|
{
|
||||||
for route in &mut self.routes {
|
for route in &mut self.routes {
|
||||||
if route.check(&mut req) {
|
if route.check(&mut req) {
|
||||||
|
149
src/router.rs
149
src/router.rs
@ -6,9 +6,9 @@ use std::collections::HashMap;
|
|||||||
use regex::{Regex, escape};
|
use regex::{Regex, escape};
|
||||||
use percent_encoding::percent_decode;
|
use percent_encoding::percent_decode;
|
||||||
|
|
||||||
use error::UrlGenerationError;
|
|
||||||
use param::Params;
|
use param::Params;
|
||||||
use resource::Resource;
|
use error::UrlGenerationError;
|
||||||
|
use resource::ResourceHandler;
|
||||||
use httprequest::HttpRequest;
|
use httprequest::HttpRequest;
|
||||||
use server::ServerSettings;
|
use server::ServerSettings;
|
||||||
|
|
||||||
@ -19,8 +19,8 @@ pub struct Router(Rc<Inner>);
|
|||||||
struct Inner {
|
struct Inner {
|
||||||
prefix: String,
|
prefix: String,
|
||||||
prefix_len: usize,
|
prefix_len: usize,
|
||||||
named: HashMap<String, (Pattern, bool)>,
|
named: HashMap<String, (Resource, bool)>,
|
||||||
patterns: Vec<Pattern>,
|
patterns: Vec<Resource>,
|
||||||
srv: ServerSettings,
|
srv: ServerSettings,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,7 +28,8 @@ impl Router {
|
|||||||
/// Create new router
|
/// Create new router
|
||||||
pub fn new<S>(prefix: &str,
|
pub fn new<S>(prefix: &str,
|
||||||
settings: ServerSettings,
|
settings: ServerSettings,
|
||||||
map: Vec<(Pattern, Option<Resource<S>>)>) -> (Router, Vec<Resource<S>>)
|
map: Vec<(Resource, Option<ResourceHandler<S>>)>)
|
||||||
|
-> (Router, Vec<ResourceHandler<S>>)
|
||||||
{
|
{
|
||||||
let prefix = prefix.trim().trim_right_matches('/').to_owned();
|
let prefix = prefix.trim().trim_right_matches('/').to_owned();
|
||||||
let mut named = HashMap::new();
|
let mut named = HashMap::new();
|
||||||
@ -64,6 +65,10 @@ impl Router {
|
|||||||
&self.0.srv
|
&self.0.srv
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_resource(&self, idx: usize) -> &Resource {
|
||||||
|
&self.0.patterns[idx]
|
||||||
|
}
|
||||||
|
|
||||||
/// Query for matched resource
|
/// Query for matched resource
|
||||||
pub fn recognize<S>(&self, req: &mut HttpRequest<S>) -> Option<usize> {
|
pub fn recognize<S>(&self, req: &mut HttpRequest<S>) -> Option<usize> {
|
||||||
if self.0.prefix_len > req.path().len() {
|
if self.0.prefix_len > req.path().len() {
|
||||||
@ -75,6 +80,7 @@ impl Router {
|
|||||||
|
|
||||||
for (idx, pattern) in self.0.patterns.iter().enumerate() {
|
for (idx, pattern) in self.0.patterns.iter().enumerate() {
|
||||||
if pattern.match_with_params(p.as_ref(), req.match_info_mut()) {
|
if pattern.match_with_params(p.as_ref(), req.match_info_mut()) {
|
||||||
|
req.set_resource(idx);
|
||||||
return Some(idx)
|
return Some(idx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -108,11 +114,7 @@ impl Router {
|
|||||||
I: AsRef<str>,
|
I: AsRef<str>,
|
||||||
{
|
{
|
||||||
if let Some(pattern) = self.0.named.get(name) {
|
if let Some(pattern) = self.0.named.get(name) {
|
||||||
if pattern.1 {
|
pattern.0.resource_path(self, elements)
|
||||||
pattern.0.path(None, elements)
|
|
||||||
} else {
|
|
||||||
pattern.0.path(Some(&self.0.prefix), elements)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
Err(UrlGenerationError::ResourceNotFound)
|
Err(UrlGenerationError::ResourceNotFound)
|
||||||
}
|
}
|
||||||
@ -125,6 +127,7 @@ impl Clone for Router {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
enum PatternElement {
|
enum PatternElement {
|
||||||
Str(String),
|
Str(String),
|
||||||
@ -137,25 +140,48 @@ enum PatternType {
|
|||||||
Dynamic(Regex, Vec<String>),
|
Dynamic(Regex, Vec<String>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Reslource type describes an entry in resources table
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Pattern {
|
pub struct Resource {
|
||||||
tp: PatternType,
|
tp: PatternType,
|
||||||
name: String,
|
name: String,
|
||||||
pattern: String,
|
pattern: String,
|
||||||
elements: Vec<PatternElement>,
|
elements: Vec<PatternElement>,
|
||||||
|
external: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pattern {
|
impl Default for Resource {
|
||||||
/// Parse path pattern and create new `Pattern` instance.
|
fn default() -> Resource {
|
||||||
|
Resource {
|
||||||
|
tp: PatternType::Static("".to_owned()),
|
||||||
|
name: "".to_owned(),
|
||||||
|
pattern: "".to_owned(),
|
||||||
|
elements: Vec::new(),
|
||||||
|
external: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Resource {
|
||||||
|
/// Parse path pattern and create new `Resource` instance.
|
||||||
///
|
///
|
||||||
/// Panics if path pattern is wrong.
|
/// Panics if path pattern is wrong.
|
||||||
pub fn new(name: &str, path: &str) -> Self {
|
pub fn new(name: &str, path: &str) -> Self {
|
||||||
Pattern::with_prefix(name, path, "/")
|
Resource::with_prefix(name, path, "/")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse path pattern and create new `Pattern` instance with custom prefix
|
/// Construct external resource
|
||||||
|
///
|
||||||
|
/// Panics if path pattern is wrong.
|
||||||
|
pub fn external(name: &str, path: &str) -> Self {
|
||||||
|
let mut resource = Resource::with_prefix(name, path, "/");
|
||||||
|
resource.external = true;
|
||||||
|
resource
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parse path pattern and create new `Resource` instance with custom prefix
|
||||||
pub fn with_prefix(name: &str, path: &str, prefix: &str) -> Self {
|
pub fn with_prefix(name: &str, path: &str, prefix: &str) -> Self {
|
||||||
let (pattern, elements, is_dynamic) = Pattern::parse(path, prefix);
|
let (pattern, elements, is_dynamic) = Resource::parse(path, prefix);
|
||||||
|
|
||||||
let tp = if is_dynamic {
|
let tp = if is_dynamic {
|
||||||
let re = match Regex::new(&pattern) {
|
let re = match Regex::new(&pattern) {
|
||||||
@ -170,20 +196,21 @@ impl Pattern {
|
|||||||
PatternType::Static(pattern.clone())
|
PatternType::Static(pattern.clone())
|
||||||
};
|
};
|
||||||
|
|
||||||
Pattern {
|
Resource {
|
||||||
tp,
|
tp,
|
||||||
pattern,
|
|
||||||
elements,
|
elements,
|
||||||
name: name.into(),
|
name: name.into(),
|
||||||
|
pattern: path.to_owned(),
|
||||||
|
external: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns name of the pattern
|
/// Name of the resource
|
||||||
pub fn name(&self) -> &str {
|
pub fn name(&self) -> &str {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns path of the pattern
|
/// Path pattern of the resource
|
||||||
pub fn pattern(&self) -> &str {
|
pub fn pattern(&self) -> &str {
|
||||||
&self.pattern
|
&self.pattern
|
||||||
}
|
}
|
||||||
@ -219,14 +246,15 @@ impl Pattern {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Build pattern path.
|
/// Build reousrce path.
|
||||||
pub fn path<U, I>(&self, prefix: Option<&str>, elements: U) -> Result<String, UrlGenerationError>
|
pub fn resource_path<U, I>(&self, router: &Router, elements: U)
|
||||||
|
-> Result<String, UrlGenerationError>
|
||||||
where U: IntoIterator<Item=I>,
|
where U: IntoIterator<Item=I>,
|
||||||
I: AsRef<str>,
|
I: AsRef<str>,
|
||||||
{
|
{
|
||||||
let mut iter = elements.into_iter();
|
let mut iter = elements.into_iter();
|
||||||
let mut path = if let Some(prefix) = prefix {
|
let mut path = if !self.external {
|
||||||
format!("{}/", prefix)
|
format!("{}/", router.prefix())
|
||||||
} else {
|
} else {
|
||||||
String::new()
|
String::new()
|
||||||
};
|
};
|
||||||
@ -309,15 +337,15 @@ impl Pattern {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for Pattern {
|
impl PartialEq for Resource {
|
||||||
fn eq(&self, other: &Pattern) -> bool {
|
fn eq(&self, other: &Resource) -> bool {
|
||||||
self.pattern == other.pattern
|
self.pattern == other.pattern
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eq for Pattern {}
|
impl Eq for Resource {}
|
||||||
|
|
||||||
impl Hash for Pattern {
|
impl Hash for Resource {
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
self.pattern.hash(state);
|
self.pattern.hash(state);
|
||||||
}
|
}
|
||||||
@ -331,13 +359,20 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_recognizer() {
|
fn test_recognizer() {
|
||||||
let routes = vec![
|
let routes = vec![
|
||||||
(Pattern::new("", "/name"), Some(Resource::default())),
|
(Resource::new("", "/name"),
|
||||||
(Pattern::new("", "/name/{val}"), Some(Resource::default())),
|
Some(ResourceHandler::default())),
|
||||||
(Pattern::new("", "/name/{val}/index.html"), Some(Resource::default())),
|
(Resource::new("", "/name/{val}"),
|
||||||
(Pattern::new("", "/file/{file}.{ext}"), Some(Resource::default())),
|
Some(ResourceHandler::default())),
|
||||||
(Pattern::new("", "/v{val}/{val2}/index.html"), Some(Resource::default())),
|
(Resource::new("", "/name/{val}/index.html"),
|
||||||
(Pattern::new("", "/v/{tail:.*}"), Some(Resource::default())),
|
Some(ResourceHandler::default())),
|
||||||
(Pattern::new("", "{test}/index.html"), Some(Resource::default()))];
|
(Resource::new("", "/file/{file}.{ext}"),
|
||||||
|
Some(ResourceHandler::default())),
|
||||||
|
(Resource::new("", "/v{val}/{val2}/index.html"),
|
||||||
|
Some(ResourceHandler::default())),
|
||||||
|
(Resource::new("", "/v/{tail:.*}"),
|
||||||
|
Some(ResourceHandler::default())),
|
||||||
|
(Resource::new("", "{test}/index.html"),
|
||||||
|
Some(ResourceHandler::default()))];
|
||||||
let (rec, _) = Router::new::<()>("", ServerSettings::default(), routes);
|
let (rec, _) = Router::new::<()>("", ServerSettings::default(), routes);
|
||||||
|
|
||||||
let mut req = TestRequest::with_uri("/name").finish();
|
let mut req = TestRequest::with_uri("/name").finish();
|
||||||
@ -375,8 +410,8 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_recognizer_2() {
|
fn test_recognizer_2() {
|
||||||
let routes = vec![
|
let routes = vec![
|
||||||
(Pattern::new("", "/index.json"), Some(Resource::default())),
|
(Resource::new("", "/index.json"), Some(ResourceHandler::default())),
|
||||||
(Pattern::new("", "/{source}.json"), Some(Resource::default()))];
|
(Resource::new("", "/{source}.json"), Some(ResourceHandler::default()))];
|
||||||
let (rec, _) = Router::new::<()>("", ServerSettings::default(), routes);
|
let (rec, _) = Router::new::<()>("", ServerSettings::default(), routes);
|
||||||
|
|
||||||
let mut req = TestRequest::with_uri("/index.json").finish();
|
let mut req = TestRequest::with_uri("/index.json").finish();
|
||||||
@ -389,8 +424,8 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_recognizer_with_prefix() {
|
fn test_recognizer_with_prefix() {
|
||||||
let routes = vec![
|
let routes = vec![
|
||||||
(Pattern::new("", "/name"), Some(Resource::default())),
|
(Resource::new("", "/name"), Some(ResourceHandler::default())),
|
||||||
(Pattern::new("", "/name/{val}"), Some(Resource::default()))];
|
(Resource::new("", "/name/{val}"), Some(ResourceHandler::default()))];
|
||||||
let (rec, _) = Router::new::<()>("/test", ServerSettings::default(), routes);
|
let (rec, _) = Router::new::<()>("/test", ServerSettings::default(), routes);
|
||||||
|
|
||||||
let mut req = TestRequest::with_uri("/name").finish();
|
let mut req = TestRequest::with_uri("/name").finish();
|
||||||
@ -406,8 +441,8 @@ mod tests {
|
|||||||
|
|
||||||
// same patterns
|
// same patterns
|
||||||
let routes = vec![
|
let routes = vec![
|
||||||
(Pattern::new("", "/name"), Some(Resource::default())),
|
(Resource::new("", "/name"), Some(ResourceHandler::default())),
|
||||||
(Pattern::new("", "/name/{val}"), Some(Resource::default()))];
|
(Resource::new("", "/name/{val}"), Some(ResourceHandler::default()))];
|
||||||
let (rec, _) = Router::new::<()>("/test2", ServerSettings::default(), routes);
|
let (rec, _) = Router::new::<()>("/test2", ServerSettings::default(), routes);
|
||||||
|
|
||||||
let mut req = TestRequest::with_uri("/name").finish();
|
let mut req = TestRequest::with_uri("/name").finish();
|
||||||
@ -423,22 +458,22 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_static() {
|
fn test_parse_static() {
|
||||||
let re = Pattern::new("test", "/");
|
let re = Resource::new("test", "/");
|
||||||
assert!(re.is_match("/"));
|
assert!(re.is_match("/"));
|
||||||
assert!(!re.is_match("/a"));
|
assert!(!re.is_match("/a"));
|
||||||
|
|
||||||
let re = Pattern::new("test", "/name");
|
let re = Resource::new("test", "/name");
|
||||||
assert!(re.is_match("/name"));
|
assert!(re.is_match("/name"));
|
||||||
assert!(!re.is_match("/name1"));
|
assert!(!re.is_match("/name1"));
|
||||||
assert!(!re.is_match("/name/"));
|
assert!(!re.is_match("/name/"));
|
||||||
assert!(!re.is_match("/name~"));
|
assert!(!re.is_match("/name~"));
|
||||||
|
|
||||||
let re = Pattern::new("test", "/name/");
|
let re = Resource::new("test", "/name/");
|
||||||
assert!(re.is_match("/name/"));
|
assert!(re.is_match("/name/"));
|
||||||
assert!(!re.is_match("/name"));
|
assert!(!re.is_match("/name"));
|
||||||
assert!(!re.is_match("/name/gs"));
|
assert!(!re.is_match("/name/gs"));
|
||||||
|
|
||||||
let re = Pattern::new("test", "/user/profile");
|
let re = Resource::new("test", "/user/profile");
|
||||||
assert!(re.is_match("/user/profile"));
|
assert!(re.is_match("/user/profile"));
|
||||||
assert!(!re.is_match("/user/profile/profile"));
|
assert!(!re.is_match("/user/profile/profile"));
|
||||||
}
|
}
|
||||||
@ -447,7 +482,7 @@ mod tests {
|
|||||||
fn test_parse_param() {
|
fn test_parse_param() {
|
||||||
let mut req = HttpRequest::default();
|
let mut req = HttpRequest::default();
|
||||||
|
|
||||||
let re = Pattern::new("test", "/user/{id}");
|
let re = Resource::new("test", "/user/{id}");
|
||||||
assert!(re.is_match("/user/profile"));
|
assert!(re.is_match("/user/profile"));
|
||||||
assert!(re.is_match("/user/2345"));
|
assert!(re.is_match("/user/2345"));
|
||||||
assert!(!re.is_match("/user/2345/"));
|
assert!(!re.is_match("/user/2345/"));
|
||||||
@ -461,7 +496,7 @@ mod tests {
|
|||||||
assert!(re.match_with_params("/user/1245125", req.match_info_mut()));
|
assert!(re.match_with_params("/user/1245125", req.match_info_mut()));
|
||||||
assert_eq!(req.match_info().get("id").unwrap(), "1245125");
|
assert_eq!(req.match_info().get("id").unwrap(), "1245125");
|
||||||
|
|
||||||
let re = Pattern::new("test", "/v{version}/resource/{id}");
|
let re = Resource::new("test", "/v{version}/resource/{id}");
|
||||||
assert!(re.is_match("/v1/resource/320120"));
|
assert!(re.is_match("/v1/resource/320120"));
|
||||||
assert!(!re.is_match("/v/resource/1"));
|
assert!(!re.is_match("/v/resource/1"));
|
||||||
assert!(!re.is_match("/resource"));
|
assert!(!re.is_match("/resource"));
|
||||||
@ -471,4 +506,24 @@ mod tests {
|
|||||||
assert_eq!(req.match_info().get("version").unwrap(), "151");
|
assert_eq!(req.match_info().get("version").unwrap(), "151");
|
||||||
assert_eq!(req.match_info().get("id").unwrap(), "adahg32");
|
assert_eq!(req.match_info().get("id").unwrap(), "adahg32");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_request_resource() {
|
||||||
|
let routes = vec![
|
||||||
|
(Resource::new("r1", "/index.json"), Some(ResourceHandler::default())),
|
||||||
|
(Resource::new("r2", "/test.json"), Some(ResourceHandler::default()))];
|
||||||
|
let (router, _) = Router::new::<()>("", ServerSettings::default(), routes);
|
||||||
|
|
||||||
|
let mut req = TestRequest::with_uri("/index.json")
|
||||||
|
.finish_with_router(router.clone());
|
||||||
|
assert_eq!(router.recognize(&mut req), Some(0));
|
||||||
|
let resource = req.resource();
|
||||||
|
assert_eq!(resource.name(), "r1");
|
||||||
|
|
||||||
|
let mut req = TestRequest::with_uri("/test.json")
|
||||||
|
.finish_with_router(router.clone());
|
||||||
|
assert_eq!(router.recognize(&mut req), Some(1));
|
||||||
|
let resource = req.resource();
|
||||||
|
assert_eq!(resource.name(), "r2");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ use application::{App, HttpApplication};
|
|||||||
use param::Params;
|
use param::Params;
|
||||||
use router::Router;
|
use router::Router;
|
||||||
use payload::Payload;
|
use payload::Payload;
|
||||||
use resource::Resource;
|
use resource::ResourceHandler;
|
||||||
use httprequest::HttpRequest;
|
use httprequest::HttpRequest;
|
||||||
use httpresponse::HttpResponse;
|
use httpresponse::HttpResponse;
|
||||||
use server::{HttpServer, IntoHttpHandler, ServerSettings};
|
use server::{HttpServer, IntoHttpHandler, ServerSettings};
|
||||||
@ -352,7 +352,7 @@ impl<S: 'static> TestApp<S> {
|
|||||||
/// Register resource. This method is similar
|
/// Register resource. This method is similar
|
||||||
/// to `App::resource()` method.
|
/// to `App::resource()` method.
|
||||||
pub fn resource<F>(&mut self, path: &str, f: F) -> &mut TestApp<S>
|
pub fn resource<F>(&mut self, path: &str, f: F) -> &mut TestApp<S>
|
||||||
where F: FnOnce(&mut Resource<S>) + 'static
|
where F: FnOnce(&mut ResourceHandler<S>) + 'static
|
||||||
{
|
{
|
||||||
self.app = Some(self.app.take().unwrap().resource(path, f));
|
self.app = Some(self.app.take().unwrap().resource(path, f));
|
||||||
self
|
self
|
||||||
|
Loading…
Reference in New Issue
Block a user