1
0
mirror of https://github.com/fafhrd91/actix-web synced 2024-11-27 17:52:56 +01:00

add NormalizePath handler

This commit is contained in:
Nikolay Kim 2017-12-09 11:39:13 -08:00
parent 273de2260d
commit 7addd2800d
3 changed files with 93 additions and 2 deletions

View File

@ -50,7 +50,7 @@ after_success:
- |
if [[ "$TRAVIS_OS_NAME" == "linux" && "$TRAVIS_RUST_VERSION" == "stable" ]]; then
bash <(curl https://raw.githubusercontent.com/xd009642/tarpaulin/master/travis-install.sh)
cargo tarpaulin --out Xml
USE_SKEPTIC=1 cargo tarpaulin --out Xml
bash <(curl -s https://codecov.io/bash)
echo "Uploaded code coverage"
fi

View File

@ -4,7 +4,10 @@ use actix::Actor;
use futures::Future;
use serde_json;
use serde::Serialize;
use regex::Regex;
use http::{header, StatusCode, Error as HttpError};
use body::Body;
use error::Error;
use context::{HttpContext, IoContext};
use httprequest::HttpRequest;
@ -263,6 +266,94 @@ impl<T: Serialize> FromRequest for Json<T> {
}
}
/// Handler that normalizes the path of a request. By normalizing it means:
///
/// - Add a trailing slash to the path.
/// - Double slashes are replaced by one.
///
/// The handler returns as soon as it finds a path that resolves
/// correctly. The order if all enable is 1) merge, 2) append
/// and 3) both merge and append. If the path resolves with
/// at least one of those conditions, it will redirect to the new path.
///
/// If *append* is *true* append slash when needed. If a resource is
/// defined with trailing slash and the request comes without it, it will
/// append it automatically.
///
/// If *merge* is *true*, merge multiple consecutive slashes in the path into one.
///
/// This handler designed to be use as a handler for application's *default resource*.
pub struct NormalizePath {
append: bool,
merge: bool,
re_merge: Regex,
redirect: StatusCode,
not_found: StatusCode,
}
impl Default for NormalizePath {
fn default() -> NormalizePath {
NormalizePath {
append: true,
merge: true,
re_merge: Regex::new("//+").unwrap(),
redirect: StatusCode::MOVED_PERMANENTLY,
not_found: StatusCode::NOT_FOUND,
}
}
}
impl NormalizePath {
pub fn new(append: bool, merge: bool, redirect: StatusCode) -> NormalizePath {
NormalizePath {
append: append,
merge: merge,
re_merge: Regex::new("//+").unwrap(),
redirect: redirect,
not_found: StatusCode::NOT_FOUND,
}
}
}
impl<S> Handler<S> for NormalizePath {
type Result = Result<HttpResponse, HttpError>;
fn handle(&self, req: HttpRequest<S>) -> Self::Result {
if let Some(router) = req.router() {
if self.merge {
// merge slashes
let p = self.re_merge.replace_all(req.path(), "/");
if p.len() != req.path().len() {
if router.has_route(p.as_ref()) {
return HttpResponse::build(self.redirect)
.header(header::LOCATION, p.as_ref())
.body(Body::Empty);
}
// merge slashes and append trailing slash
if self.append && !p.ends_with('/') {
let p = p.as_ref().to_owned() + "/";
if router.has_route(&p) {
return HttpResponse::build(self.redirect)
.header(header::LOCATION, p.as_str())
.body(Body::Empty);
}
}
}
}
// append trailing slash
if self.append && !req.path().ends_with('/') {
let p = req.path().to_owned() + "/";
if router.has_route(&p) {
return HttpResponse::build(self.redirect)
.header(header::LOCATION, p.as_str())
.body(Body::Empty);
}
}
}
Ok(HttpResponse::new(self.not_found, Body::Empty))
}
}
#[cfg(test)]
mod tests {
use super::*;

View File

@ -87,7 +87,7 @@ pub use application::Application;
pub use httprequest::HttpRequest;
pub use httpresponse::HttpResponse;
pub use payload::{Payload, PayloadItem};
pub use handler::{Reply, Json, FromRequest};
pub use handler::{Reply, FromRequest, Json, NormalizePath};
pub use route::Route;
pub use resource::Resource;
pub use server::HttpServer;