add normalize_slashes middleware

This commit is contained in:
qdequele 2020-05-07 12:28:41 +02:00
parent 36abcb3976
commit 7a8e64be30
No known key found for this signature in database
GPG key ID: B3F0A000EBF11745
9 changed files with 99 additions and 5 deletions

View file

@ -134,7 +134,7 @@ impl Data {
let db_opt = DatabaseOptions {
main_map_size: opt.main_map_size,
update_map_size: opt.update_map_size
update_map_size: opt.update_map_size,
};
let db = Arc::new(Database::open_or_create(opt.db_path, db_opt).unwrap());

View file

@ -17,7 +17,6 @@ pub enum Authentication {
Admin,
}
impl<S: 'static, B> Transform<S> for Authentication
where
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,

View file

@ -1,4 +1,6 @@
pub mod authentication;
pub mod meilisearch;
pub mod normalize_slashes;
pub use authentication::Authentication;
pub use normalize_slashes::NormalizeSlashes;

View file

@ -0,0 +1,87 @@
///
/// This middleware normalizes slashes in paths
/// * consecutive instances of `/` get collapsed into one `/`
/// * any ending `/` is removed.
///
/// Ex:
/// /this///url/
/// becomes : /this/url
///
use actix_service::{Service, Transform};
use actix_web::{
dev::ServiceRequest,
dev::ServiceResponse,
http::uri::{PathAndQuery, Uri},
Error as ActixError,
};
use futures::future::{ok, Ready};
use regex::Regex;
use std::task::{Context, Poll};
pub struct NormalizeSlashes;
impl<S, B> Transform<S> for NormalizeSlashes
where
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = ActixError>,
S::Future: 'static,
{
type Request = ServiceRequest;
type Response = ServiceResponse<B>;
type Error = ActixError;
type InitError = ();
type Transform = SlashNormalization<S>;
type Future = Ready<Result<Self::Transform, Self::InitError>>;
fn new_transform(&self, service: S) -> Self::Future {
ok(SlashNormalization { service })
}
}
pub struct SlashNormalization<S> {
service: S,
}
impl<S, B> Service for SlashNormalization<S>
where
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = ActixError>,
S::Future: 'static,
{
type Request = ServiceRequest;
type Response = ServiceResponse<B>;
type Error = ActixError;
type Future = S::Future;
fn poll_ready(&mut self, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
self.service.poll_ready(cx)
}
fn call(&mut self, mut req: ServiceRequest) -> Self::Future {
let head = req.head();
let path = head.uri.path();
let original_len = path.len();
let slash_regex = Regex::new("//+").unwrap();
let new_path = slash_regex.replace_all(path, "/");
let new_path = new_path.trim_end_matches("/");
if original_len != new_path.len() {
let mut parts = head.uri.clone().into_parts();
let path = match parts.path_and_query.as_ref().map(|pq| pq.query()).flatten() {
Some(q) => bytes::Bytes::from(format!("{}?{}", new_path, q)),
None =>bytes::Bytes::from(format!("{}", new_path))
};
if let Ok(pq) = PathAndQuery::from_maybe_shared(path) {
parts.path_and_query = Some(pq);
if let Ok(uri) = Uri::from_parts(parts) {
req.match_info_mut().get_mut().update(&uri);
req.head_mut().uri = uri;
}
}
}
self.service.call(req)
}
}

View file

@ -5,6 +5,7 @@ use actix_web::{middleware, HttpServer};
use log::info;
use main_error::MainError;
use meilisearch_http::data::Data;
use meilisearch_http::helpers::NormalizeSlashes;
use meilisearch_http::option::Opt;
use meilisearch_http::{create_app, index_update_callback};
use structopt::StructOpt;
@ -72,6 +73,7 @@ async fn main() -> Result<(), MainError> {
)
.wrap(middleware::Logger::default())
.wrap(middleware::Compress::default())
.wrap(NormalizeSlashes)
})
.bind(opt.http_addr)?
.run()

View file

@ -33,5 +33,5 @@ pub struct Opt {
/// The maximum size, in bytes, of the update lmdb database directory
#[structopt(long, env = "MEILI_UPDATE_MAP_SIZE", default_value = "107374182400")] // 100GB
pub update_map_size: usize
pub update_map_size: usize,
}