1
0
mirror of https://gitlab.com/comunic/comunicapiv3 synced 2024-11-22 21:39:21 +00:00

Handle multipart requests

This commit is contained in:
Pierre HUBERT 2020-06-20 11:37:29 +02:00
parent bab1fe8272
commit 25a368fd98
4 changed files with 50 additions and 21 deletions

1
Cargo.lock generated
View File

@ -529,6 +529,7 @@ dependencies = [
"actix-multipart", "actix-multipart",
"actix-rt", "actix-rt",
"actix-web", "actix-web",
"bytes",
"chrono", "chrono",
"encoding_rs", "encoding_rs",
"futures", "futures",

View File

@ -21,3 +21,4 @@ mailchecker = "3.3.6"
sha1 = "0.6.0" sha1 = "0.6.0"
rand = "0.7.3" rand = "0.7.3"
chrono = "0.4.11" chrono = "0.4.11"
bytes = "0.5.4"

View File

@ -3,8 +3,9 @@ use std::pin::Pin;
use actix_web::{App, FromRequest, http, HttpMessage, HttpRequest, HttpResponse, HttpServer, web}; use actix_web::{App, FromRequest, http, HttpMessage, HttpRequest, HttpResponse, HttpServer, web};
use actix_web::dev::{Decompress, Payload, PayloadStream}; use actix_web::dev::{Decompress, Payload, PayloadStream};
use actix_web::error::{ErrorBadRequest, PayloadError}; use actix_web::error::{ErrorBadRequest, ErrorInternalServerError, PayloadError};
use actix_web::web::{Bytes, BytesMut}; use actix_web::web::{Bytes, BytesMut};
use bytes::{Buf, BufMut};
use encoding_rs::UTF_8; use encoding_rs::UTF_8;
use futures::{FutureExt, Stream, StreamExt}; use futures::{FutureExt, Stream, StreamExt};
use futures::future::LocalBoxFuture; use futures::future::LocalBoxFuture;
@ -133,18 +134,51 @@ impl FromRequest for CustomRequest {
// Add the value to the body // Add the value to the body
body_args.insert( body_args.insert(
percent_decode_str(args[0]).decode_utf8_lossy().to_string(), percent_decode_str(args[0]).decode_utf8_lossy().to_string(),
RequestValue::string(percent_decode_str(args[1]).decode_utf8_lossy().to_string()), RequestValue::String(percent_decode_str(args[1]).decode_utf8_lossy().to_string()),
); );
} }
} }
} }
// Process "multipart/form-data" request // Process "multipart/form-data" request
else if req.content_type().starts_with("multipart/form-data") { else if req.content_type().starts_with("multipart/form-data") {
let mut req = actix_multipart::Multipart::new(req.headers(), payload); let mut req = actix_multipart::Multipart::new(req.headers(), payload);
// Process the list of arguments
while let Some(el) = req.next().await { while let Some(el) = req.next().await {
let mut field = el?; let mut field = el?;
let content_type = field.content_disposition().ok_or(
ErrorInternalServerError("F1"))?;
let name = content_type.get_name().ok_or(
ErrorInternalServerError("Missing field name!"))?;
// Handle file upload
if content_type.get_filename().is_some() && name.eq("file") {
let filename = content_type.get_filename().unwrap();
let mut buf = BytesMut::new();
while let Some(chunk) = field.next().await {
let data = chunk.unwrap();
buf.put(data);
}
body_args.insert(name.to_string(),
RequestValue::File(filename.to_string(), buf.to_bytes()));
}
// It is a simple field
else {
let mut content = String::new();
// Get content
while let Some(chunk) = field.next().await {
content = format!("{}{}", content, String::from_utf8_lossy(chunk?.bytes()));
}
body_args.insert(name.to_string(), RequestValue::String(content));
}
} }
} }

View File

@ -14,23 +14,16 @@ use crate::data::error::{ExecError, ResultBoxError};
use crate::data::user::UserID; use crate::data::user::UserID;
use crate::helpers::{account_helper, api_helper, user_helper, conversations_helper}; use crate::helpers::{account_helper, api_helper, user_helper, conversations_helper};
use crate::utils::virtual_directories_utils::check_virtual_directory; use crate::utils::virtual_directories_utils::check_virtual_directory;
use bytes::Bytes;
/// Http request handler /// Http request handler
/// ///
/// @author Pierre Hubert /// @author Pierre Hubert
/// Single request body value /// Single request body value
pub struct RequestValue { pub enum RequestValue {
pub string: Option<String> String(String),
} File(String, Bytes),
impl RequestValue {
/// Build a string value
pub fn string(s: String) -> RequestValue {
RequestValue {
string: Some(s)
}
}
} }
#[derive(Serialize)] #[derive(Serialize)]
@ -187,19 +180,19 @@ impl HttpRequestHandler {
-> ResultBoxError<String> { -> ResultBoxError<String> {
let param = self.post_parameter(name)?; let param = self.post_parameter(name)?;
match (&param.string, required) { match (&param, required) {
(None, true) => (RequestValue::String(s), _) => {
Err(self.bad_request(format!("'{}' is not a string!", name)).unwrap_err()),
(None, false) => Ok(String::new()),
(Some(s), _) => {
if s.len() >= min_length { if s.len() >= min_length {
Ok(s.to_string()) Ok(s.to_string())
} else { } else {
Err(self.bad_request(format!("'{}' is too short!", name)).unwrap_err()) Err(self.bad_request(format!("'{}' is too short!", name)).unwrap_err())
} }
} }
(_, false) => Ok(String::new()),
(_, true) =>
Err(self.bad_request(format!("'{}' is not a string!", name)).unwrap_err()),
} }
} }