mirror of
https://github.com/actix/actix-web.git
synced 2024-12-20 23:26:44 +00:00
add resource map, it allow to check if router has resource and it allows to generate urls for named resources
This commit is contained in:
parent
2f6df11183
commit
aadcdaa3d6
13 changed files with 361 additions and 18 deletions
|
@ -72,11 +72,13 @@ actix-utils = { git = "https://github.com/actix/actix-net.git" }
|
|||
actix-http = { git = "https://github.com/actix/actix-http.git" }
|
||||
actix-router = { git = "https://github.com/actix/actix-net.git" }
|
||||
actix-server = { git = "https://github.com/actix/actix-net.git" }
|
||||
#actix-router = { path="../actix-net/router" }
|
||||
|
||||
bytes = "0.4"
|
||||
derive_more = "0.14"
|
||||
encoding = "0.2"
|
||||
futures = "0.1"
|
||||
hashbrown = "0.1.8"
|
||||
log = "0.4"
|
||||
lazy_static = "1.2"
|
||||
mime = "0.3"
|
||||
|
@ -89,6 +91,7 @@ serde_json = "1.0"
|
|||
serde_urlencoded = "^0.5.3"
|
||||
threadpool = "1.7"
|
||||
time = "0.1"
|
||||
url = { version="1.7", features=["query_encoding"] }
|
||||
|
||||
# middlewares
|
||||
# actix-session = { path="session", optional = true }
|
||||
|
|
|
@ -1090,4 +1090,35 @@ mod tests {
|
|||
// assert_eq!(response.status(), StatusCode::OK);
|
||||
// }
|
||||
|
||||
#[test]
|
||||
fn test_path_buf() {
|
||||
assert_eq!(
|
||||
PathBuf::from_param("/test/.tt"),
|
||||
Err(UriSegmentError::BadStart('.'))
|
||||
);
|
||||
assert_eq!(
|
||||
PathBuf::from_param("/test/*tt"),
|
||||
Err(UriSegmentError::BadStart('*'))
|
||||
);
|
||||
assert_eq!(
|
||||
PathBuf::from_param("/test/tt:"),
|
||||
Err(UriSegmentError::BadEnd(':'))
|
||||
);
|
||||
assert_eq!(
|
||||
PathBuf::from_param("/test/tt<"),
|
||||
Err(UriSegmentError::BadEnd('<'))
|
||||
);
|
||||
assert_eq!(
|
||||
PathBuf::from_param("/test/tt>"),
|
||||
Err(UriSegmentError::BadEnd('>'))
|
||||
);
|
||||
assert_eq!(
|
||||
PathBuf::from_param("/seg1/seg2/"),
|
||||
Ok(PathBuf::from_iter(vec!["seg1", "seg2"]))
|
||||
);
|
||||
assert_eq!(
|
||||
PathBuf::from_param("/seg1/../seg2/"),
|
||||
Ok(PathBuf::from_iter(vec!["seg2"]))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
24
src/app.rs
24
src/app.rs
|
@ -16,6 +16,7 @@ use futures::{Async, Future, IntoFuture, Poll};
|
|||
use crate::config::AppConfig;
|
||||
use crate::guard::Guard;
|
||||
use crate::resource::Resource;
|
||||
use crate::rmap::ResourceMap;
|
||||
use crate::route::Route;
|
||||
use crate::service::{
|
||||
HttpServiceFactory, ServiceFactory, ServiceFactoryWrapper, ServiceRequest,
|
||||
|
@ -449,19 +450,29 @@ where
|
|||
.into_iter()
|
||||
.for_each(|mut srv| srv.register(&mut config));
|
||||
|
||||
// set factory
|
||||
let mut rmap = ResourceMap::new(ResourceDef::new(""));
|
||||
|
||||
// complete pipeline creation
|
||||
*self.factory_ref.borrow_mut() = Some(AppRoutingFactory {
|
||||
default,
|
||||
services: Rc::new(
|
||||
config
|
||||
.into_services()
|
||||
.into_iter()
|
||||
.map(|(rdef, srv, guards)| (rdef, srv, RefCell::new(guards)))
|
||||
.map(|(mut rdef, srv, guards, nested)| {
|
||||
rmap.add(&mut rdef, nested);
|
||||
(rdef, srv, RefCell::new(guards))
|
||||
})
|
||||
.collect(),
|
||||
),
|
||||
});
|
||||
|
||||
// complete ResourceMap tree creation
|
||||
let rmap = Rc::new(rmap);
|
||||
rmap.finish(rmap.clone());
|
||||
|
||||
AppInit {
|
||||
rmap,
|
||||
chain: self.chain,
|
||||
state: self.state,
|
||||
extensions: Rc::new(RefCell::new(Rc::new(self.extensions))),
|
||||
|
@ -561,8 +572,7 @@ impl<P> Future for AppRoutingFactoryResponse<P> {
|
|||
.fold(Router::build(), |mut router, item| {
|
||||
match item {
|
||||
CreateAppRoutingItem::Service(path, guards, service) => {
|
||||
router.rdef(path, service);
|
||||
router.set_user_data(guards);
|
||||
router.rdef(path, service).2 = guards;
|
||||
}
|
||||
CreateAppRoutingItem::Future(_, _, _) => unreachable!(),
|
||||
}
|
||||
|
@ -683,6 +693,7 @@ where
|
|||
C: NewService<ServiceRequest, Response = ServiceRequest<P>>,
|
||||
{
|
||||
chain: C,
|
||||
rmap: Rc<ResourceMap>,
|
||||
state: Vec<Box<StateFactory>>,
|
||||
extensions: Rc<RefCell<Rc<Extensions>>>,
|
||||
}
|
||||
|
@ -702,6 +713,7 @@ where
|
|||
chain: self.chain.new_service(&()),
|
||||
state: self.state.iter().map(|s| s.construct()).collect(),
|
||||
extensions: self.extensions.clone(),
|
||||
rmap: self.rmap.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -712,6 +724,7 @@ where
|
|||
C: NewService<ServiceRequest, Response = ServiceRequest<P>, InitError = ()>,
|
||||
{
|
||||
chain: C::Future,
|
||||
rmap: Rc<ResourceMap>,
|
||||
state: Vec<Box<StateFactoryResult>>,
|
||||
extensions: Rc<RefCell<Rc<Extensions>>>,
|
||||
}
|
||||
|
@ -744,6 +757,7 @@ where
|
|||
|
||||
Ok(Async::Ready(AppInitService {
|
||||
chain,
|
||||
rmap: self.rmap.clone(),
|
||||
extensions: self.extensions.borrow().clone(),
|
||||
}))
|
||||
}
|
||||
|
@ -755,6 +769,7 @@ where
|
|||
C: Service<ServiceRequest, Response = ServiceRequest<P>>,
|
||||
{
|
||||
chain: C,
|
||||
rmap: Rc<ResourceMap>,
|
||||
extensions: Rc<Extensions>,
|
||||
}
|
||||
|
||||
|
@ -774,6 +789,7 @@ where
|
|||
let req = ServiceRequest::new(
|
||||
Path::new(Url::new(req.uri().clone())),
|
||||
req,
|
||||
self.rmap.clone(),
|
||||
self.extensions.clone(),
|
||||
);
|
||||
self.chain.call(req)
|
||||
|
|
|
@ -5,6 +5,7 @@ use actix_router::ResourceDef;
|
|||
use actix_service::{boxed, IntoNewService, NewService};
|
||||
|
||||
use crate::guard::Guard;
|
||||
use crate::rmap::ResourceMap;
|
||||
use crate::service::{ServiceRequest, ServiceResponse};
|
||||
|
||||
type Guards = Vec<Box<Guard>>;
|
||||
|
@ -18,7 +19,12 @@ pub struct AppConfig<P> {
|
|||
host: String,
|
||||
root: bool,
|
||||
default: Rc<HttpNewService<P>>,
|
||||
services: Vec<(ResourceDef, HttpNewService<P>, Option<Guards>)>,
|
||||
services: Vec<(
|
||||
ResourceDef,
|
||||
HttpNewService<P>,
|
||||
Option<Guards>,
|
||||
Option<Rc<ResourceMap>>,
|
||||
)>,
|
||||
}
|
||||
|
||||
impl<P: 'static> AppConfig<P> {
|
||||
|
@ -46,7 +52,12 @@ impl<P: 'static> AppConfig<P> {
|
|||
|
||||
pub(crate) fn into_services(
|
||||
self,
|
||||
) -> Vec<(ResourceDef, HttpNewService<P>, Option<Guards>)> {
|
||||
) -> Vec<(
|
||||
ResourceDef,
|
||||
HttpNewService<P>,
|
||||
Option<Guards>,
|
||||
Option<Rc<ResourceMap>>,
|
||||
)> {
|
||||
self.services
|
||||
}
|
||||
|
||||
|
@ -85,6 +96,7 @@ impl<P: 'static> AppConfig<P> {
|
|||
rdef: ResourceDef,
|
||||
guards: Option<Vec<Box<Guard>>>,
|
||||
service: F,
|
||||
nested: Option<Rc<ResourceMap>>,
|
||||
) where
|
||||
F: IntoNewService<S, ServiceRequest<P>>,
|
||||
S: NewService<
|
||||
|
@ -98,6 +110,7 @@ impl<P: 'static> AppConfig<P> {
|
|||
rdef,
|
||||
boxed::new_service(service.into_new_service()),
|
||||
guards,
|
||||
nested,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
20
src/error.rs
Normal file
20
src/error.rs
Normal file
|
@ -0,0 +1,20 @@
|
|||
pub use actix_http::error::*;
|
||||
use derive_more::{Display, From};
|
||||
use url::ParseError as UrlParseError;
|
||||
|
||||
/// Errors which can occur when attempting to generate resource uri.
|
||||
#[derive(Debug, PartialEq, Display, From)]
|
||||
pub enum UrlGenerationError {
|
||||
/// Resource not found
|
||||
#[display(fmt = "Resource not found")]
|
||||
ResourceNotFound,
|
||||
/// Not all path pattern covered
|
||||
#[display(fmt = "Not all path pattern covered")]
|
||||
NotEnoughElements,
|
||||
/// URL parse error
|
||||
#[display(fmt = "{}", _0)]
|
||||
ParseError(UrlParseError),
|
||||
}
|
||||
|
||||
/// `InternalServerError` for `UrlGeneratorError`
|
||||
impl ResponseError for UrlGenerationError {}
|
|
@ -6,11 +6,13 @@ mod handler;
|
|||
// mod info;
|
||||
pub mod blocking;
|
||||
mod config;
|
||||
pub mod error;
|
||||
pub mod guard;
|
||||
pub mod middleware;
|
||||
mod request;
|
||||
mod resource;
|
||||
mod responder;
|
||||
mod rmap;
|
||||
mod route;
|
||||
mod scope;
|
||||
mod server;
|
||||
|
@ -27,7 +29,7 @@ pub use actix_web_codegen::*;
|
|||
|
||||
// re-export for convenience
|
||||
pub use actix_http::Response as HttpResponse;
|
||||
pub use actix_http::{error, http, Error, HttpMessage, ResponseError, Result};
|
||||
pub use actix_http::{http, Error, HttpMessage, ResponseError, Result};
|
||||
|
||||
pub use crate::app::App;
|
||||
pub use crate::extract::FromRequest;
|
||||
|
|
|
@ -7,7 +7,9 @@ use actix_http::http::{HeaderMap, Method, Uri, Version};
|
|||
use actix_http::{Error, Extensions, HttpMessage, Message, Payload, RequestHead};
|
||||
use actix_router::{Path, Url};
|
||||
|
||||
use crate::error::UrlGenerationError;
|
||||
use crate::extract::FromRequest;
|
||||
use crate::rmap::ResourceMap;
|
||||
use crate::service::ServiceFromRequest;
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -15,6 +17,7 @@ use crate::service::ServiceFromRequest;
|
|||
pub struct HttpRequest {
|
||||
pub(crate) head: Message<RequestHead>,
|
||||
pub(crate) path: Path<Url>,
|
||||
rmap: Rc<ResourceMap>,
|
||||
extensions: Rc<Extensions>,
|
||||
}
|
||||
|
||||
|
@ -23,11 +26,13 @@ impl HttpRequest {
|
|||
pub(crate) fn new(
|
||||
head: Message<RequestHead>,
|
||||
path: Path<Url>,
|
||||
rmap: Rc<ResourceMap>,
|
||||
extensions: Rc<Extensions>,
|
||||
) -> HttpRequest {
|
||||
HttpRequest {
|
||||
head,
|
||||
path,
|
||||
rmap,
|
||||
extensions,
|
||||
}
|
||||
}
|
||||
|
@ -93,6 +98,47 @@ impl HttpRequest {
|
|||
&self.extensions
|
||||
}
|
||||
|
||||
/// Generate url for named resource
|
||||
///
|
||||
/// ```rust
|
||||
/// # extern crate actix_web;
|
||||
/// # use actix_web::{App, HttpRequest, HttpResponse, http};
|
||||
/// #
|
||||
/// fn index(req: HttpRequest) -> HttpResponse {
|
||||
/// let url = req.url_for("foo", &["1", "2", "3"]); // <- generate url for "foo" resource
|
||||
/// HttpResponse::Ok().into()
|
||||
/// }
|
||||
///
|
||||
/// fn main() {
|
||||
/// let app = App::new()
|
||||
/// .resource("/test/{one}/{two}/{three}", |r| {
|
||||
/// r.name("foo"); // <- set resource name, then it could be used in `url_for`
|
||||
/// r.method(http::Method::GET).f(|_| HttpResponse::Ok());
|
||||
/// })
|
||||
/// .finish();
|
||||
/// }
|
||||
/// ```
|
||||
pub fn url_for<U, I>(
|
||||
&self,
|
||||
name: &str,
|
||||
elements: U,
|
||||
) -> Result<url::Url, UrlGenerationError>
|
||||
where
|
||||
U: IntoIterator<Item = I>,
|
||||
I: AsRef<str>,
|
||||
{
|
||||
self.rmap.url_for(&self, name, elements)
|
||||
}
|
||||
|
||||
/// Generate url for named resource
|
||||
///
|
||||
/// This method is similar to `HttpRequest::url_for()` but it can be used
|
||||
/// for urls that do not contain variable parts.
|
||||
pub fn url_for_static(&self, name: &str) -> Result<url::Url, UrlGenerationError> {
|
||||
const NO_PARAMS: [&str; 0] = [];
|
||||
self.url_for(name, &NO_PARAMS)
|
||||
}
|
||||
|
||||
// /// Get *ConnectionInfo* for the correct request.
|
||||
// #[inline]
|
||||
// pub fn connection_info(&self) -> Ref<ConnectionInfo> {
|
||||
|
|
|
@ -288,7 +288,7 @@ where
|
|||
} else {
|
||||
ResourceDef::new(&self.rdef)
|
||||
};
|
||||
config.register_service(rdef, guards, self)
|
||||
config.register_service(rdef, guards, self, None)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
188
src/rmap.rs
Normal file
188
src/rmap.rs
Normal file
|
@ -0,0 +1,188 @@
|
|||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
use actix_router::ResourceDef;
|
||||
use hashbrown::HashMap;
|
||||
use url::Url;
|
||||
|
||||
use crate::error::UrlGenerationError;
|
||||
use crate::request::HttpRequest;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ResourceMap {
|
||||
root: ResourceDef,
|
||||
parent: RefCell<Option<Rc<ResourceMap>>>,
|
||||
named: HashMap<String, ResourceDef>,
|
||||
patterns: Vec<(ResourceDef, Option<Rc<ResourceMap>>)>,
|
||||
}
|
||||
|
||||
impl ResourceMap {
|
||||
pub fn new(root: ResourceDef) -> Self {
|
||||
ResourceMap {
|
||||
root,
|
||||
parent: RefCell::new(None),
|
||||
named: HashMap::new(),
|
||||
patterns: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add(&mut self, pattern: &mut ResourceDef, nested: Option<Rc<ResourceMap>>) {
|
||||
pattern.set_id(self.patterns.len() as u16);
|
||||
self.patterns.push((pattern.clone(), nested));
|
||||
if !pattern.name().is_empty() {
|
||||
self.named
|
||||
.insert(pattern.name().to_string(), pattern.clone());
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn finish(&self, current: Rc<ResourceMap>) {
|
||||
for (_, nested) in &self.patterns {
|
||||
if let Some(ref nested) = nested {
|
||||
*nested.parent.borrow_mut() = Some(current.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ResourceMap {
|
||||
/// Generate url for named resource
|
||||
///
|
||||
/// Check [`HttpRequest::url_for()`](../struct.HttpRequest.html#method.
|
||||
/// url_for) for detailed information.
|
||||
pub fn url_for<U, I>(
|
||||
&self,
|
||||
req: &HttpRequest,
|
||||
name: &str,
|
||||
elements: U,
|
||||
) -> Result<Url, UrlGenerationError>
|
||||
where
|
||||
U: IntoIterator<Item = I>,
|
||||
I: AsRef<str>,
|
||||
{
|
||||
let mut path = String::new();
|
||||
let mut elements = elements.into_iter();
|
||||
|
||||
if self.patterns_for(name, &mut path, &mut elements)?.is_some() {
|
||||
if path.starts_with('/') {
|
||||
// let conn = req.connection_info();
|
||||
// Ok(Url::parse(&format!(
|
||||
// "{}://{}{}",
|
||||
// conn.scheme(),
|
||||
// conn.host(),
|
||||
// path
|
||||
// ))?)
|
||||
unimplemented!()
|
||||
} else {
|
||||
Ok(Url::parse(&path)?)
|
||||
}
|
||||
} else {
|
||||
Err(UrlGenerationError::ResourceNotFound)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn has_resource(&self, path: &str) -> bool {
|
||||
let path = if path.is_empty() { "/" } else { path };
|
||||
|
||||
for (pattern, rmap) in &self.patterns {
|
||||
if let Some(ref rmap) = rmap {
|
||||
if let Some(plen) = pattern.is_prefix_match(path) {
|
||||
return rmap.has_resource(&path[plen..]);
|
||||
}
|
||||
} else if pattern.is_match(path) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
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)?;
|
||||
if pattern.resource_path(path, elements) {
|
||||
Ok(Some(()))
|
||||
} else {
|
||||
Err(UrlGenerationError::NotEnoughElements)
|
||||
}
|
||||
} else {
|
||||
for (_, rmap) in &self.patterns {
|
||||
if let Some(ref rmap) = rmap {
|
||||
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)?;
|
||||
}
|
||||
if self.root.resource_path(path, elements) {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(UrlGenerationError::NotEnoughElements)
|
||||
}
|
||||
}
|
||||
|
||||
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)?;
|
||||
if pattern.resource_path(path, elements) {
|
||||
Ok(Some(()))
|
||||
} else {
|
||||
Err(UrlGenerationError::NotEnoughElements)
|
||||
}
|
||||
} else {
|
||||
parent.parent_pattern_for(name, path, elements)
|
||||
}
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
19
src/scope.rs
19
src/scope.rs
|
@ -13,6 +13,7 @@ use futures::{Async, Poll};
|
|||
use crate::dev::{AppConfig, HttpServiceFactory};
|
||||
use crate::guard::Guard;
|
||||
use crate::resource::Resource;
|
||||
use crate::rmap::ResourceMap;
|
||||
use crate::route::Route;
|
||||
use crate::service::{
|
||||
ServiceFactory, ServiceFactoryWrapper, ServiceRequest, ServiceResponse,
|
||||
|
@ -237,35 +238,46 @@ where
|
|||
> + 'static,
|
||||
{
|
||||
fn register(self, config: &mut AppConfig<P>) {
|
||||
// update default resource if needed
|
||||
if self.default.borrow().is_none() {
|
||||
*self.default.borrow_mut() = Some(config.default_service());
|
||||
}
|
||||
|
||||
// register services
|
||||
// register nested services
|
||||
let mut cfg = config.clone_config();
|
||||
self.services
|
||||
.into_iter()
|
||||
.for_each(|mut srv| srv.register(&mut cfg));
|
||||
|
||||
let mut rmap = ResourceMap::new(ResourceDef::root_prefix(&self.rdef));
|
||||
|
||||
// complete scope pipeline creation
|
||||
*self.factory_ref.borrow_mut() = Some(ScopeFactory {
|
||||
default: self.default.clone(),
|
||||
services: Rc::new(
|
||||
cfg.into_services()
|
||||
.into_iter()
|
||||
.map(|(rdef, srv, guards)| (rdef, srv, RefCell::new(guards)))
|
||||
.map(|(mut rdef, srv, guards, nested)| {
|
||||
rmap.add(&mut rdef, nested);
|
||||
(rdef, srv, RefCell::new(guards))
|
||||
})
|
||||
.collect(),
|
||||
),
|
||||
});
|
||||
|
||||
// get guards
|
||||
let guards = if self.guards.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(self.guards)
|
||||
};
|
||||
|
||||
// register final service
|
||||
config.register_service(
|
||||
ResourceDef::root_prefix(&self.rdef),
|
||||
guards,
|
||||
self.endpoint,
|
||||
Some(Rc::new(rmap)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -367,8 +379,7 @@ impl<P> Future for ScopeFactoryResponse<P> {
|
|||
.fold(Router::build(), |mut router, item| {
|
||||
match item {
|
||||
CreateScopeServiceItem::Service(path, guards, service) => {
|
||||
router.rdef(path, service);
|
||||
router.set_user_data(guards);
|
||||
router.rdef(path, service).2 = guards;
|
||||
}
|
||||
CreateScopeServiceItem::Future(_, _, _) => unreachable!(),
|
||||
}
|
||||
|
|
|
@ -230,7 +230,7 @@ where
|
|||
///
|
||||
/// HttpServer does not change any configuration for TcpListener,
|
||||
/// it needs to be configured before passing it to listen() method.
|
||||
pub fn listen(mut self, lst: net::TcpListener) -> Self {
|
||||
pub fn listen(mut self, lst: net::TcpListener) -> io::Result<Self> {
|
||||
let cfg = self.config.clone();
|
||||
let factory = self.factory.clone();
|
||||
let addr = lst.local_addr().unwrap();
|
||||
|
@ -248,9 +248,9 @@ where
|
|||
ServiceConfig::new(c.keep_alive, c.client_timeout, 0);
|
||||
HttpService::with_config(service_config, factory())
|
||||
},
|
||||
));
|
||||
)?);
|
||||
|
||||
self
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
#[cfg(feature = "tls")]
|
||||
|
@ -328,7 +328,7 @@ where
|
|||
let sockets = self.bind2(addr)?;
|
||||
|
||||
for lst in sockets {
|
||||
self = self.listen(lst);
|
||||
self = self.listen(lst)?;
|
||||
}
|
||||
|
||||
Ok(self)
|
||||
|
|
|
@ -15,6 +15,7 @@ use futures::future::{ok, FutureResult, IntoFuture};
|
|||
|
||||
use crate::config::AppConfig;
|
||||
use crate::request::HttpRequest;
|
||||
use crate::rmap::ResourceMap;
|
||||
|
||||
pub trait HttpServiceFactory<P> {
|
||||
fn register(self, config: &mut AppConfig<P>);
|
||||
|
@ -58,12 +59,13 @@ impl<P> ServiceRequest<P> {
|
|||
pub(crate) fn new(
|
||||
path: Path<Url>,
|
||||
request: Request<P>,
|
||||
rmap: Rc<ResourceMap>,
|
||||
extensions: Rc<Extensions>,
|
||||
) -> Self {
|
||||
let (head, payload) = request.into_parts();
|
||||
ServiceRequest {
|
||||
payload,
|
||||
req: HttpRequest::new(head, path, extensions),
|
||||
req: HttpRequest::new(head, path, rmap, extensions),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
13
src/test.rs
13
src/test.rs
|
@ -6,13 +6,14 @@ use actix_http::http::header::{Header, HeaderName, IntoHeaderValue};
|
|||
use actix_http::http::{HttpTryFrom, Method, Version};
|
||||
use actix_http::test::TestRequest as HttpTestRequest;
|
||||
use actix_http::{Extensions, PayloadStream, Request};
|
||||
use actix_router::{Path, Url};
|
||||
use actix_router::{Path, ResourceDef, Url};
|
||||
use actix_rt::Runtime;
|
||||
use actix_service::{IntoNewService, NewService, Service};
|
||||
use bytes::Bytes;
|
||||
use futures::Future;
|
||||
|
||||
use crate::request::HttpRequest;
|
||||
use crate::rmap::ResourceMap;
|
||||
use crate::service::{ServiceFromRequest, ServiceRequest, ServiceResponse};
|
||||
|
||||
thread_local! {
|
||||
|
@ -135,6 +136,7 @@ where
|
|||
pub struct TestRequest {
|
||||
req: HttpTestRequest,
|
||||
extensions: Extensions,
|
||||
rmap: ResourceMap,
|
||||
}
|
||||
|
||||
impl Default for TestRequest {
|
||||
|
@ -142,6 +144,7 @@ impl Default for TestRequest {
|
|||
TestRequest {
|
||||
req: HttpTestRequest::default(),
|
||||
extensions: Extensions::new(),
|
||||
rmap: ResourceMap::new(ResourceDef::new("")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -152,6 +155,7 @@ impl TestRequest {
|
|||
TestRequest {
|
||||
req: HttpTestRequest::default().uri(path).take(),
|
||||
extensions: Extensions::new(),
|
||||
rmap: ResourceMap::new(ResourceDef::new("")),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -160,6 +164,7 @@ impl TestRequest {
|
|||
TestRequest {
|
||||
req: HttpTestRequest::default().set(hdr).take(),
|
||||
extensions: Extensions::new(),
|
||||
rmap: ResourceMap::new(ResourceDef::new("")),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -172,6 +177,7 @@ impl TestRequest {
|
|||
TestRequest {
|
||||
req: HttpTestRequest::default().header(key, value).take(),
|
||||
extensions: Extensions::new(),
|
||||
rmap: ResourceMap::new(ResourceDef::new("")),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -180,6 +186,7 @@ impl TestRequest {
|
|||
TestRequest {
|
||||
req: HttpTestRequest::default().method(Method::GET).take(),
|
||||
extensions: Extensions::new(),
|
||||
rmap: ResourceMap::new(ResourceDef::new("")),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -188,6 +195,7 @@ impl TestRequest {
|
|||
TestRequest {
|
||||
req: HttpTestRequest::default().method(Method::POST).take(),
|
||||
extensions: Extensions::new(),
|
||||
rmap: ResourceMap::new(ResourceDef::new("")),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -244,6 +252,7 @@ impl TestRequest {
|
|||
ServiceRequest::new(
|
||||
Path::new(Url::new(req.uri().clone())),
|
||||
req,
|
||||
Rc::new(self.rmap),
|
||||
Rc::new(self.extensions),
|
||||
)
|
||||
}
|
||||
|
@ -260,6 +269,7 @@ impl TestRequest {
|
|||
ServiceRequest::new(
|
||||
Path::new(Url::new(req.uri().clone())),
|
||||
req,
|
||||
Rc::new(self.rmap),
|
||||
Rc::new(self.extensions),
|
||||
)
|
||||
.into_request()
|
||||
|
@ -272,6 +282,7 @@ impl TestRequest {
|
|||
let req = ServiceRequest::new(
|
||||
Path::new(Url::new(req.uri().clone())),
|
||||
req,
|
||||
Rc::new(self.rmap),
|
||||
Rc::new(self.extensions),
|
||||
);
|
||||
ServiceFromRequest::new(req, None)
|
||||
|
|
Loading…
Reference in a new issue