mirror of
https://github.com/meilisearch/meilisearch.git
synced 2024-11-30 09:04:59 +08:00
Merge pull request #695 from meilisearch/fix-dashboard
update normalize_path middleware
This commit is contained in:
commit
59ed3e88b3
@ -13,6 +13,7 @@
|
|||||||
- Fix url trailing slash and double slash issues (#659)
|
- Fix url trailing slash and double slash issues (#659)
|
||||||
- Fix accept all Content-Type by default (#653)
|
- Fix accept all Content-Type by default (#653)
|
||||||
- Return the error message from Serde when a deserialization error is encountered (#661)
|
- Return the error message from Serde when a deserialization error is encountered (#661)
|
||||||
|
- Fix NormalizePath middleware to make the dashboard accessible (#695)
|
||||||
|
|
||||||
## v0.10.1
|
## v0.10.1
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
pub mod authentication;
|
pub mod authentication;
|
||||||
pub mod meilisearch;
|
pub mod meilisearch;
|
||||||
pub mod normalize_slashes;
|
pub mod normalize_path;
|
||||||
|
|
||||||
pub use authentication::Authentication;
|
pub use authentication::Authentication;
|
||||||
pub use normalize_slashes::NormalizeSlashes;
|
pub use normalize_path::NormalizePath;
|
||||||
|
86
meilisearch-http/src/helpers/normalize_path.rs
Normal file
86
meilisearch-http/src/helpers/normalize_path.rs
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
/// From https://docs.rs/actix-web/3.0.0-alpha.2/src/actix_web/middleware/normalize.rs.html#34
|
||||||
|
use actix_http::Error;
|
||||||
|
use actix_service::{Service, Transform};
|
||||||
|
use actix_web::{
|
||||||
|
dev::ServiceRequest,
|
||||||
|
dev::ServiceResponse,
|
||||||
|
http::uri::{PathAndQuery, Uri},
|
||||||
|
};
|
||||||
|
use futures::future::{ok, Ready};
|
||||||
|
use regex::Regex;
|
||||||
|
use std::task::{Context, Poll};
|
||||||
|
pub struct NormalizePath;
|
||||||
|
|
||||||
|
impl<S, B> Transform<S> for NormalizePath
|
||||||
|
where
|
||||||
|
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||||
|
S::Future: 'static,
|
||||||
|
{
|
||||||
|
type Request = ServiceRequest;
|
||||||
|
type Response = ServiceResponse<B>;
|
||||||
|
type Error = Error;
|
||||||
|
type InitError = ();
|
||||||
|
type Transform = NormalizePathNormalization<S>;
|
||||||
|
type Future = Ready<Result<Self::Transform, Self::InitError>>;
|
||||||
|
|
||||||
|
fn new_transform(&self, service: S) -> Self::Future {
|
||||||
|
ok(NormalizePathNormalization {
|
||||||
|
service,
|
||||||
|
merge_slash: Regex::new("//+").unwrap(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct NormalizePathNormalization<S> {
|
||||||
|
service: S,
|
||||||
|
merge_slash: Regex,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S, B> Service for NormalizePathNormalization<S>
|
||||||
|
where
|
||||||
|
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||||
|
S::Future: 'static,
|
||||||
|
{
|
||||||
|
type Request = ServiceRequest;
|
||||||
|
type Response = ServiceResponse<B>;
|
||||||
|
type Error = Error;
|
||||||
|
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_mut();
|
||||||
|
|
||||||
|
// always add trailing slash, might be an extra one
|
||||||
|
let path = head.uri.path().to_string() + "/";
|
||||||
|
|
||||||
|
if self.merge_slash.find(&path).is_some() {
|
||||||
|
// normalize multiple /'s to one /
|
||||||
|
let path = self.merge_slash.replace_all(&path, "/");
|
||||||
|
|
||||||
|
let path = if path.len() > 1 {
|
||||||
|
path.trim_end_matches('/')
|
||||||
|
} else {
|
||||||
|
&path
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut parts = head.uri.clone().into_parts();
|
||||||
|
let pq = parts.path_and_query.as_ref().unwrap();
|
||||||
|
|
||||||
|
let path = if let Some(q) = pq.query() {
|
||||||
|
bytes::Bytes::from(format!("{}?{}", path, q))
|
||||||
|
} else {
|
||||||
|
bytes::Bytes::copy_from_slice(path.as_bytes())
|
||||||
|
};
|
||||||
|
parts.path_and_query = Some(PathAndQuery::from_maybe_shared(path).unwrap());
|
||||||
|
|
||||||
|
let uri = Uri::from_parts(parts).unwrap();
|
||||||
|
req.match_info_mut().get_mut().update(&uri);
|
||||||
|
req.head_mut().uri = uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.service.call(req)
|
||||||
|
}
|
||||||
|
}
|
@ -1,88 +0,0 @@
|
|||||||
///
|
|
||||||
/// This middleware normalizes slashes in paths
|
|
||||||
/// * consecutive instances of `/` get collapsed into one `/`
|
|
||||||
/// * any ending `/` is removed.
|
|
||||||
/// Original source from: https://gitlab.com/snippets/1884466
|
|
||||||
///
|
|
||||||
/// 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(new_path.to_string()),
|
|
||||||
};
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
@ -4,7 +4,7 @@ use actix_cors::Cors;
|
|||||||
use actix_web::{middleware, HttpServer};
|
use actix_web::{middleware, HttpServer};
|
||||||
use main_error::MainError;
|
use main_error::MainError;
|
||||||
use meilisearch_http::data::Data;
|
use meilisearch_http::data::Data;
|
||||||
use meilisearch_http::helpers::NormalizeSlashes;
|
use meilisearch_http::helpers::NormalizePath;
|
||||||
use meilisearch_http::option::Opt;
|
use meilisearch_http::option::Opt;
|
||||||
use meilisearch_http::{create_app, index_update_callback};
|
use meilisearch_http::{create_app, index_update_callback};
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
@ -72,7 +72,7 @@ async fn main() -> Result<(), MainError> {
|
|||||||
)
|
)
|
||||||
.wrap(middleware::Logger::default())
|
.wrap(middleware::Logger::default())
|
||||||
.wrap(middleware::Compress::default())
|
.wrap(middleware::Compress::default())
|
||||||
.wrap(NormalizeSlashes)
|
.wrap(NormalizePath)
|
||||||
})
|
})
|
||||||
.bind(opt.http_addr)?
|
.bind(opt.http_addr)?
|
||||||
.run()
|
.run()
|
||||||
|
@ -7,7 +7,7 @@ use actix_web::{http::StatusCode, test};
|
|||||||
use meilisearch_core::DatabaseOptions;
|
use meilisearch_core::DatabaseOptions;
|
||||||
use meilisearch_http::data::Data;
|
use meilisearch_http::data::Data;
|
||||||
use meilisearch_http::option::Opt;
|
use meilisearch_http::option::Opt;
|
||||||
use meilisearch_http::helpers::NormalizeSlashes;
|
use meilisearch_http::helpers::NormalizePath;
|
||||||
use tempdir::TempDir;
|
use tempdir::TempDir;
|
||||||
use tokio::time::delay_for;
|
use tokio::time::delay_for;
|
||||||
|
|
||||||
@ -128,7 +128,7 @@ impl Server {
|
|||||||
pub async fn get_request(&mut self, url: &str) -> (Value, StatusCode) {
|
pub async fn get_request(&mut self, url: &str) -> (Value, StatusCode) {
|
||||||
eprintln!("get_request: {}", url);
|
eprintln!("get_request: {}", url);
|
||||||
|
|
||||||
let mut app = test::init_service(meilisearch_http::create_app(&self.data).wrap(NormalizeSlashes)).await;
|
let mut app = test::init_service(meilisearch_http::create_app(&self.data).wrap(NormalizePath)).await;
|
||||||
|
|
||||||
let req = test::TestRequest::get().uri(url).to_request();
|
let req = test::TestRequest::get().uri(url).to_request();
|
||||||
let res = test::call_service(&mut app, req).await;
|
let res = test::call_service(&mut app, req).await;
|
||||||
@ -142,7 +142,7 @@ impl Server {
|
|||||||
pub async fn post_request(&mut self, url: &str, body: Value) -> (Value, StatusCode) {
|
pub async fn post_request(&mut self, url: &str, body: Value) -> (Value, StatusCode) {
|
||||||
eprintln!("post_request: {}", url);
|
eprintln!("post_request: {}", url);
|
||||||
|
|
||||||
let mut app = test::init_service(meilisearch_http::create_app(&self.data).wrap(NormalizeSlashes)).await;
|
let mut app = test::init_service(meilisearch_http::create_app(&self.data).wrap(NormalizePath)).await;
|
||||||
|
|
||||||
let req = test::TestRequest::post()
|
let req = test::TestRequest::post()
|
||||||
.uri(url)
|
.uri(url)
|
||||||
@ -171,7 +171,7 @@ impl Server {
|
|||||||
pub async fn put_request(&mut self, url: &str, body: Value) -> (Value, StatusCode) {
|
pub async fn put_request(&mut self, url: &str, body: Value) -> (Value, StatusCode) {
|
||||||
eprintln!("put_request: {}", url);
|
eprintln!("put_request: {}", url);
|
||||||
|
|
||||||
let mut app = test::init_service(meilisearch_http::create_app(&self.data).wrap(NormalizeSlashes)).await;
|
let mut app = test::init_service(meilisearch_http::create_app(&self.data).wrap(NormalizePath)).await;
|
||||||
|
|
||||||
let req = test::TestRequest::put()
|
let req = test::TestRequest::put()
|
||||||
.uri(url)
|
.uri(url)
|
||||||
@ -199,7 +199,7 @@ impl Server {
|
|||||||
pub async fn delete_request(&mut self, url: &str) -> (Value, StatusCode) {
|
pub async fn delete_request(&mut self, url: &str) -> (Value, StatusCode) {
|
||||||
eprintln!("delete_request: {}", url);
|
eprintln!("delete_request: {}", url);
|
||||||
|
|
||||||
let mut app = test::init_service(meilisearch_http::create_app(&self.data).wrap(NormalizeSlashes)).await;
|
let mut app = test::init_service(meilisearch_http::create_app(&self.data).wrap(NormalizePath)).await;
|
||||||
|
|
||||||
let req = test::TestRequest::delete().uri(url).to_request();
|
let req = test::TestRequest::delete().uri(url).to_request();
|
||||||
let res = test::call_service(&mut app, req).await;
|
let res = test::call_service(&mut app, req).await;
|
||||||
|
12
meilisearch-http/tests/dashboard.rs
Normal file
12
meilisearch-http/tests/dashboard.rs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
mod common;
|
||||||
|
|
||||||
|
#[actix_rt::test]
|
||||||
|
async fn dashboard() {
|
||||||
|
let mut server = common::Server::with_uid("movies");
|
||||||
|
|
||||||
|
let (_response, status_code) = server.get_request("/").await;
|
||||||
|
assert_eq!(status_code, 200);
|
||||||
|
|
||||||
|
let (_response, status_code) = server.get_request("/bulma.min.css").await;
|
||||||
|
assert_eq!(status_code, 200);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user