1
0
Fork 0
mirror of https://github.com/actix/actix-web.git synced 2024-12-30 12:00:38 +00:00

Add Normalization middleware for in place (#783)

This commit is contained in:
Douman 2019-04-19 23:53:49 +03:00 committed by Nikolay Kim
parent bc40f5ae40
commit 1e7f97a111
2 changed files with 110 additions and 0 deletions

View file

@ -6,6 +6,7 @@ pub mod cors;
mod defaultheaders;
pub mod errhandlers;
mod logger;
pub mod normalize;
pub use self::defaultheaders::DefaultHeaders;
pub use self::logger::Logger;

109
src/middleware/normalize.rs Normal file
View file

@ -0,0 +1,109 @@
//! `Middleware` to normalize request's URI
use regex::Regex;
use actix_service::{Service, Transform};
use futures::future::{self, FutureResult};
use crate::service::{ServiceRequest, ServiceResponse};
#[derive(Default, Clone, Copy)]
/// `Middleware` to normalize request's URI in place
///
/// Performs following:
///
/// - Merges multiple slashes into one.
pub struct NormalizePath;
impl<S> Transform<S> for NormalizePath
where
S: Service<Request = ServiceRequest, Response = ServiceResponse>,
{
type Request = ServiceRequest;
type Response = ServiceResponse;
type Error = S::Error;
type InitError = ();
type Transform = NormalizePathNormalization<S>;
type Future = FutureResult<Self::Transform, Self::InitError>;
fn new_transform(&self, service: S) -> Self::Future {
future::ok(NormalizePathNormalization {
service,
merge_slash: Regex::new("//+").unwrap()
})
}
}
pub struct NormalizePathNormalization<S> {
service: S,
merge_slash: Regex,
}
impl<S> Service for NormalizePathNormalization<S>
where
S: Service<Request = ServiceRequest, Response = ServiceResponse>,
{
type Request = ServiceRequest;
type Response = ServiceResponse;
type Error = S::Error;
type Future = S::Future;
fn poll_ready(&mut self) -> futures::Poll<(), Self::Error> {
self.service.poll_ready()
}
fn call(&mut self, mut req: ServiceRequest) -> Self::Future {
let head = req.head_mut();
let path = head.uri.path();
let original_len = path.len();
let path = self.merge_slash.replace_all(path, "/");
if original_len != path.len() {
head.uri = path.parse().unwrap();
}
self.service.call(req)
}
}
#[cfg(test)]
mod tests {
use actix_service::FnService;
use super::*;
use crate::dev::ServiceRequest;
use crate::http::header::CONTENT_TYPE;
use crate::test::{block_on, TestRequest};
use crate::HttpResponse;
#[test]
fn test_in_place_normalization() {
let srv = FnService::new(|req: ServiceRequest| {
assert_eq!("/v1/something/", req.path());
req.into_response(HttpResponse::Ok().finish())
});
let mut normalize = block_on(NormalizePath.new_transform(srv)).unwrap();
let req = TestRequest::with_uri("/v1//something////").to_srv_request();
let res = block_on(normalize.call(req)).unwrap();
assert!(res.status().is_success());
}
#[test]
fn should_normalize_nothing() {
const URI: &str = "/v1/something/";
let srv = FnService::new(|req: ServiceRequest| {
assert_eq!(URI, req.path());
req.into_response(HttpResponse::Ok().finish())
});
let mut normalize = block_on(NormalizePath.new_transform(srv)).unwrap();
let req = TestRequest::with_uri(URI).to_srv_request();
let res = block_on(normalize.call(req)).unwrap();
assert!(res.status().is_success());
}
}