mirror of
https://github.com/actix/actix-web.git
synced 2024-11-20 08:31:09 +00:00
added Logger middleware
This commit is contained in:
parent
561a89b8b3
commit
244fff9e0a
9 changed files with 279 additions and 150 deletions
|
@ -81,10 +81,12 @@ mime = "0.3"
|
|||
net2 = "0.2.33"
|
||||
num_cpus = "1.10"
|
||||
parking_lot = "0.7"
|
||||
regex = "1.0"
|
||||
serde = "1.0"
|
||||
serde_json = "1.0"
|
||||
serde_urlencoded = "^0.5.3"
|
||||
threadpool = "1.7"
|
||||
time = "0.1"
|
||||
|
||||
# middlewares
|
||||
# actix-session = { path="session", optional = true }
|
||||
|
|
|
@ -451,7 +451,7 @@ where
|
|||
|
||||
// set factory
|
||||
*self.factory_ref.borrow_mut() = Some(AppRoutingFactory {
|
||||
default: default,
|
||||
default,
|
||||
services: Rc::new(
|
||||
config
|
||||
.into_services()
|
||||
|
@ -784,7 +784,7 @@ where
|
|||
mod tests {
|
||||
use super::*;
|
||||
use crate::http::{Method, StatusCode};
|
||||
use crate::test::{self, block_on, init_service, TestRequest};
|
||||
use crate::test::{block_on, init_service, TestRequest};
|
||||
use crate::{web, HttpResponse, State};
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -48,7 +48,7 @@ pub mod dev {
|
|||
pub use crate::config::AppConfig;
|
||||
pub use crate::service::HttpServiceFactory;
|
||||
|
||||
pub use actix_http::body::{Body, MessageBody, ResponseBody};
|
||||
pub use actix_http::body::{Body, BodyLength, MessageBody, ResponseBody};
|
||||
pub use actix_http::dev::ResponseBuilder as HttpResponseBuilder;
|
||||
pub use actix_http::{
|
||||
Extensions, Payload, PayloadStream, RequestHead, ResponseHead,
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
//! Middleware for setting default response headers
|
||||
use std::rc::Rc;
|
||||
|
||||
use actix_http::http::header::{HeaderName, HeaderValue, CONTENT_TYPE};
|
||||
use actix_http::http::{HeaderMap, HttpTryFrom};
|
||||
use actix_service::{Service, Transform};
|
||||
use futures::future::{ok, FutureResult};
|
||||
use futures::{Future, Poll};
|
||||
|
||||
use crate::http::header::{HeaderName, HeaderValue, CONTENT_TYPE};
|
||||
use crate::http::{HeaderMap, HttpTryFrom};
|
||||
use crate::service::{ServiceRequest, ServiceResponse};
|
||||
|
||||
/// `Middleware` for setting default response headers.
|
||||
|
@ -147,10 +147,10 @@ where
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use actix_http::http::header::CONTENT_TYPE;
|
||||
use actix_service::FnService;
|
||||
|
||||
use super::*;
|
||||
use crate::http::header::CONTENT_TYPE;
|
||||
use crate::test::{block_on, TestRequest};
|
||||
use crate::{HttpResponse, ServiceRequest};
|
||||
|
||||
|
|
|
@ -2,15 +2,19 @@
|
|||
use std::collections::HashSet;
|
||||
use std::env;
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
use std::rc::Rc;
|
||||
|
||||
use actix_service::{Service, Transform};
|
||||
use bytes::Bytes;
|
||||
use futures::future::{ok, FutureResult};
|
||||
use futures::{Async, Future, Poll};
|
||||
use regex::Regex;
|
||||
use time;
|
||||
|
||||
use error::Result;
|
||||
use httpmessage::HttpMessage;
|
||||
use httprequest::HttpRequest;
|
||||
use httpresponse::HttpResponse;
|
||||
use middleware::{Finished, Middleware, Started};
|
||||
use crate::dev::{BodyLength, MessageBody, ResponseBody};
|
||||
use crate::error::{Error, Result};
|
||||
use crate::service::{ServiceRequest, ServiceResponse};
|
||||
use crate::{HttpMessage, HttpResponse};
|
||||
|
||||
/// `Middleware` for logging request and response info to the terminal.
|
||||
///
|
||||
|
@ -69,7 +73,9 @@ use middleware::{Finished, Middleware, Started};
|
|||
///
|
||||
/// `%{FOO}e` os.environ['FOO']
|
||||
///
|
||||
pub struct Logger {
|
||||
pub struct Logger(Rc<Inner>);
|
||||
|
||||
struct Inner {
|
||||
format: Format,
|
||||
exclude: HashSet<String>,
|
||||
}
|
||||
|
@ -77,15 +83,18 @@ pub struct Logger {
|
|||
impl Logger {
|
||||
/// Create `Logger` middleware with the specified `format`.
|
||||
pub fn new(format: &str) -> Logger {
|
||||
Logger {
|
||||
Logger(Rc::new(Inner {
|
||||
format: Format::new(format),
|
||||
exclude: HashSet::new(),
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
/// Ignore and do not log access info for specified path.
|
||||
pub fn exclude<T: Into<String>>(mut self, path: T) -> Self {
|
||||
self.exclude.insert(path.into());
|
||||
Rc::get_mut(&mut self.0)
|
||||
.unwrap()
|
||||
.exclude
|
||||
.insert(path.into());
|
||||
self
|
||||
}
|
||||
}
|
||||
|
@ -97,40 +106,147 @@ impl Default for Logger {
|
|||
/// %a "%r" %s %b "%{Referer}i" "%{User-Agent}i" %T
|
||||
/// ```
|
||||
fn default() -> Logger {
|
||||
Logger {
|
||||
Logger(Rc::new(Inner {
|
||||
format: Format::default(),
|
||||
exclude: HashSet::new(),
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl<S, P, B> Transform<S, ServiceRequest<P>> for Logger
|
||||
where
|
||||
S: Service<ServiceRequest<P>, Response = ServiceResponse<B>>,
|
||||
B: MessageBody,
|
||||
{
|
||||
type Response = ServiceResponse<StreamLog<B>>;
|
||||
type Error = S::Error;
|
||||
type InitError = ();
|
||||
type Transform = LoggerMiddleware<S>;
|
||||
type Future = FutureResult<Self::Transform, Self::InitError>;
|
||||
|
||||
fn new_transform(&self, service: S) -> Self::Future {
|
||||
ok(LoggerMiddleware {
|
||||
service,
|
||||
inner: self.0.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Logger middleware
|
||||
pub struct LoggerMiddleware<S> {
|
||||
inner: Rc<Inner>,
|
||||
service: S,
|
||||
}
|
||||
|
||||
impl<S, P, B> Service<ServiceRequest<P>> for LoggerMiddleware<S>
|
||||
where
|
||||
S: Service<ServiceRequest<P>, Response = ServiceResponse<B>>,
|
||||
B: MessageBody,
|
||||
{
|
||||
type Response = ServiceResponse<StreamLog<B>>;
|
||||
type Error = S::Error;
|
||||
type Future = LoggerResponse<S, P, B>;
|
||||
|
||||
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
||||
self.service.poll_ready()
|
||||
}
|
||||
|
||||
fn call(&mut self, req: ServiceRequest<P>) -> Self::Future {
|
||||
if self.inner.exclude.contains(req.path()) {
|
||||
LoggerResponse {
|
||||
fut: self.service.call(req),
|
||||
format: None,
|
||||
time: time::now(),
|
||||
}
|
||||
} else {
|
||||
let now = time::now();
|
||||
let mut format = self.inner.format.clone();
|
||||
|
||||
for unit in &mut format.0 {
|
||||
unit.render_request(now, &req);
|
||||
}
|
||||
LoggerResponse {
|
||||
fut: self.service.call(req),
|
||||
format: Some(format),
|
||||
time: now,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct StartTime(time::Tm);
|
||||
#[doc(hidden)]
|
||||
pub struct LoggerResponse<S, P, B>
|
||||
where
|
||||
B: MessageBody,
|
||||
S: Service<ServiceRequest<P>, Response = ServiceResponse<B>>,
|
||||
{
|
||||
fut: S::Future,
|
||||
time: time::Tm,
|
||||
format: Option<Format>,
|
||||
}
|
||||
|
||||
impl Logger {
|
||||
fn log<S>(&self, req: &HttpRequest<S>, resp: &HttpResponse) {
|
||||
if let Some(entry_time) = req.extensions().get::<StartTime>() {
|
||||
impl<S, P, B> Future for LoggerResponse<S, P, B>
|
||||
where
|
||||
B: MessageBody,
|
||||
S: Service<ServiceRequest<P>, Response = ServiceResponse<B>>,
|
||||
{
|
||||
type Item = ServiceResponse<StreamLog<B>>;
|
||||
type Error = S::Error;
|
||||
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
let res = futures::try_ready!(self.fut.poll());
|
||||
|
||||
if let Some(ref mut format) = self.format {
|
||||
for unit in &mut format.0 {
|
||||
unit.render_response(&res);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Async::Ready(res.map_body(move |_, body| {
|
||||
ResponseBody::Body(StreamLog {
|
||||
body,
|
||||
size: 0,
|
||||
time: self.time,
|
||||
format: self.format.take(),
|
||||
})
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct StreamLog<B> {
|
||||
body: ResponseBody<B>,
|
||||
format: Option<Format>,
|
||||
size: usize,
|
||||
time: time::Tm,
|
||||
}
|
||||
|
||||
impl<B> Drop for StreamLog<B> {
|
||||
fn drop(&mut self) {
|
||||
if let Some(ref format) = self.format {
|
||||
let render = |fmt: &mut Formatter| {
|
||||
for unit in &self.format.0 {
|
||||
unit.render(fmt, req, resp, entry_time.0)?;
|
||||
for unit in &format.0 {
|
||||
unit.render(fmt, self.size, self.time)?;
|
||||
}
|
||||
Ok(())
|
||||
};
|
||||
info!("{}", FormatDisplay(&render));
|
||||
log::info!("{}", FormatDisplay(&render));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Middleware<S> for Logger {
|
||||
fn start(&self, req: &HttpRequest<S>) -> Result<Started> {
|
||||
if !self.exclude.contains(req.path()) {
|
||||
req.extensions_mut().insert(StartTime(time::now()));
|
||||
}
|
||||
Ok(Started::Done)
|
||||
impl<B: MessageBody> MessageBody for StreamLog<B> {
|
||||
fn length(&self) -> BodyLength {
|
||||
self.body.length()
|
||||
}
|
||||
|
||||
fn finish(&self, req: &HttpRequest<S>, resp: &HttpResponse) -> Finished {
|
||||
self.log(req, resp);
|
||||
Finished::Done
|
||||
fn poll_next(&mut self) -> Poll<Option<Bytes>, Error> {
|
||||
match self.body.poll_next()? {
|
||||
Async::Ready(Some(chunk)) => {
|
||||
self.size += chunk.len();
|
||||
Ok(Async::Ready(Some(chunk)))
|
||||
}
|
||||
val => Ok(val),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -152,7 +268,7 @@ impl Format {
|
|||
///
|
||||
/// Returns `None` if the format string syntax is incorrect.
|
||||
pub fn new(s: &str) -> Format {
|
||||
trace!("Access log format: {}", s);
|
||||
log::trace!("Access log format: {}", s);
|
||||
let fmt = Regex::new(r"%(\{([A-Za-z0-9\-_]+)\}([ioe])|[atPrsbTD]?)").unwrap();
|
||||
|
||||
let mut idx = 0;
|
||||
|
@ -215,33 +331,16 @@ pub enum FormatText {
|
|||
}
|
||||
|
||||
impl FormatText {
|
||||
fn render<S>(
|
||||
&self, fmt: &mut Formatter, req: &HttpRequest<S>, resp: &HttpResponse,
|
||||
fn render(
|
||||
&self,
|
||||
fmt: &mut Formatter,
|
||||
size: usize,
|
||||
entry_time: time::Tm,
|
||||
) -> Result<(), fmt::Error> {
|
||||
match *self {
|
||||
FormatText::Str(ref string) => fmt.write_str(string),
|
||||
FormatText::Percent => "%".fmt(fmt),
|
||||
FormatText::RequestLine => {
|
||||
if req.query_string().is_empty() {
|
||||
fmt.write_fmt(format_args!(
|
||||
"{} {} {:?}",
|
||||
req.method(),
|
||||
req.path(),
|
||||
req.version()
|
||||
))
|
||||
} else {
|
||||
fmt.write_fmt(format_args!(
|
||||
"{} {}?{} {:?}",
|
||||
req.method(),
|
||||
req.path(),
|
||||
req.query_string(),
|
||||
req.version()
|
||||
))
|
||||
}
|
||||
}
|
||||
FormatText::ResponseStatus => resp.status().as_u16().fmt(fmt),
|
||||
FormatText::ResponseSize => resp.response_size().fmt(fmt),
|
||||
FormatText::ResponseSize => size.fmt(fmt),
|
||||
FormatText::Time => {
|
||||
let rt = time::now() - entry_time;
|
||||
let rt = (rt.num_nanoseconds().unwrap_or(0) as f64) / 1_000_000_000.0;
|
||||
|
@ -252,17 +351,71 @@ impl FormatText {
|
|||
let rt = (rt.num_nanoseconds().unwrap_or(0) as f64) / 1_000_000.0;
|
||||
fmt.write_fmt(format_args!("{:.6}", rt))
|
||||
}
|
||||
FormatText::RemoteAddr => {
|
||||
if let Some(remote) = req.connection_info().remote() {
|
||||
return remote.fmt(fmt);
|
||||
// FormatText::RemoteAddr => {
|
||||
// if let Some(remote) = req.connection_info().remote() {
|
||||
// return remote.fmt(fmt);
|
||||
// } else {
|
||||
// "-".fmt(fmt)
|
||||
// }
|
||||
// }
|
||||
FormatText::EnvironHeader(ref name) => {
|
||||
if let Ok(val) = env::var(name) {
|
||||
fmt.write_fmt(format_args!("{}", val))
|
||||
} else {
|
||||
"-".fmt(fmt)
|
||||
}
|
||||
}
|
||||
FormatText::RequestTime => entry_time
|
||||
.strftime("[%d/%b/%Y:%H:%M:%S %z]")
|
||||
.unwrap()
|
||||
.fmt(fmt),
|
||||
_ => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
fn render_response<B>(&mut self, res: &HttpResponse<B>) {
|
||||
match *self {
|
||||
FormatText::ResponseStatus => {
|
||||
*self = FormatText::Str(format!("{}", res.status().as_u16()))
|
||||
}
|
||||
FormatText::ResponseHeader(ref name) => {
|
||||
let s = if let Some(val) = res.headers().get(name) {
|
||||
if let Ok(s) = val.to_str() {
|
||||
s
|
||||
} else {
|
||||
"-"
|
||||
}
|
||||
} else {
|
||||
"-"
|
||||
};
|
||||
*self = FormatText::Str(s.to_string())
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn render_request<P>(&mut self, now: time::Tm, req: &ServiceRequest<P>) {
|
||||
match *self {
|
||||
FormatText::RequestLine => {
|
||||
*self = if req.query_string().is_empty() {
|
||||
FormatText::Str(format!(
|
||||
"{} {} {:?}",
|
||||
req.method(),
|
||||
req.path(),
|
||||
req.version()
|
||||
))
|
||||
} else {
|
||||
FormatText::Str(format!(
|
||||
"{} {}?{} {:?}",
|
||||
req.method(),
|
||||
req.path(),
|
||||
req.query_string(),
|
||||
req.version()
|
||||
))
|
||||
};
|
||||
}
|
||||
FormatText::RequestTime => {
|
||||
*self = FormatText::Str(format!(
|
||||
"{:?}",
|
||||
now.strftime("[%d/%b/%Y:%H:%M:%S %z]").unwrap()
|
||||
))
|
||||
}
|
||||
FormatText::RequestHeader(ref name) => {
|
||||
let s = if let Some(val) = req.headers().get(name) {
|
||||
if let Ok(s) = val.to_str() {
|
||||
|
@ -273,27 +426,9 @@ impl FormatText {
|
|||
} else {
|
||||
"-"
|
||||
};
|
||||
fmt.write_fmt(format_args!("{}", s))
|
||||
}
|
||||
FormatText::ResponseHeader(ref name) => {
|
||||
let s = if let Some(val) = resp.headers().get(name) {
|
||||
if let Ok(s) = val.to_str() {
|
||||
s
|
||||
} else {
|
||||
"-"
|
||||
}
|
||||
} else {
|
||||
"-"
|
||||
};
|
||||
fmt.write_fmt(format_args!("{}", s))
|
||||
}
|
||||
FormatText::EnvironHeader(ref name) => {
|
||||
if let Ok(val) = env::var(name) {
|
||||
fmt.write_fmt(format_args!("{}", val))
|
||||
} else {
|
||||
"-".fmt(fmt)
|
||||
}
|
||||
*self = FormatText::Str(s.to_string());
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -308,77 +443,67 @@ impl<'a> fmt::Display for FormatDisplay<'a> {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use time;
|
||||
use actix_service::{FnService, Service, Transform};
|
||||
|
||||
use super::*;
|
||||
use http::{header, StatusCode};
|
||||
use test::TestRequest;
|
||||
use crate::http::{header, StatusCode};
|
||||
use crate::test::{block_on, TestRequest};
|
||||
|
||||
#[test]
|
||||
fn test_logger() {
|
||||
let srv = FnService::new(|req: ServiceRequest<_>| {
|
||||
req.into_response(
|
||||
HttpResponse::build(StatusCode::OK)
|
||||
.header("X-Test", "ttt")
|
||||
.finish(),
|
||||
)
|
||||
});
|
||||
let logger = Logger::new("%% %{User-Agent}i %{X-Test}o %{HOME}e %D test");
|
||||
|
||||
let req = TestRequest::with_header(
|
||||
header::USER_AGENT,
|
||||
header::HeaderValue::from_static("ACTIX-WEB"),
|
||||
).finish();
|
||||
let resp = HttpResponse::build(StatusCode::OK)
|
||||
.header("X-Test", "ttt")
|
||||
.force_close()
|
||||
.finish();
|
||||
|
||||
match logger.start(&req) {
|
||||
Ok(Started::Done) => (),
|
||||
_ => panic!(),
|
||||
};
|
||||
match logger.finish(&req, &resp) {
|
||||
Finished::Done => (),
|
||||
_ => panic!(),
|
||||
}
|
||||
let entry_time = time::now();
|
||||
let render = |fmt: &mut Formatter| {
|
||||
for unit in &logger.format.0 {
|
||||
unit.render(fmt, &req, &resp, entry_time)?;
|
||||
}
|
||||
Ok(())
|
||||
};
|
||||
let s = format!("{}", FormatDisplay(&render));
|
||||
assert!(s.contains("ACTIX-WEB ttt"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_default_format() {
|
||||
let format = Format::default();
|
||||
let mut srv = block_on(logger.new_transform(srv)).unwrap();
|
||||
|
||||
let req = TestRequest::with_header(
|
||||
header::USER_AGENT,
|
||||
header::HeaderValue::from_static("ACTIX-WEB"),
|
||||
).finish();
|
||||
let resp = HttpResponse::build(StatusCode::OK).force_close().finish();
|
||||
let entry_time = time::now();
|
||||
|
||||
let render = |fmt: &mut Formatter| {
|
||||
for unit in &format.0 {
|
||||
unit.render(fmt, &req, &resp, entry_time)?;
|
||||
}
|
||||
Ok(())
|
||||
};
|
||||
let s = format!("{}", FormatDisplay(&render));
|
||||
assert!(s.contains("GET / HTTP/1.1"));
|
||||
assert!(s.contains("200 0"));
|
||||
assert!(s.contains("ACTIX-WEB"));
|
||||
|
||||
let req = TestRequest::with_uri("/?test").finish();
|
||||
let resp = HttpResponse::build(StatusCode::OK).force_close().finish();
|
||||
let entry_time = time::now();
|
||||
|
||||
let render = |fmt: &mut Formatter| {
|
||||
for unit in &format.0 {
|
||||
unit.render(fmt, &req, &resp, entry_time)?;
|
||||
}
|
||||
Ok(())
|
||||
};
|
||||
let s = format!("{}", FormatDisplay(&render));
|
||||
assert!(s.contains("GET /?test HTTP/1.1"));
|
||||
)
|
||||
.to_service();
|
||||
let _res = block_on(srv.call(req));
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// fn test_default_format() {
|
||||
// let format = Format::default();
|
||||
|
||||
// let req = TestRequest::with_header(
|
||||
// header::USER_AGENT,
|
||||
// header::HeaderValue::from_static("ACTIX-WEB"),
|
||||
// )
|
||||
// .finish();
|
||||
// let resp = HttpResponse::build(StatusCode::OK).force_close().finish();
|
||||
// let entry_time = time::now();
|
||||
|
||||
// let render = |fmt: &mut Formatter| {
|
||||
// for unit in &format.0 {
|
||||
// unit.render(fmt, &req, &resp, entry_time)?;
|
||||
// }
|
||||
// Ok(())
|
||||
// };
|
||||
// let s = format!("{}", FormatDisplay(&render));
|
||||
// assert!(s.contains("GET / HTTP/1.1"));
|
||||
// assert!(s.contains("200 0"));
|
||||
// assert!(s.contains("ACTIX-WEB"));
|
||||
|
||||
// let req = TestRequest::with_uri("/?test").finish();
|
||||
// let resp = HttpResponse::build(StatusCode::OK).force_close().finish();
|
||||
// let entry_time = time::now();
|
||||
|
||||
// let render = |fmt: &mut Formatter| {
|
||||
// for unit in &format.0 {
|
||||
// unit.render(fmt, &req, &resp, entry_time)?;
|
||||
// }
|
||||
// Ok(())
|
||||
// };
|
||||
// let s = format!("{}", FormatDisplay(&render));
|
||||
// assert!(s.contains("GET /?test HTTP/1.1"));
|
||||
// }
|
||||
}
|
|
@ -8,3 +8,6 @@ pub use self::defaultheaders::DefaultHeaders;
|
|||
|
||||
#[cfg(feature = "session")]
|
||||
pub use actix_session as session;
|
||||
|
||||
mod logger;
|
||||
pub use self::logger::Logger;
|
||||
|
|
|
@ -286,7 +286,7 @@ where
|
|||
let rdef = if config.is_root() {
|
||||
ResourceDef::new(&insert_slash(&self.rdef))
|
||||
} else {
|
||||
ResourceDef::new(&insert_slash(&self.rdef))
|
||||
ResourceDef::new(&self.rdef)
|
||||
};
|
||||
config.register_service(rdef, guards, self)
|
||||
}
|
||||
|
|
|
@ -50,9 +50,8 @@ impl<P: 'static> Route<P> {
|
|||
let config_ref = Rc::new(RefCell::new(None));
|
||||
Route {
|
||||
service: Box::new(RouteNewService::new(
|
||||
Extract::new(config_ref.clone()).and_then(
|
||||
Handle::new(|| HttpResponse::NotFound()).map_err(|_| panic!()),
|
||||
),
|
||||
Extract::new(config_ref.clone())
|
||||
.and_then(Handle::new(HttpResponse::NotFound).map_err(|_| panic!())),
|
||||
)),
|
||||
guards: Rc::new(Vec::new()),
|
||||
config: ConfigStorage::default(),
|
||||
|
|
|
@ -10,7 +10,7 @@ use actix_service::{
|
|||
use futures::future::{ok, Either, Future, FutureResult};
|
||||
use futures::{Async, Poll};
|
||||
|
||||
use crate::dev::{insert_slash, AppConfig, HttpServiceFactory};
|
||||
use crate::dev::{AppConfig, HttpServiceFactory};
|
||||
use crate::guard::Guard;
|
||||
use crate::resource::Resource;
|
||||
use crate::route::Route;
|
||||
|
@ -263,9 +263,9 @@ where
|
|||
Some(self.guards)
|
||||
};
|
||||
let rdef = if config.is_root() {
|
||||
ResourceDef::prefix(&insert_slash(&self.rdef))
|
||||
ResourceDef::root_prefix(&self.rdef)
|
||||
} else {
|
||||
ResourceDef::prefix(&insert_slash(&self.rdef))
|
||||
ResourceDef::prefix(&self.rdef)
|
||||
};
|
||||
config.register_service(rdef, guards, self.endpoint)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue