mirror of
				https://github.com/meilisearch/meilisearch.git
				synced 2025-10-31 07:56:28 +00:00 
			
		
		
		
	invalid content type error
This commit is contained in:
		| @@ -84,6 +84,7 @@ pub enum Code { | ||||
|     DumpAlreadyInProgress, | ||||
|     DumpProcessFailed, | ||||
|  | ||||
|     InvalidContentType, | ||||
|     MissingContentType, | ||||
|     MalformedPayload, | ||||
| } | ||||
| @@ -158,7 +159,8 @@ impl Code { | ||||
|                 ErrCode::internal("dump_process_failed", StatusCode::INTERNAL_SERVER_ERROR) | ||||
|             } | ||||
|             MissingContentType => ErrCode::invalid("missing_content_type", StatusCode::UNSUPPORTED_MEDIA_TYPE), | ||||
|             MalformedPayload => ErrCode::invalid("malformed_payload", StatusCode::BAD_REQUEST) | ||||
|             MalformedPayload => ErrCode::invalid("malformed_payload", StatusCode::BAD_REQUEST), | ||||
|             InvalidContentType => ErrCode::invalid("invalid_content_type", StatusCode::UNSUPPORTED_MEDIA_TYPE), | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -13,12 +13,15 @@ use serde::{Deserialize, Serialize}; | ||||
| pub enum MeilisearchHttpError { | ||||
|     #[error("A Content-Type header is missing. Accepted values for the Content-Type header are: \"application/json\", \"application/x-ndjson\", \"test/csv\"")] | ||||
|     MissingContentType, | ||||
|     #[error("The Content-Type \"{0}\" is invalid. Accepted values for the Content-Type header are: \"application/json\", \"application/x-ndjson\", \"test/csv\"")] | ||||
|     InvalidContentType(String), | ||||
| } | ||||
|  | ||||
| impl ErrorCode for MeilisearchHttpError { | ||||
|     fn error_code(&self) -> Code { | ||||
|         match self { | ||||
|             MeilisearchHttpError::MissingContentType => Code::MissingContentType, | ||||
|             MeilisearchHttpError::InvalidContentType(_) => Code::InvalidContentType, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| use actix_web::error::PayloadError; | ||||
| use actix_web::web::Bytes; | ||||
| use actix_web::{web, HttpResponse}; | ||||
| use actix_web::{web, HttpRequest, HttpResponse}; | ||||
| use futures::{Stream, StreamExt}; | ||||
| use log::debug; | ||||
| use meilisearch_lib::index_controller::{DocumentAdditionFormat, Update}; | ||||
| @@ -18,29 +18,6 @@ use crate::routes::IndexParam; | ||||
| const DEFAULT_RETRIEVE_DOCUMENTS_OFFSET: usize = 0; | ||||
| const DEFAULT_RETRIEVE_DOCUMENTS_LIMIT: usize = 20; | ||||
|  | ||||
| macro_rules! guard_content_type { | ||||
|     ($fn_name:ident, $guard_value:literal) => { | ||||
|         fn $fn_name(head: &actix_web::dev::RequestHead) -> bool { | ||||
|             if let Some(content_type) = head.headers.get("Content-Type") { | ||||
|                 content_type | ||||
|                     .to_str() | ||||
|                     .map(|v| v.contains($guard_value)) | ||||
|                     .unwrap_or(false) | ||||
|             } else { | ||||
|                 false | ||||
|             } | ||||
|         } | ||||
|     }; | ||||
| } | ||||
|  | ||||
| guard_content_type!(guard_ndjson, "application/x-ndjson"); | ||||
| guard_content_type!(guard_csv, "text/csv"); | ||||
| guard_content_type!(guard_json, "application/json"); | ||||
|  | ||||
| fn empty_application_type(head: &actix_web::dev::RequestHead) -> bool { | ||||
|     head.headers.get("Content-Type").is_none() | ||||
| } | ||||
|  | ||||
| /// This is required because Payload is not Sync nor Send | ||||
| fn payload_to_stream(mut payload: Payload) -> impl Stream<Item = Result<Bytes, PayloadError>> { | ||||
|     let (snd, recv) = mpsc::channel(1); | ||||
| @@ -62,26 +39,8 @@ pub fn configure(cfg: &mut web::ServiceConfig) { | ||||
|     cfg.service( | ||||
|         web::resource("") | ||||
|             .route(web::get().to(get_all_documents)) | ||||
|             // replace documents routes | ||||
|             .route( | ||||
|                 web::post() | ||||
|                     .guard(empty_application_type) | ||||
|                     .to(missing_content_type_error), | ||||
|             ) | ||||
|             .route(web::post().guard(guard_json).to(add_documents_json)) | ||||
|             .route(web::post().guard(guard_ndjson).to(add_documents_ndjson)) | ||||
|             .route(web::post().guard(guard_csv).to(add_documents_csv)) | ||||
|             .route(web::post().to(HttpResponse::UnsupportedMediaType)) | ||||
|             // update documents routes | ||||
|             .route( | ||||
|                 web::put() | ||||
|                     .guard(empty_application_type) | ||||
|                     .to(missing_content_type_error), | ||||
|             ) | ||||
|             .route(web::put().guard(guard_json).to(update_documents_json)) | ||||
|             .route(web::put().guard(guard_ndjson).to(update_documents_ndjson)) | ||||
|             .route(web::put().guard(guard_csv).to(update_documents_csv)) | ||||
|             .route(web::put().to(HttpResponse::UnsupportedMediaType)) | ||||
|             .route(web::post().to(add_documents)) | ||||
|             .route(web::put().to(update_documents)) | ||||
|             .route(web::delete().to(clear_all_documents)), | ||||
|     ) | ||||
|     // this route needs to be before the /documents/{document_id} to match properly | ||||
| @@ -93,10 +52,6 @@ pub fn configure(cfg: &mut web::ServiceConfig) { | ||||
|     ); | ||||
| } | ||||
|  | ||||
| async fn missing_content_type_error() -> Result<HttpResponse, ResponseError> { | ||||
|     Err(MeilisearchHttpError::MissingContentType.into()) | ||||
| } | ||||
|  | ||||
| pub async fn get_document( | ||||
|     meilisearch: GuardedData<Public, MeiliSearch>, | ||||
|     path: web::Path<DocumentParam>, | ||||
| @@ -169,126 +124,69 @@ pub struct UpdateDocumentsQuery { | ||||
|     primary_key: Option<String>, | ||||
| } | ||||
|  | ||||
| pub async fn add_documents_json( | ||||
| pub async fn add_documents( | ||||
|     meilisearch: GuardedData<Private, MeiliSearch>, | ||||
|     path: web::Path<IndexParam>, | ||||
|     params: web::Query<UpdateDocumentsQuery>, | ||||
|     body: Payload, | ||||
|     req: HttpRequest, | ||||
| ) -> Result<HttpResponse, ResponseError> { | ||||
|     debug!("called with params: {:?}", params); | ||||
|     document_addition( | ||||
|         req.headers().get("Content-type").map(|s| s.to_str().unwrap_or("unkown")), | ||||
|         meilisearch, | ||||
|         path, | ||||
|         params, | ||||
|         path.into_inner().index_uid, | ||||
|         params.into_inner().primary_key, | ||||
|         body, | ||||
|         DocumentAdditionFormat::Json, | ||||
|         IndexDocumentsMethod::ReplaceDocuments, | ||||
|     ) | ||||
|     .await | ||||
|         IndexDocumentsMethod::ReplaceDocuments) | ||||
|         .await | ||||
| } | ||||
|  | ||||
| pub async fn add_documents_ndjson( | ||||
| pub async fn update_documents( | ||||
|     meilisearch: GuardedData<Private, MeiliSearch>, | ||||
|     path: web::Path<IndexParam>, | ||||
|     params: web::Query<UpdateDocumentsQuery>, | ||||
|     body: Payload, | ||||
|     req: HttpRequest, | ||||
| ) -> Result<HttpResponse, ResponseError> { | ||||
|     debug!("called with params: {:?}", params); | ||||
|     document_addition( | ||||
|         req.headers().get("Content-type").map(|s| s.to_str().unwrap_or("unkown")), | ||||
|         meilisearch, | ||||
|         path, | ||||
|         params, | ||||
|         path.into_inner().index_uid, | ||||
|         params.into_inner().primary_key, | ||||
|         body, | ||||
|         DocumentAdditionFormat::Ndjson, | ||||
|         IndexDocumentsMethod::ReplaceDocuments, | ||||
|     ) | ||||
|     .await | ||||
|         IndexDocumentsMethod::UpdateDocuments) | ||||
|         .await | ||||
| } | ||||
|  | ||||
| pub async fn add_documents_csv( | ||||
|     meilisearch: GuardedData<Private, MeiliSearch>, | ||||
|     path: web::Path<IndexParam>, | ||||
|     params: web::Query<UpdateDocumentsQuery>, | ||||
|     body: Payload, | ||||
| ) -> Result<HttpResponse, ResponseError> { | ||||
|     document_addition( | ||||
|         meilisearch, | ||||
|         path, | ||||
|         params, | ||||
|         body, | ||||
|         DocumentAdditionFormat::Csv, | ||||
|         IndexDocumentsMethod::ReplaceDocuments, | ||||
|     ) | ||||
|     .await | ||||
| } | ||||
|  | ||||
| pub async fn update_documents_json( | ||||
|     meilisearch: GuardedData<Private, MeiliSearch>, | ||||
|     path: web::Path<IndexParam>, | ||||
|     params: web::Query<UpdateDocumentsQuery>, | ||||
|     body: Payload, | ||||
| ) -> Result<HttpResponse, ResponseError> { | ||||
|     document_addition( | ||||
|         meilisearch, | ||||
|         path, | ||||
|         params, | ||||
|         body, | ||||
|         DocumentAdditionFormat::Json, | ||||
|         IndexDocumentsMethod::UpdateDocuments, | ||||
|     ) | ||||
|     .await | ||||
| } | ||||
|  | ||||
| pub async fn update_documents_ndjson( | ||||
|     meilisearch: GuardedData<Private, MeiliSearch>, | ||||
|     path: web::Path<IndexParam>, | ||||
|     params: web::Query<UpdateDocumentsQuery>, | ||||
|     body: Payload, | ||||
| ) -> Result<HttpResponse, ResponseError> { | ||||
|     document_addition( | ||||
|         meilisearch, | ||||
|         path, | ||||
|         params, | ||||
|         body, | ||||
|         DocumentAdditionFormat::Ndjson, | ||||
|         IndexDocumentsMethod::UpdateDocuments, | ||||
|     ) | ||||
|     .await | ||||
| } | ||||
|  | ||||
| pub async fn update_documents_csv( | ||||
|     meilisearch: GuardedData<Private, MeiliSearch>, | ||||
|     path: web::Path<IndexParam>, | ||||
|     params: web::Query<UpdateDocumentsQuery>, | ||||
|     body: Payload, | ||||
| ) -> Result<HttpResponse, ResponseError> { | ||||
|     document_addition( | ||||
|         meilisearch, | ||||
|         path, | ||||
|         params, | ||||
|         body, | ||||
|         DocumentAdditionFormat::Csv, | ||||
|         IndexDocumentsMethod::UpdateDocuments, | ||||
|     ) | ||||
|     .await | ||||
| } | ||||
| /// Route used when the payload type is "application/json" | ||||
| /// Used to add or replace documents | ||||
| async fn document_addition( | ||||
|     content_type: Option<&str>, | ||||
|     meilisearch: GuardedData<Private, MeiliSearch>, | ||||
|     path: web::Path<IndexParam>, | ||||
|     params: web::Query<UpdateDocumentsQuery>, | ||||
|     index_uid: String, | ||||
|     primary_key: Option<String>, | ||||
|     body: Payload, | ||||
|     format: DocumentAdditionFormat, | ||||
|     method: IndexDocumentsMethod, | ||||
| ) -> Result<HttpResponse, ResponseError> { | ||||
|     debug!("called with params: {:?}", params); | ||||
|     let format = match content_type { | ||||
|         Some("application/json") => DocumentAdditionFormat::Json, | ||||
|         Some("application/x-ndjson") => DocumentAdditionFormat::Ndjson, | ||||
|         Some("text/csv") => DocumentAdditionFormat::Csv, | ||||
|         Some(other) => return Err(MeilisearchHttpError::InvalidContentType(other.to_string()).into()), | ||||
|         None => return Err(MeilisearchHttpError::MissingContentType.into()), | ||||
|     }; | ||||
|  | ||||
|     let update = Update::DocumentAddition { | ||||
|         payload: Box::new(payload_to_stream(body)), | ||||
|         primary_key: params.primary_key.clone(), | ||||
|         primary_key, | ||||
|         method, | ||||
|         format, | ||||
|     }; | ||||
|  | ||||
|     let update_status = meilisearch | ||||
|         .register_update(path.into_inner().index_uid, update, true) | ||||
|         .register_update(index_uid, update, true) | ||||
|         .await?; | ||||
|  | ||||
|     debug!("returns: {:?}", update_status); | ||||
|   | ||||
| @@ -361,10 +361,8 @@ mod test { | ||||
|  | ||||
|             indexes::documents::clear_all_documents, | ||||
|             indexes::documents::delete_documents, | ||||
|             indexes::documents::update_documents_json, | ||||
|             indexes::documents::update_documents_csv, | ||||
|             indexes::documents::add_documents_json, | ||||
|             indexes::documents::add_documents_csv, | ||||
|             indexes::documents::update_documents, | ||||
|             indexes::documents::add_documents, | ||||
|             indexes::documents::delete_document, | ||||
|  | ||||
|             indexes::updates::get_all_updates_status, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user