diff --git a/meilisearch/src/error.rs b/meilisearch/src/error.rs index 9d0a03c34..004f0d143 100644 --- a/meilisearch/src/error.rs +++ b/meilisearch/src/error.rs @@ -1,5 +1,6 @@ use actix_web as aweb; use aweb::error::{JsonPayloadError, QueryPayloadError}; +use byte_unit::Byte; use meilisearch_types::document_formats::{DocumentFormatError, PayloadType}; use meilisearch_types::error::{Code, ErrorCode, ResponseError}; use meilisearch_types::index_uid::{IndexUid, IndexUidFormatError}; @@ -26,8 +27,8 @@ pub enum MeilisearchHttpError { InvalidExpression(&'static [&'static str], Value), #[error("A {0} payload is missing.")] MissingPayload(PayloadType), - #[error("The provided payload reached the size limit.")] - PayloadTooLarge, + #[error("The provided payload reached the size limit. The maximum accepted payload size is {}.", Byte::from_bytes(*.0 as u64).get_appropriate_unit(true))] + PayloadTooLarge(usize), #[error("Two indexes must be given for each swap. The list `[{}]` contains {} indexes.", .0.iter().map(|uid| format!("\"{uid}\"")).collect::>().join(", "), .0.len() )] @@ -62,7 +63,7 @@ impl ErrorCode for MeilisearchHttpError { MeilisearchHttpError::DocumentNotFound(_) => Code::DocumentNotFound, MeilisearchHttpError::EmptyFilter => Code::InvalidDocumentDeleteFilter, MeilisearchHttpError::InvalidExpression(_, _) => Code::InvalidSearchFilter, - MeilisearchHttpError::PayloadTooLarge => Code::PayloadTooLarge, + MeilisearchHttpError::PayloadTooLarge(_) => Code::PayloadTooLarge, MeilisearchHttpError::SwapIndexPayloadWrongLength(_) => Code::InvalidSwapIndexes, MeilisearchHttpError::IndexUid(e) => e.error_code(), MeilisearchHttpError::SerdeJson(_) => Code::Internal, diff --git a/meilisearch/src/extractors/payload.rs b/meilisearch/src/extractors/payload.rs index 0ccebe8f9..5e7e9cf7e 100644 --- a/meilisearch/src/extractors/payload.rs +++ b/meilisearch/src/extractors/payload.rs @@ -11,6 +11,7 @@ use crate::error::MeilisearchHttpError; pub struct Payload { payload: Decompress, limit: usize, + remaining: usize, } pub struct PayloadConfig { @@ -43,6 +44,7 @@ impl FromRequest for Payload { ready(Ok(Payload { payload: Decompress::from_headers(payload.take(), req.headers()), limit, + remaining: limit, })) } } @@ -54,12 +56,14 @@ impl Stream for Payload { fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { match Pin::new(&mut self.payload).poll_next(cx) { Poll::Ready(Some(result)) => match result { - Ok(bytes) => match self.limit.checked_sub(bytes.len()) { + Ok(bytes) => match self.remaining.checked_sub(bytes.len()) { Some(new_limit) => { - self.limit = new_limit; + self.remaining = new_limit; Poll::Ready(Some(Ok(bytes))) } - None => Poll::Ready(Some(Err(MeilisearchHttpError::PayloadTooLarge))), + None => { + Poll::Ready(Some(Err(MeilisearchHttpError::PayloadTooLarge(self.limit)))) + } }, x => Poll::Ready(Some(x.map_err(MeilisearchHttpError::from))), }, diff --git a/meilisearch/tests/documents/add_documents.rs b/meilisearch/tests/documents/add_documents.rs index c2ba2ccaa..11a5e0fc8 100644 --- a/meilisearch/tests/documents/add_documents.rs +++ b/meilisearch/tests/documents/add_documents.rs @@ -1781,7 +1781,7 @@ async fn error_add_documents_payload_size() { snapshot!(json_string!(response, { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" { - "message": "The provided payload reached the size limit.", + "message": "The provided payload reached the size limit. The maximum accepted payload size is 10.00 MiB.", "code": "payload_too_large", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#payload_too_large"