mirror of
https://gitlab.com/comunic/comunicapiv3
synced 2025-06-21 00:45:18 +00:00
Start to read POST request arguments
This commit is contained in:
@ -1,17 +1,119 @@
|
||||
use actix_web::{App, HttpResponse, HttpServer, web, http};
|
||||
use actix_web::{App, HttpResponse, HttpServer, web, http, FromRequest, HttpRequest, HttpMessage};
|
||||
|
||||
use crate::controllers::routes::{get_routes, Route};
|
||||
use crate::controllers::routes::{get_routes, Route, RequestResult};
|
||||
use crate::data::config::Config;
|
||||
use crate::data::http_error::HttpError;
|
||||
use crate::controllers::routes::Method::{GET, POST};
|
||||
use crate::data::http_request_handler::HttpRequestHandler;
|
||||
use crate::data::http_request_handler::{HttpRequestHandler, RequestValue};
|
||||
use actix_web::dev::{PayloadStream, Payload, Decompress};
|
||||
use actix_web::web::{BytesMut};
|
||||
use futures::future::{ok, LocalBoxFuture, err};
|
||||
use futures::{FutureExt, StreamExt, TryFutureExt};
|
||||
use actix_web::error::{PayloadError, ErrorBadRequest};
|
||||
use std::error::Error;
|
||||
use encoding_rs::UTF_8;
|
||||
use std::collections::HashMap;
|
||||
|
||||
|
||||
/// Main server functions
|
||||
///
|
||||
/// @author Pierre Hubert
|
||||
|
||||
/// Custom request value
|
||||
struct CustomRequest {
|
||||
req: web::HttpRequest,
|
||||
body: HashMap<String, RequestValue>,
|
||||
}
|
||||
|
||||
/// Process in our way incoming requests
|
||||
impl FromRequest for CustomRequest {
|
||||
type Error = actix_web::Error;
|
||||
type Future = LocalBoxFuture<'static, Result<CustomRequest, actix_web::Error>>;
|
||||
type Config = ();
|
||||
|
||||
fn from_request(req: &HttpRequest, payload: &mut Payload<PayloadStream>) -> Self::Future {
|
||||
let req = req.clone();
|
||||
let payload = payload.take();
|
||||
|
||||
async move {
|
||||
let mut body_args = HashMap::new();
|
||||
|
||||
// Process "application/x-www-form-urlencoded" requests
|
||||
if req.content_type().eq("application/x-www-form-urlencoded") {
|
||||
|
||||
// Maximum size of the request
|
||||
let limit = 16384;
|
||||
|
||||
// Ready body
|
||||
let mut body = BytesMut::with_capacity(8192);
|
||||
let mut stream = Decompress::from_headers(payload, req.headers());
|
||||
while let Some(item) = stream.next().await {
|
||||
let chunk = item?;
|
||||
|
||||
|
||||
if body.len() + chunk.len() > limit {
|
||||
return Err(actix_web::error::ErrorBadRequest("Overflow - too long"));
|
||||
} else {
|
||||
body.extend_from_slice(&chunk);
|
||||
}
|
||||
}
|
||||
let body = body.freeze();
|
||||
|
||||
|
||||
// Decode body as a string
|
||||
let encoding = req.encoding()?;
|
||||
|
||||
let body_str = if encoding == UTF_8 {
|
||||
String::from_utf8_lossy(body.as_ref()).to_string()
|
||||
} else {
|
||||
encoding
|
||||
.decode_without_bom_handling_and_without_replacement(&body)
|
||||
.map(|s| s.into_owned())
|
||||
.ok_or_else(|| ErrorBadRequest("Can not decode body"))?
|
||||
};
|
||||
|
||||
// Parse body arguments (following the pattern key1=value1&key2=value2)
|
||||
if body_str.len() > 0 {
|
||||
for v in body_str.split("&") {
|
||||
if v.len() == 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
let args: Vec<&str> = v.split("=").collect();
|
||||
|
||||
if args.len() != 2 {
|
||||
return Err(actix_web::error::ErrorBadRequest(format!("{} is invalid!", args[0])));
|
||||
}
|
||||
|
||||
// Add the value to the body
|
||||
body_args.insert(
|
||||
args[0].to_string(),
|
||||
RequestValue::string(args[1].to_string())
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(CustomRequest {
|
||||
req: req.clone(),
|
||||
body: body_args,
|
||||
})
|
||||
}.boxed_local()
|
||||
}
|
||||
}
|
||||
|
||||
/// Process a "simple request" aka not a WebSocket request
|
||||
fn process_simple_route(route: &Route, req: &mut HttpRequestHandler) -> RequestResult {
|
||||
|
||||
// Validate client token
|
||||
req.check_client_token()?;
|
||||
|
||||
(route.func)(req)
|
||||
}
|
||||
|
||||
/// Process an incoming request
|
||||
async fn process_request(req: web::HttpRequest) -> HttpResponse {
|
||||
async fn process_request(custom_req: CustomRequest) -> HttpResponse {
|
||||
let req = &custom_req.req;
|
||||
let routes = get_routes();
|
||||
|
||||
// We search the appropriate route for the request
|
||||
@ -40,9 +142,9 @@ async fn process_request(req: web::HttpRequest) -> HttpResponse {
|
||||
let route = route.unwrap();
|
||||
|
||||
// Execute the request
|
||||
let mut request = HttpRequestHandler::new(req);
|
||||
let mut request = HttpRequestHandler::new(custom_req.req, custom_req.body);
|
||||
|
||||
match (route.func)(&mut request) {
|
||||
match process_simple_route(route, &mut request) {
|
||||
|
||||
// Set default error response if required
|
||||
Err(e) => {
|
||||
@ -57,10 +159,6 @@ async fn process_request(req: web::HttpRequest) -> HttpResponse {
|
||||
request.success("Success").unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
// I use this to be quiet with IntelliJ
|
||||
#[allow(unreachable_patterns)]
|
||||
_ => {println!("Unexpected case (server.rs)!")}
|
||||
}
|
||||
|
||||
request.response()
|
||||
|
Reference in New Issue
Block a user