Skip to content
Snippets Groups Projects
Commit f85cfb4d authored by codecraft's avatar codecraft :crocodile:
Browse files

Complete `get_post_data()` implementation

set maximum post body size to 4196 bytes
parent 66349541
No related branches found
No related tags found
1 merge request!1Initial feature merge
......@@ -10,6 +10,8 @@ use crate::handling::{
};
use crate::setup::MountPoint;
static MAX_HTTPMESSAGE_SIZE: u16 = 4196;
pub async fn handle_connection(mut stream: TcpStream, mountpoints: Vec<MountPoint<'_>>) {
let mut buf_reader = BufReader::new(&mut stream);
let mut http_request: Vec<String> = Vec::with_capacity(30);
......@@ -61,6 +63,7 @@ pub async fn handle_connection(mut stream: TcpStream, mountpoints: Vec<MountPoin
buffer: vec![],
};
if request.can_have_body() {
println!("{:#?}", request.headers);
let length = if let Some(len) = request
.headers
.iter()
......@@ -87,9 +90,9 @@ pub async fn handle_connection(mut stream: TcpStream, mountpoints: Vec<MountPoin
0
};
if length != 0 {
let mut buffer: Vec<u8> = vec![];
buf_reader.read_buf(&mut buffer).await.unwrap();
if buffer.len() != length {
let mut buffer = vec![0u8; MAX_HTTPMESSAGE_SIZE.into()];
let read = buf_reader.read(&mut buffer).await.unwrap();
if read != length {
len_not_defined(stream, Status::LengthRequired).await;
return;
}
......
......@@ -4,6 +4,8 @@ use std::{collections::HashMap, error::Error, fmt::Display};
use crate::utils::mime::mime_enum::Mime;
static TWO_NEWLINES: u8 = 3;
use super::{
methods::Method,
routes::{Data, Uri},
......@@ -125,9 +127,13 @@ impl Request<'_> {
let content_type = val.trim().strip_prefix("Content-Type: ").unwrap();
let type_vec = content_type.split(';').collect::<Vec<&str>>();
boundary = if let Some(bound) = type_vec.iter().find(|part| part.contains("boundary="))
boundary = if let Some(bound) = type_vec.iter().find(|part| part.contains(" boundary="))
{
bound.strip_prefix("boundary=").unwrap().trim_matches('"')
bound
.strip_prefix(" boundary=")
.unwrap()
.trim_end()
.trim_matches('"')
} else {
""
};
......@@ -192,62 +198,10 @@ impl Request<'_> {
Mime::MultipartFormData => {
let mut temp_bound = "--".to_string();
temp_bound.push_str(&format!("{boundary}"));
let end_boundary = format!("{temp_bound}--").as_bytes().to_owned();
let end_boundary = format!("{temp_bound}--\r").as_bytes().to_owned();
temp_bound.push('\r');
let boundary = temp_bound.as_bytes();
let parts = data.split(|byte| byte == &b'\n').collect::<Vec<&[u8]>>();
let mut current_key: Option<String> = None;
let mut boundary_found = true;
for part in parts {
if part == [] {
continue;
}
if part == end_boundary {
break;
}
if !boundary_found && part == boundary {
boundary_found = true;
current_key = None;
continue;
}
if part.starts_with(b"Content-Disposition: form-data; name=") {
let headers = part
.split(|byte| byte == &b';')
.filter(|header| !header.is_empty())
.collect::<Vec<_>>();
if headers.len() < 2 {
continue;
}
let name = headers[1].split(|byte| byte == &b'=').collect::<Vec<_>>();
if name.len() != 2 {
continue;
}
let mkey = String::from_utf8_lossy(name[1])
.as_ref()
.trim_end()
.trim_matches('"')
.to_owned();
if keymap.contains_key::<str>(&mkey) {
current_key = Some(mkey.to_owned());
}
boundary_found = false;
continue;
} else if let Some(key) = &current_key {
if let Some(val) = keymap.get::<str>(&key) {
if let Err(_) = val {
keymap.insert(key.to_string(), Ok(part.to_vec()));
continue;
}
keymap
.get_mut(key)
.unwrap()
.as_mut()
.unwrap()
.extend_from_slice(part);
}
}
}
Request::get_multipart(data, boundary, &end_boundary, &mut keymap);
}
_ => {
return Err(ParseFormError {
......@@ -257,6 +211,77 @@ impl Request<'_> {
};
Ok(keymap)
}
fn get_multipart(
data: &[u8],
boundary: &[u8],
end_boundary: &[u8],
map: &mut HashMap<String, Result<Vec<u8>, ParseFormError>>,
) {
let parts = data.split(|byte| byte == &b'\n').collect::<Vec<&[u8]>>();
let mut current_part: Vec<&[u8]> = vec![];
let mut current_key: Option<String> = None;
let mut ignore_line = 0;
for part in parts {
if part == &[b'\r'] {
if let Some(_) = current_key {
if ignore_line >= TWO_NEWLINES {
current_part.push(&[b'\n']);
continue;
}
ignore_line += 1;
}
continue;
}
if part == end_boundary {
if let Some(key) = &current_key {
let mut part = current_part.join(&b'\n');
if part.ends_with(&[b'\r']) {
part.pop();
}
map.insert(key.to_string(), Ok(part));
}
break;
}
if part == boundary {
if let Some(key) = &current_key {
let mut part = current_part.join(&b'\n');
if part.ends_with(&[b'\r']) {
part.pop();
}
map.insert(key.to_string(), Ok(part));
}
current_part = vec![];
current_key = None;
ignore_line = 0;
continue;
}
if part.starts_with(b"Content-Disposition: form-data; name=") {
let headers = part
.split(|byte| byte == &b';')
.filter(|header| !header.is_empty())
.collect::<Vec<_>>();
if headers.len() < 2 {
continue;
}
let name = headers[1].split(|byte| byte == &b'=').collect::<Vec<_>>();
if name.len() != 2 {
continue;
}
let mkey = String::from_utf8_lossy(name[1])
.as_ref()
.trim_end()
.trim_matches('"')
.to_owned();
if map.contains_key::<str>(&mkey) {
current_key = Some(mkey.to_owned());
}
continue;
} else if let Some(_) = &current_key {
current_part.push(part);
}
}
}
}
#[cfg(test)]
......@@ -287,30 +312,31 @@ mod test {
);
let req = Request {
uri: "",
headers: vec!["Content-Type: multipart/form-data;boundary=\"boundary\"".to_string()],
headers: vec!["Content-Type: multipart/form-data; boundary=\"boundary\"".to_string()],
method: crate::handling::methods::Method::Post,
};
let data = Data {
buffer: b"--boundary
Content-Disposition: form-data; name=\"field1\"
value1
--boundary
Content-Disposition: form-data; name=\"field2\"; filename=\"example.txt\"
value2\n
--boundary--
buffer: b"--boundary\r
Content-Disposition: form-data; name=\"field1\"\r
\r
value1\r
--boundary\r
Content-Disposition: form-data; name=\"field2\"; filename=\"example.txt\"\r
\r
va\nlue2\r
--boundary--\r
"
.to_vec(),
is_complete: true,
};
let map = req.get_post_data(&["field1", "field2"], &data).unwrap();
assert_eq!(
&b"value1".to_vec(),
map.get("field1").unwrap().as_ref().unwrap()
);
assert_eq!(
&b"value2\n".to_vec(),
&b"va\nlue2".to_vec(),
map.get("field2").unwrap().as_ref().unwrap()
);
}
......
......@@ -7,7 +7,7 @@
<body>
<h1>404</h1>
<p>Hi from Rust</p>
<form action="/post/post" method="post">
<form action="/post/post" method="post" enctype="multipart/form-data">
<label for="message">Enter your message:</label>
<input type="text" id="message" name="message" />
<button type="submit">Send</button>
......
......@@ -62,12 +62,11 @@ fn post_hi_handler(request: Request, data: Data) -> Outcome<Response, Status, Da
if data.is_empty() {
return Outcome::Forward(data);
}
// let data = if let Ok(val) = request.get_post_text_form_key("message", &data) {
// val
// } else {
// return Outcome::Failure(Status::BadRequest);
// };
let dat = post_hi(String::from_utf8(data.buffer).unwrap());
let dat = if let Ok(val) = request.get_post_data(&["message"], &data) {
post_hi(String::from_utf8_lossy(val.get("message").unwrap().as_ref().unwrap()).to_string())
} else {
return Outcome::Failure(Status::BadRequest);
};
Outcome::Success(Response {
headers: vec![
format!("Content-Length: {}", dat.len()),
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment