rusty_web/parser/
mod.rs

1use std::collections::HashMap;
2
3pub mod body {
4    use std::io::{Seek, SeekFrom, Write};
5    use tempfile::NamedTempFile;
6    use crate::headers;
7    use crate::headers::Headers;
8    use crate::parser::body::reader::StreamReader;
9
10    pub struct Limits {
11        pub max_body_size: usize,
12    }
13
14    #[derive(Debug)]
15    pub enum BodyReadError {
16        MaxBodySizeExceed,
17        ContentLengthMissing,
18        BodyAlreadyRead,
19        Others(&'static str),
20    }
21
22    pub mod reader {
23        use std::io::Read;
24        use std::net::TcpStream;
25        use crate::parser::body::{BodyReadError, Limits};
26
27        pub trait StreamReader {
28            fn get_chunk(&mut self) -> Result<Vec<u8>, BodyReadError>;
29            fn get_exact(&mut self, size: usize) -> Result<Vec<u8>, BodyReadError>;
30        }
31
32        pub struct BodyReader {
33            stream: TcpStream,
34            content_length: usize,
35            bytes_read: usize,
36            limits: Limits,
37        }
38
39        impl BodyReader {
40            pub fn new(stream: TcpStream, content_length: usize, bytes_read: usize, limits: Limits) -> Self {
41                return Self {
42                    stream,
43                    content_length,
44                    bytes_read,
45                    limits,
46                };
47            }
48        }
49
50        impl StreamReader for BodyReader {
51            fn get_chunk(&mut self) -> Result<Vec<u8>, BodyReadError> {
52                if self.bytes_read >= self.content_length {
53                    return Err(BodyReadError::MaxBodySizeExceed);
54                }
55
56                if self.bytes_read >= self.limits.max_body_size {
57                    return Err(BodyReadError::BodyAlreadyRead);
58                }
59
60                let mut buffer = [0u8; 1024];
61                let read_result = self.stream.read(&mut buffer);
62                if !read_result.is_ok() {
63                    return Err(BodyReadError::Others(
64                        "Unable to read stream. May be client disconnected."
65                    ));
66                }
67
68                let chunk_length = read_result.unwrap();
69                let chunk = Vec::from(&buffer[0..chunk_length]);
70                self.bytes_read += chunk_length;
71                return Ok(chunk);
72            }
73
74            fn get_exact(&mut self, size: usize) -> Result<Vec<u8>, BodyReadError> {
75                if self.bytes_read >= self.content_length {
76                    return Err(BodyReadError::MaxBodySizeExceed);
77                }
78
79                if self.bytes_read >= self.limits.max_body_size {
80                    return Err(BodyReadError::BodyAlreadyRead);
81                }
82
83                let mut buffer = vec![0u8; size];
84                let read_result = self.stream.read_exact(&mut buffer);
85                if !read_result.is_ok() {
86                    return Err(BodyReadError::Others(
87                        "Unable to read stream. May be client disconnected."
88                    ));
89                }
90                self.bytes_read += size;
91                return Ok(buffer);
92            }
93        }
94    }
95
96    pub fn parse<T: StreamReader>(partial_bytes: Vec<u8>, headers: &Headers, mut reader: T)
97                                  -> Result<NamedTempFile, BodyReadError> {
98        let mut body_buffer = Vec::from(partial_bytes);
99        let mut body_read = body_buffer.len();
100
101        let content_length = headers::content_length(&headers);
102        if !content_length.is_some() {
103            return Err(BodyReadError::ContentLengthMissing);
104        }
105
106        // Create new tmp directory
107        let temp_file_create = NamedTempFile::new();
108        let mut temp_file;
109
110        match temp_file_create {
111            Ok(file) => {
112                temp_file = file;
113            }
114
115            Err(_) => {
116                return Err(BodyReadError::Others("Error creating temporary file"));
117            }
118        }
119
120        let content_length = content_length.unwrap();
121
122        loop {
123            let write_result = temp_file.write_all(&body_buffer);
124            if !write_result.is_ok() {
125                return Err(BodyReadError::Others("Error writing to temporary file"));
126            }
127
128            if body_read >= content_length {
129                let seek_result = temp_file.seek(SeekFrom::Start(0));
130                if !seek_result.is_ok() {
131                    return Err(BodyReadError::Others("Failed to seek temporary file"));
132                }
133                return Ok(temp_file);
134            }
135
136            body_buffer.clear();
137
138            let read_result = reader.get_chunk();
139            match read_result {
140                Ok(chunk) => {
141                    body_read += chunk.len();
142                    body_buffer.extend(chunk);
143                }
144                Err(error) => {
145                    return Err(error);
146                }
147            }
148        }
149    }
150}
151
152pub fn parse_url_encoded(text: &str) -> HashMap<String, Vec<String>> {
153    let mut params = HashMap::new();
154    let values = text.split("&");
155
156    for value in values {
157        let key_values: Vec<&str> = value.split("=").collect();
158        if key_values.len() >= 2 {
159            let name = key_values.get(0).unwrap();
160            let value = key_values.get(1).unwrap();
161
162            let name_formatted = url_decode(name);
163            let value_formatted = url_decode(value);
164
165            if !params.contains_key(&name_formatted) {
166                params.insert(name.to_string(), Vec::new());
167            }
168
169            let values = params.get_mut(&name_formatted).unwrap();
170            values.push(value_formatted);
171        }
172    }
173    return params;
174}
175
176pub fn url_decode(value: &str) -> String {
177    return match urlencoding::decode(value) {
178        Ok(decoded_value) => {
179            decoded_value.to_string()
180        }
181        Err(_) => {
182            value.to_string()
183        }
184    };
185}
186
187pub mod url_encoded {
188    use std::collections::HashMap;
189    use crate::headers;
190    use crate::headers::{Headers};
191    use crate::parser::parse_url_encoded;
192    use crate::parser::url_encoded::reader::StreamReader;
193
194    #[derive(Debug)]
195    pub enum UrlEncodedFormDataError {
196        /// Occurs, if the request body is not x-www-form-urlencoded
197        InvalidFormat(&'static str),
198        /// Occurs, if there is no Content-Length header
199        ContentLengthMissing(&'static str),
200        /// Occurs, if failed to parse the request
201        ParsingError(&'static str),
202        /// Occurs, if the request body size exceed the given size
203        MaxBodySizeExceed(&'static str),
204        /// Occurs, if parser requires more data to parse fully, but there is no more data left
205        BodyReadEnd,
206        /// Occurs, if error not fulfilled by above conditions
207        Others(&'static str),
208    }
209
210    pub mod reader {
211        use std::io::Read;
212        use std::net::TcpStream;
213        use crate::parser::url_encoded::UrlEncodedFormDataError;
214
215        /// The reusable trait for fetching "x-www-form-urlencoded" form data
216        pub trait StreamReader {
217            fn get_chunk(&mut self) -> Result<Vec<u8>, UrlEncodedFormDataError>;
218            fn get_exact(&mut self, size: usize) -> Result<Vec<u8>, UrlEncodedFormDataError>;
219        }
220
221        pub struct UrlEncodedReader {
222            pub stream: TcpStream,
223            pub content_length: usize,
224            // Size of bytes that has been already read
225            pub bytes_read: usize,
226            pub body_ended: bool,
227        }
228
229        impl UrlEncodedReader {
230            pub fn new(stream: TcpStream, content_length: usize, bytes_read: usize) -> Self {
231                let body_ended;
232
233                if bytes_read == content_length {
234                    body_ended = true;
235                } else {
236                    body_ended = false;
237                };
238
239                return Self {
240                    stream,
241                    content_length,
242                    bytes_read,
243                    body_ended,
244                };
245            }
246
247            fn update_read_status(&mut self, new_chunk: &[u8]) {
248                self.bytes_read += new_chunk.len();
249
250                if self.bytes_read >= self.content_length {
251                    self.body_ended = true;
252                }
253            }
254        }
255
256        impl StreamReader for UrlEncodedReader {
257            fn get_chunk(&mut self) -> Result<Vec<u8>, UrlEncodedFormDataError> {
258                if self.body_ended {
259                    return Err(UrlEncodedFormDataError::BodyReadEnd);
260                }
261
262                let mut buffer = [0u8; 1024];
263                let read_result = self.stream.read(&mut buffer);
264
265                if !read_result.is_ok() {
266                    return Err(UrlEncodedFormDataError::Others(
267                        "Unable to read stream. May be client disconnected."
268                    ));
269                }
270
271                let read_size = read_result.unwrap();
272
273                if read_size == 0 {
274                    return Err(UrlEncodedFormDataError::Others("Bytes read size is 0. Probably client disconnected."));
275                }
276
277                let chunk = &buffer[0..read_size];
278                self.update_read_status(chunk);
279                return Ok(chunk.to_vec());
280            }
281
282            fn get_exact(&mut self, size: usize) -> Result<Vec<u8>, UrlEncodedFormDataError> {
283                if self.body_ended {
284                    return Err(UrlEncodedFormDataError::BodyReadEnd);
285                }
286
287                let mut buffer = vec![0u8; size];
288                let result = self.stream.read_exact(&mut buffer);
289                if !result.is_ok() {
290                    return Err(UrlEncodedFormDataError::Others(
291                        "Unable to read stream. May be client disconnected."
292                    ));
293                }
294
295                return Ok(buffer.to_vec());
296            }
297        }
298    }
299
300    pub struct Limits {
301        pub max_body_size: usize,
302    }
303
304    pub type FormFields = HashMap<String, Vec<String>>;
305
306    pub fn parse<T: StreamReader>(partial_bytes: Vec<u8>, headers: &Headers, reader: &mut T,
307                                  limits: Limits) -> Result<FormFields, UrlEncodedFormDataError> {
308        let mut body_buffer = Vec::from(partial_bytes);
309        let content_length = headers::content_length(headers);
310
311        if let Some(content_length) = content_length {
312            if content_length > limits.max_body_size {
313                return Err(UrlEncodedFormDataError::MaxBodySizeExceed(
314                    "Request body size is larger than the limit."
315                ));
316            }
317        } else {
318            return Err(UrlEncodedFormDataError::ContentLengthMissing(
319                "Content-Length header is missing."
320            ));
321        }
322
323        let content_length = content_length.unwrap();
324        let bytes_read = body_buffer.len();
325
326        // Load all the request body to memory
327        while content_length > bytes_read {
328            let request_chunk = reader.get_chunk();
329
330            match request_chunk {
331                Ok(chunk) => {
332                    body_buffer.extend(chunk);
333                }
334
335                Err(error) => {
336                    return Err(error);
337                }
338            }
339        };
340
341        let value = String::from_utf8_lossy(&body_buffer).to_string();
342        let form_values = parse_url_encoded(value.as_str());
343        return Ok(form_values);
344    }
345}
346
347pub mod multipart {
348    use std::collections::HashMap;
349    use std::io::{Seek, SeekFrom, Write};
350    use regex::Regex;
351    use tempfile::NamedTempFile;
352    use crate::headers;
353    use crate::headers::Headers;
354
355    #[derive(Debug)]
356    pub enum MultipartFormDataError {
357        /// Occurs, if the request body is not multipart/form-data
358        InvalidMultiPart(&'static str),
359        /// Occurs, if failed to parse the request
360        ParsingError(&'static str),
361        /// Occurs, if the size of the form part header exceeds the given size
362        HeaderSizeExceed(&'static str),
363        /// Occurs, if the request body size exceed the given size
364        MaxBodySizeExceed(&'static str),
365        /// Occurs, if the form part content size exceed
366        MaxFieldSizeExceed(String, &'static str),
367        /// Occurs, if parser requires more data to parse fully, but there is no more data left
368        BodyReadEnd,
369        /// Occurs, if error not fulfilled by above conditions
370        Others(&'static str),
371    }
372
373
374    /// The reusable trait for fetching multipart bytes
375    pub trait StreamReader {
376        fn get_chunk(&mut self) -> Result<Vec<u8>, MultipartFormDataError>;
377        fn get_exact(&mut self, size: usize) -> Result<Vec<u8>, MultipartFormDataError>;
378    }
379
380    /// Extracts boundary from Content-Type header.
381    pub fn extract_boundary(content_type: &String) -> Option<String> {
382        let value: Vec<&str> = content_type.split(";").collect();
383
384        if value.len() >= 2 {
385            let content_type_text = value.get(1).unwrap().trim();
386            let boundary = content_type_text.strip_prefix("boundary=").unwrap();
387            return Some(boundary.to_string());
388        }
389
390        return None;
391    }
392
393    pub mod reader {
394        use std::io::Read;
395        use std::net::TcpStream;
396        use crate::parser::multipart::{MultipartFormDataError, StreamReader};
397
398        pub struct FormDataReader {
399            pub stream: TcpStream,
400            pub boundary_end_bytes: Vec<u8>,
401            pub content_length: Option<usize>,
402            // Size of bytes that has been already read
403            pub bytes_read: usize,
404            pub body_ended: bool,
405            /// Store only some amount of bytes equals to the boundary end bytes
406            body_buffer: Vec<u8>,
407        }
408
409        impl FormDataReader {
410            pub fn new(stream: TcpStream, boundary: String, content_length: Option<usize>, body_read: usize) -> Self {
411                let boundary_end = format!("--{}\r\n", boundary);
412                let boundary_end_bytes = boundary_end.as_bytes().to_vec();
413                let body_buffer = Vec::with_capacity(boundary_end_bytes.len());
414
415                let body_ended;
416                if let Some(content_length) = content_length {
417                    body_ended = body_read >= content_length;
418                } else if body_buffer.ends_with(&boundary_end_bytes) {
419                    body_ended = true;
420                } else {
421                    body_ended = false;
422                }
423
424                return Self {
425                    stream,
426                    boundary_end_bytes,
427                    content_length,
428                    bytes_read: body_read,
429                    body_ended,
430                    body_buffer,
431                };
432            }
433
434            /// Performs checks and updates status
435            fn update_read_status(&mut self, new_chunk: &[u8]) {
436                self.bytes_read += new_chunk.len();
437
438                if self.content_length.is_some() {
439                    let body_ended = self.bytes_read >= self.content_length.unwrap();
440                    if body_ended {
441                        self.body_ended = true;
442                    }
443                } else {
444                    if self.body_buffer.ends_with(&self.boundary_end_bytes) {
445                        self.body_ended = true;
446                        return;
447                    }
448
449                    // Read is not finished yet, but we will prepare for next time
450                    // If length of new chunk is more than the boundary end bytes, it means data is not ended yet.
451                    // We can copy whole last bytes equivalent of boundary end bytes
452                    if new_chunk.len() > self.boundary_end_bytes.len() {
453                        self.body_buffer.clear();
454                        let last_sice = &new_chunk[(self.boundary_end_bytes.len() - self.boundary_end_bytes.len())..self.boundary_end_bytes.len()];
455                        self.body_buffer.extend(last_sice);
456                    } else {
457                        // If the chunk is smaller than the boundary length
458                        // Merge old and new slice and save in the body_buffer
459                        let start_index = self.boundary_end_bytes.len() - new_chunk.len() - 1;
460                        let old_slice_to_copy = &self.body_buffer[start_index..].to_owned();
461
462                        self.body_buffer.clear();
463                        self.body_buffer.extend(old_slice_to_copy);
464                        self.body_buffer.extend(new_chunk);
465                    }
466                }
467            }
468        }
469
470        impl StreamReader for FormDataReader {
471            fn get_chunk(&mut self) -> Result<Vec<u8>, MultipartFormDataError> {
472                if self.body_ended {
473                    return Err(MultipartFormDataError::BodyReadEnd);
474                }
475
476                const BUFFER_SIZE: usize = 8 * 1024; // 8 KiB
477                let mut buffer = [0u8; BUFFER_SIZE];
478                let result = self.stream.read(&mut buffer);
479
480                if !result.is_ok() {
481                    return Err(MultipartFormDataError::Others("Unable to read stream. May be client disconnected."));
482                }
483
484                let read_size = result.unwrap();
485                if read_size == 0 {
486                    return Err(MultipartFormDataError::Others("Bytes read size is 0. Probably client disconnected."));
487                }
488
489                let chunk_slice = &buffer[0..read_size];
490                self.update_read_status(&chunk_slice);
491
492                let chunk = Vec::from(chunk_slice);
493                return Ok(chunk);
494            }
495
496            fn get_exact(&mut self, size: usize) -> Result<Vec<u8>, MultipartFormDataError> {
497                if self.body_ended {
498                    return Err(MultipartFormDataError::BodyReadEnd);
499                }
500
501                let mut buffer: Vec<u8> = vec![0u8; size];
502                let result = self.stream.read_exact(&mut buffer);
503                if !result.is_ok() {
504                    return Err(MultipartFormDataError::Others("Unable to read stream. May be client disconnected."));
505                }
506
507                self.update_read_status(&buffer);
508                return Ok(buffer);
509            }
510        }
511    }
512
513    #[derive(Debug)]
514    pub struct FormPart {
515        pub name: Option<String>,
516        pub filename: Option<String>,
517        pub content_type: Option<String>,
518        pub temp_file: Option<NamedTempFile>,
519        pub value: Option<Vec<u8>>,
520    }
521
522    #[derive(Debug)]
523    pub struct FormPartLimit {
524        pub max_size: Option<usize>,
525        pub content_type: Option<String>,
526    }
527
528    #[derive(Debug)]
529    pub struct Limits {
530        pub max_body_size: Option<usize>,
531        pub max_header_size: Option<usize>,
532        pub max_value_size: Option<usize>,
533        pub form_part_limits: HashMap<String, FormPartLimit>,
534    }
535
536    impl Limits {
537        pub fn none() -> Self {
538            return Self {
539                max_body_size: None,
540                max_header_size: None,
541                max_value_size: None,
542                form_part_limits: HashMap::new(),
543            };
544        }
545    }
546
547    #[derive(Debug)]
548    pub enum FormPartResult {
549        CheckNext,
550        BodyCompleted,
551    }
552
553    impl FormPart {
554        pub fn empty() -> Self {
555            return FormPart {
556                name: None,
557                filename: None,
558                content_type: None,
559                temp_file: None,
560                value: None,
561            };
562        }
563    }
564
565    /// It expects that the header has been completely read including \r\n\r\n characters.
566    ///
567    ///
568    /// Here's example:
569    /// ```markdown
570    /// ----------------------------648887867674240986891965
571    /// Content-Disposition: form-data; name="name"
572    ///
573    /// John Doe
574    /// ----------------------------648887867674240986891965
575    /// Content-Disposition: form-data; name="file"; filename="a.txt"
576    /// Content-Type: text/plain
577    ///
578    ///
579    /// hello
580    ///
581    /// ----------------------------648887867674240986891965
582    /// Content-Disposition: form-data; name="gender"
583    ///
584    /// male
585    /// ----------------------------648887867674240986891965--
586    /// ```
587    pub fn parse<T: StreamReader>(partial_bytes: Vec<u8>, headers: &Headers, reader: T, limits: Limits)
588                                  -> Result<Vec<FormPart>, MultipartFormDataError> {
589        let content_type_bytes = headers.get("Content-Type");
590
591        let content_type: String;
592        if let Some(content_type_bytes) = content_type_bytes {
593            content_type = content_type_bytes.get(0).unwrap().to_owned();
594        } else {
595            return Err(MultipartFormDataError::InvalidMultiPart("Content-Type header missing."));
596        };
597
598        let multipart_boundary: String;
599        if let Some(boundary) = extract_boundary(&content_type) {
600            multipart_boundary = boundary;
601        } else {
602            return Err(MultipartFormDataError::InvalidMultiPart("Unable to extract multipart boundary."));
603        }
604
605        // Check if the client body is larger than the limit
606        if let Some(max_body_size) = limits.max_body_size {
607            if let Some(content_length) = headers::content_length(&headers) {
608                if content_length > max_body_size {
609                    return Err(MultipartFormDataError::MaxBodySizeExceed("Maximum specified body size exceed."));
610                }
611            }
612        }
613
614        let body_buffer = Vec::from(partial_bytes);
615        return parse_body_parts(reader, body_buffer, &multipart_boundary, limits);
616    }
617
618    pub fn parse_body_parts<T: StreamReader>(mut reader: T, mut body_buffer: Vec<u8>, boundary: &String,
619                                             limits: Limits) -> Result<Vec<FormPart>, MultipartFormDataError> {
620        let mut form_parts = Vec::new();
621
622        // Remove starting boundary first. It will make parsing easy by matching \r\n--{boundary}
623
624        let start_boundary = format!("--{}\r\n", boundary);
625        let start_boundary_bytes = start_boundary.as_bytes();
626
627        // All the data is not be received. If not received try to read the required number bytes to make the boundary string.
628        if body_buffer.len() <= start_boundary_bytes.len() {
629            // Instead of reading bytes of some length, we will read exactly bytes required to prevent from reading again.
630            let bytes_required = start_boundary_bytes.len() - body_buffer.len();
631            let chunk_request_result = reader.get_exact(bytes_required);
632
633            match chunk_request_result {
634                Ok(chunk) => {
635                    body_buffer.extend(chunk);
636                }
637
638                Err(error) => {
639                    return Err(error);
640                }
641            }
642        };
643
644        if !body_buffer_starts_with_boundary(&body_buffer, start_boundary_bytes) {
645            return Err(MultipartFormDataError::InvalidMultiPart("Body does not start with boundary"));
646        }
647
648        // Remove boundary header start
649        body_buffer = Vec::from(&body_buffer[start_boundary_bytes.len()..]);
650
651        // Now, we can start looping the form part contents.
652        loop {
653            // Extract header from form part
654            let header_result = extract_form_part_header(
655                &mut reader,
656                &mut body_buffer,
657                &limits,
658            );
659            if !header_result.is_ok() {
660                return Err(header_result.unwrap_err());
661            }
662
663            let form_part_header = header_result.unwrap();
664            let header_text = String::from_utf8_lossy(&form_part_header).to_string();
665
666            // Parse header obtained above
667            let header_parse_result = parse_form_part_header(header_text);
668            if !header_parse_result.is_ok() {
669                return Err(header_parse_result.unwrap_err());
670            }
671
672            // Obtain form part after parsing header.
673            // This contains file metadata and form name, value
674            let mut form_part = header_parse_result.unwrap();
675
676            // Extract the body to value or temporary file.
677            // If it is file, it will be available on form_part.temp_file else value
678            let body_parse_result = extract_form_part_body(
679                &mut reader,
680                &mut body_buffer,
681                boundary,
682                &mut form_part,
683                &limits,
684            );
685
686            match body_parse_result {
687                Ok(result) => {
688                    match result {
689                        FormPartResult::BodyCompleted => {
690                            form_parts.push(form_part);
691                            return Ok(form_parts);
692                        }
693
694                        FormPartResult::CheckNext => {
695                            form_parts.push(form_part);
696                            // Continue looping
697                        }
698                    }
699                }
700
701                Err(error) => {
702                    return Err(error);
703                }
704            }
705        }
706    }
707
708    pub fn body_buffer_starts_with_boundary(body_buffer: &Vec<u8>, start_boundary_bytes: &[u8]) -> bool {
709        // Check if the body buffer starts with start boundary or not. If not we will discard and don't process further.
710        let extracted_boundary_slice = &body_buffer[0..start_boundary_bytes.len()];
711        return extracted_boundary_slice == start_boundary_bytes;
712    }
713
714    /// Parses the form part header and removes the header from body buffer including \r\n\r\n bytes.
715    ///
716    /// ```markdown
717    /// Content-Disposition: form-data; name="name"
718    ///
719
720    /// John Doe
721    /// ----------------------------648887867674240986891965
722    /// Content-Disposition: form-data; name="file"; filename="a.txt"
723    /// Content-Type: text/plain
724    ///
725    ///
726    /// ... continues
727    /// ```
728    pub fn extract_form_part_header<T: StreamReader>(reader: &mut T, body_buffer: &mut Vec<u8>, limits: &Limits)
729                                                     -> Result<Vec<u8>, MultipartFormDataError> {
730        // There can be one CRLF line break as well as two. Need to handle both cases.
731        let header_end_bytes = b"\r\n\r\n";
732        let mut form_part_header_buffer = Vec::new();
733
734        let max_header_size = limits.max_header_size;
735
736        loop {
737            let scan_result = body_buffer.windows(header_end_bytes.len())
738                .position(|window| window == header_end_bytes);
739
740            if let Some(found_index) = scan_result {
741                // Copy the found header to form part header
742                form_part_header_buffer.extend(&body_buffer[0..found_index]);
743
744                // If MAX_HEADER_SIZE exceeds, return error.
745                if max_header_size.is_some() && (form_part_header_buffer.len() >= max_header_size.unwrap()) {
746                    return Err(MultipartFormDataError::HeaderSizeExceed("Header size exceed max specified size"));
747                }
748
749                // Remove the found header including trailing header end bytes
750                *body_buffer = Vec::from(&body_buffer[found_index + header_end_bytes.len()..]);
751                return Ok(form_part_header_buffer);
752            } else {
753                // Header is not found yet. However, we copy the unmatched buffer too except last 4 bytes;
754                // Last 4 bytes not copied to header buffer because it'README.md half part may be available in the buffer next time
755                // after new read. So we can't check if it ends or not.
756                // If there is no enough data to copy to header buffer we ignore and fill more data to body buffer.
757                let to_copy_to_header_buffer = body_buffer.len() as i32 - header_end_bytes.len() as i32;
758                if to_copy_to_header_buffer > 0 {
759                    // Append new data to header buffer
760                    form_part_header_buffer.extend(header_end_bytes);
761                    // Also remove copied data from body buffer
762                    *body_buffer = Vec::from(&body_buffer[to_copy_to_header_buffer as usize..]);
763                }
764
765                // If MAX_HEADER_SIZE exceeds, return error.
766                if max_header_size.is_some() && (form_part_header_buffer.len() >= max_header_size.unwrap()) {
767                    return Err(MultipartFormDataError::HeaderSizeExceed("Header size exceed max specified size"));
768                } else {
769                    let request_new_chunk = reader.get_chunk();
770
771                    match request_new_chunk {
772                        Ok(new_chunk) => {
773                            body_buffer.extend(new_chunk);
774                        }
775
776                        Err(error) => {
777                            return Err(error);
778                        }
779                    }
780                }
781            };
782        }
783    }
784
785    /// Expects only the header
786    pub fn parse_form_part_header(part_header: String) -> Result<FormPart, MultipartFormDataError> {
787        let mut form_part = FormPart::empty();
788
789        let headers: Vec<&str> = part_header.split("\r\n").collect();
790
791        // Splitting headers lines by \r\n
792        for header_line in headers {
793            // Parse individual header line and update the form part.
794            parse_header_line(header_line, &mut form_part);
795        }
796
797        return Ok(form_part);
798    }
799
800    pub fn parse_header_line(line: &str, form_part: &mut FormPart) {
801        let line = line.trim();
802
803        if line.is_empty() {
804            return;
805        }
806
807        let name_value: Vec<&str> = line.split(":").collect();
808        if name_value.len() >= 2 {
809            let header_name = name_value.get(0).unwrap().trim();
810            let header_value = name_value.get(1).unwrap().trim();
811
812            // If the header is Content-Disposition, extract the metadata
813            if header_name.to_lowercase() == "Content-Disposition".to_lowercase() {
814                parse_content_disposition_value(header_value, form_part);
815            } else if header_name.to_lowercase() == "Content-Type".to_lowercase() {
816                parse_content_type(header_value, form_part);
817            }
818        }
819    }
820
821
822    /// Expects value of Content-Disposition value.
823    ///
824    /// Example:
825    /// ```markdown
826    /// form-data; name="username"
827    /// form-data; name="file"; filename="hello.txt"
828    /// ```
829    pub fn parse_content_disposition_value(value: &str, form_part: &mut FormPart) {
830        let value = value.trim();
831
832        if !value.starts_with("form-data;") {
833            // Not a valid Content-Deposition value for form part header
834            return;
835        }
836
837        let remaining = value.strip_prefix("form-data;").unwrap().trim();
838        let pattern = Regex::new(r#"(?<attribute>\w+)="(?<value>[^"]*)""#).unwrap();
839
840        for captured in pattern.captures_iter(remaining) {
841            let attribute = &captured["attribute"];
842            let value = &captured["value"];
843
844            if attribute == "name" {
845                form_part.name = Some(value.to_string());
846            } else if attribute == "filename" {
847                form_part.filename = Some(value.to_string());
848            }
849        }
850    }
851
852    pub fn parse_content_type(value: &str, form_part: &mut FormPart) {
853        form_part.content_type = Some(value.to_string());
854    }
855
856    pub fn extract_form_part_body<T: StreamReader>(reader: &mut T, body_buffer: &mut Vec<u8>, boundary: &String,
857                                                   form_part: &mut FormPart, limits: &Limits) ->
858                                                   Result<FormPartResult, MultipartFormDataError> {
859        let field_name = &form_part.name;
860
861        let mut form_part_limit: Option<&FormPartLimit> = None;
862        if field_name.is_some() {
863            let field_name = field_name.clone().unwrap();
864            form_part_limit = limits.form_part_limits.get(&field_name);
865        }
866
867        let is_file = form_part.filename.is_some();
868        if is_file {
869            return extract_form_file_body(reader, body_buffer, boundary, form_part, form_part_limit);
870        }
871
872        let field_value_limit;
873        if form_part_limit.is_some() {
874            // No limit set for field value. Since it will be stored in the memory,
875            // default limit is set
876            field_value_limit = FormPartLimit {
877                max_size: form_part_limit.unwrap().max_size,
878                content_type: None,
879            };
880        } else {
881            field_value_limit = FormPartLimit {
882                max_size: limits.max_value_size,
883                content_type: None,
884            }
885        }
886
887        form_part_limit = Some(&field_value_limit);
888        return extract_form_value(reader, body_buffer, boundary, form_part, form_part_limit);
889    }
890
891    /// It writes the file to temporary file.
892    /// Example to copy file
893    /// ```markdown
894    /// // Example to copy temp file
895    ///
896    /// let filename = &form_part.filename.unwrap();
897    /// let owned = filename.to_owned();
898    /// let path = temp_file.path();
899    ///
900    /// fs::copy(path, owned).expect("Error copying");
901    /// ```
902    pub fn extract_form_file_body<T: StreamReader>(reader: &mut T, body_buffer: &mut Vec<u8>, boundary: &String,
903                                                   form_part: &mut FormPart, form_part_limit: Option<&FormPartLimit>)
904                                                   -> Result<FormPartResult, MultipartFormDataError> {
905        // Create new tmp directory
906        let temp_file_create = NamedTempFile::new();
907        let mut temp_file;
908
909        match temp_file_create {
910            Ok(file) => {
911                temp_file = file;
912            }
913
914            Err(_) => {
915                return Err(MultipartFormDataError::Others("Error creating temporary file"));
916            }
917        }
918
919        // Files can be ended with single CRLF line breaks as well as multiple.
920        // \r\n and --\r\n are ignored to match later. These will decide whether there is next form part or body ends.
921        let file_end_matcher = format!("\r\n--{}", boundary);
922        let file_end_matching_bytes = file_end_matcher.as_bytes();
923
924        let mut bytes_written: usize = 0;
925
926        loop {
927            let search_file_end = body_buffer.windows(file_end_matching_bytes.len())
928                .position(|window| window == file_end_matching_bytes);
929
930            // Position where file_end_matcher started matching
931            if let Some(body_end_index) = search_file_end {
932                // Check if file is empty or not. If body_end_index is 0, either file is empty or file is already
933                // written but body end is just matched.
934
935                if body_end_index > 0 {
936                    // Body end position has been found
937                    // Exact body bytes left range
938                    let mut bytes_to_copy = &body_buffer[0..body_end_index];
939                    bytes_written += bytes_to_copy.len();
940
941                    // Check extra two bytes if the file body ends with \r\n. Some client adds double CRLF line breaks.
942                    // If file body ends with \r\n, ignore
943                    if bytes_to_copy.ends_with(b"\r\n") {
944                        bytes_to_copy = &bytes_to_copy[0..bytes_to_copy.len() - 2];
945                    }
946
947                    let write_result = temp_file.write_all(bytes_to_copy);
948                    if !write_result.is_ok() {
949                        return Err(MultipartFormDataError::Others("Error writing to temporary file"));
950                    }
951
952                    // Remove copied data from body buffer including boundary by creating new array.
953                    *body_buffer = Vec::from(&body_buffer[body_end_index + file_end_matching_bytes.len()..]);
954                }
955
956                // Check if the file size is more than the limit set.
957                if form_part_limit.is_some() && (bytes_written > form_part_limit.unwrap().max_size.unwrap()) {
958                    return Err(MultipartFormDataError::MaxFieldSizeExceed(
959                        form_part.name.clone().unwrap().to_string(),
960                        "The file is bigger than the maximum allowed size")
961                    );
962                }
963
964                // Check if it is the last form content or still there are others.
965                // If it is the last form part content, it will contain --\r\n in next bytes.
966                // If it is not last the last form part content, there will be \r\n in next bytes.
967                // Till now, we don't know if body is completed or not.
968
969                let end_body_bytes = b"--\r\n";
970                let next_part_bytes = b"\r\n";
971                // Read exact 4 bytes if there is nothing in the body buffer else request required number of bytes.
972                // 4 bytes should be there before completing request body.
973
974                if body_buffer.len() < 4 {
975                    // Amount of bytes to read
976                    let bytes_to_read = 4 - body_buffer.len();
977
978                    let request_new_chunk = reader.get_exact(bytes_to_read);
979                    match request_new_chunk {
980                        Ok(chunk) => {
981                            body_buffer.extend(chunk);
982                        }
983                        Err(error) => {
984                            return Err(error);
985                        }
986                    }
987                }
988
989                // Compare --\r\n
990                let body_end_compare = &body_buffer[0..4];
991                if body_end_compare == end_body_bytes {
992                    // All form part has been parsed
993                    body_buffer.clear();
994                    if !temp_file.seek(SeekFrom::Start(0)).is_ok() {
995                        return Err(MultipartFormDataError::Others("Error to seek start 0 temporary file."));
996                    }
997
998                    form_part.temp_file = Some(temp_file);
999                    return Ok(FormPartResult::BodyCompleted);
1000                }
1001
1002                // Compare \r\n
1003                let form_part_next_compare = &body_buffer[0..2];
1004                if form_part_next_compare == next_part_bytes {
1005                    // Remove \r\n bytes from the body buffer
1006                    *body_buffer = Vec::from(&body_buffer[2..]);
1007
1008                    if !temp_file.seek(SeekFrom::Start(0)).is_ok() {
1009                        return Err(MultipartFormDataError::Others("Error seek to start 0 temporary file."));
1010                    }
1011
1012                    form_part.temp_file = Some(temp_file);
1013                    return Ok(FormPartResult::CheckNext);
1014                }
1015
1016                // None of the condition is satisfied. Problem with the request body.
1017                return Err(MultipartFormDataError::ParsingError("Form content did not end with \r\n"));
1018            } else {
1019                // Body end still not found. Add new chunk to body buffer
1020                // However we still write the data from the buffer except last bytes equal to the boundary match header.
1021                // We don't want to compare with half bytes of boundary which will never match.
1022                // Instead, keep last bytes of boundary bytes size still in the body buffer to compare later.
1023
1024                // This many bytes can be copied to temp file if it'README.md size > 0
1025                // Here 2 is the size of length of \r\n which can be ignorable from the file.
1026                // Some uses single CRLF line break as well as double line breaks.
1027                // Don't move data from buffer to file if the length of the buffer is smaller than the
1028                // ending boundary + \r\n bytes.
1029
1030                let to_copy_size = body_buffer.len() as i32 - (file_end_matching_bytes.len() as i32 + 2);
1031
1032                if to_copy_size > 0 {
1033                    let to_copy = &body_buffer[0..to_copy_size as usize];
1034
1035                    let write_result = temp_file.write_all(to_copy);
1036                    if !write_result.is_ok() {
1037                        return Err(MultipartFormDataError::Others("Error writing to temporary file"));
1038                    }
1039
1040                    // Remove copied bytes from the body buffer
1041                    *body_buffer = Vec::from(&body_buffer[to_copy_size as usize..]);
1042                    bytes_written += to_copy_size as usize;
1043                }
1044
1045                if form_part_limit.is_some() && (bytes_written > form_part_limit.unwrap().max_size.unwrap()) {
1046                    return Err(MultipartFormDataError::MaxFieldSizeExceed(
1047                        form_part.name.clone().unwrap().to_string(),
1048                        "The file is bigger than the maximum allowed size"));
1049                }
1050
1051                let request_new_chunk = reader.get_chunk();
1052
1053                match request_new_chunk {
1054                    Ok(new_chunk) => {
1055                        body_buffer.extend(new_chunk);
1056                    }
1057
1058                    Err(error) => {
1059                        return Err(error);
1060                    }
1061                }
1062            };
1063        };
1064    }
1065
1066    pub fn extract_form_value<T: StreamReader>(reader: &mut T, body_buffer: &mut Vec<u8>, boundary: &String,
1067                                               form_part: &mut FormPart, form_part_limit: Option<&FormPartLimit>)
1068                                               -> Result<FormPartResult, MultipartFormDataError> {
1069        let value_end_matcher = format!("\r\n--{}", boundary);
1070        let value_end_matching_bytes = value_end_matcher.as_bytes();
1071
1072        let mut value_buffer: Vec<u8> = Vec::new();
1073        let mut bytes_written: usize = 0;
1074
1075        let mut max_value_size = None;
1076        if form_part_limit.is_some() {
1077            max_value_size = form_part_limit.unwrap().max_size;
1078        }
1079
1080        loop {
1081            let end_index = body_buffer.windows(value_end_matching_bytes.len())
1082                .position(|window| window == value_end_matching_bytes);
1083
1084            if let Some(end_index) = end_index {
1085                // Either value is empty or value has already stored, but its end is just matched
1086                if end_index > 0 {
1087                    // Value end found
1088                    let mut to_copy_bytes = &body_buffer[..end_index];
1089
1090                    if to_copy_bytes.ends_with(b"\r\n") {
1091                        to_copy_bytes = &to_copy_bytes[0..to_copy_bytes.len() - 2]
1092                    }
1093
1094                    bytes_written += to_copy_bytes.len();
1095                    value_buffer.extend(to_copy_bytes);
1096
1097                    // Remove partial value end boundary from body buffer
1098                    *body_buffer = Vec::from(&body_buffer[end_index + value_end_matching_bytes.len()..]);
1099                }
1100
1101                // Check if the value bytes written is larger than the limit specified
1102                if max_value_size.is_some() && max_value_size.unwrap() > bytes_written {
1103                    return Err(MultipartFormDataError::MaxFieldSizeExceed(
1104                        form_part.name.clone().unwrap().to_string(),
1105                        "The form field value size exceeds the limit specified",
1106                    ));
1107                }
1108
1109                // Check if it is the last form content or still there are others.
1110                // If it is the last form part content, it will contain --\r\n in next bytes.
1111                // If it is not last the last form part content, there will be \r\n in next bytes.
1112                // Till now, we don't know if body is completed or not.
1113
1114                let end_body_bytes = b"--\r\n";
1115                let next_part_bytes = b"\r\n";
1116                // Read exact 4 bytes if there is nothing in the body buffer else request required number of bytes.
1117                // 4 bytes should be there before completing request body.
1118
1119                if body_buffer.len() < 4 {
1120                    // Amount of bytes to read
1121                    let bytes_to_read = 4 - body_buffer.len();
1122
1123                    let request_new_chunk = reader.get_exact(bytes_to_read);
1124                    match request_new_chunk {
1125                        Ok(chunk) => {
1126                            body_buffer.extend(chunk);
1127                        }
1128                        Err(error) => {
1129                            return Err(error);
1130                        }
1131                    }
1132                }
1133
1134                // Compare --\r\n
1135                let body_end_compare = &body_buffer[0..4];
1136                if body_end_compare == end_body_bytes {
1137                    // All form part has been parsed
1138                    body_buffer.clear();
1139                    form_part.value = Some(value_buffer);
1140                    return Ok(FormPartResult::BodyCompleted);
1141                }
1142
1143                // Compare \r\n
1144                let form_part_next_compare = &body_buffer[0..2];
1145                if form_part_next_compare == next_part_bytes {
1146                    // Remove \r\n bytes from the body buffer
1147                    *body_buffer = Vec::from(&body_buffer[2..]);
1148                    form_part.value = Some(value_buffer);
1149                    return Ok(FormPartResult::CheckNext);
1150                }
1151
1152                // None of the condition is satisfied. Problem with the request body.
1153                return Err(MultipartFormDataError::ParsingError("Form content did not end with \r\n"));
1154            } else {
1155                // Value end not found
1156
1157                // Copy scanned values to buffer except last bytes equal to the length of value_end_matching_bytes
1158                // We left last some bytes equal to value_end_matching_bytes because we need to compare again.
1159                // Here 2 is the size of length of \r\n which can be ignorable from the value.
1160                // Some uses single CRLF line break as well as double line breaks.
1161                let to_copy_size = body_buffer.len() as i32 - (value_end_matching_bytes.len() as i32 + 2);
1162                if to_copy_size > 0 {
1163                    bytes_written += to_copy_size as usize;
1164
1165                    // This many bytes can be copied to value_buffer
1166                    value_buffer.extend(&body_buffer[..to_copy_size as usize]);
1167                    // Remove copied bytes form body buffer
1168                    *body_buffer = Vec::from(&body_buffer[to_copy_size as usize..]);
1169                }
1170
1171                if form_part_limit.is_some() && (bytes_written > form_part_limit.unwrap().max_size.unwrap()) {
1172                    return Err(MultipartFormDataError::MaxFieldSizeExceed(
1173                        form_part.name.clone().unwrap().to_string(),
1174                        "The form field value size exceeds the limit specified")
1175                    );
1176                }
1177
1178                let request_new_chunk = reader.get_chunk();
1179                match request_new_chunk {
1180                    Ok(chunk) => {
1181                        body_buffer.extend(chunk);
1182                    }
1183
1184                    Err(error) => {
1185                        return Err(error);
1186                    }
1187                }
1188            }
1189        }
1190    }
1191}
1192
1193#[cfg(test)]
1194mod test {
1195    use std::collections::HashMap;
1196    use std::io::{Read};
1197    use rand::{Rng};
1198    use crate::headers::Headers;
1199    use crate::parser::multipart::{StreamReader};
1200    use crate::parser::multipart::{
1201        extract_form_part_body,
1202        extract_form_value,
1203        FormPart,
1204        Limits,
1205        MultipartFormDataError,
1206        parse,
1207        parse_form_part_header,
1208    };
1209
1210    struct ChunkReader {
1211        body_bytes: Vec<u8>,
1212        bytes_read: usize,
1213    }
1214
1215    impl ChunkReader {
1216        fn new(body: &str, bytes_read: usize) -> Self {
1217            let body_bytes = body.as_bytes().to_vec();
1218
1219            return ChunkReader {
1220                body_bytes,
1221                bytes_read,
1222            };
1223        }
1224
1225        fn get_bytes_left(&self) -> usize {
1226            // Number of bytes that are left
1227            let bytes_left: i32 = self.body_bytes.len() as i32 - self.bytes_read as i32;
1228
1229            // Simulate socket broken
1230            if bytes_left > 0 {
1231                return bytes_left as usize;
1232            }
1233
1234            println!("Waiting forever...");
1235            println!("Socket connection broken.");
1236            return 0;
1237        }
1238    }
1239
1240    impl StreamReader for ChunkReader {
1241        fn get_chunk(&mut self) -> Result<Vec<u8>, MultipartFormDataError> {
1242            // Number of bytes that are left
1243            let bytes_left = self.get_bytes_left();
1244            if bytes_left == 0 {
1245                return Err(MultipartFormDataError::BodyReadEnd);
1246            }
1247
1248            let to_read = rand::thread_rng().gen_range(0..bytes_left + 1);
1249            let chunk = Vec::from(&self.body_bytes[self.bytes_read..&self.bytes_read + to_read]);
1250            self.bytes_read = self.bytes_read + to_read;
1251            return Ok(chunk);
1252        }
1253
1254        fn get_exact(&mut self, size: usize) -> Result<Vec<u8>, MultipartFormDataError> {
1255            let bytes_left = self.get_bytes_left();
1256            if bytes_left == 0 {
1257                println!("Waiting...");
1258                println!("Body is already read");
1259                return Err(MultipartFormDataError::BodyReadEnd);
1260            }
1261            let chunk = &self.body_bytes[self.bytes_read..self.bytes_read + size];
1262            self.bytes_read = self.bytes_read + size;
1263            return Ok(Vec::from(chunk));
1264        }
1265    }
1266
1267    const SAMPLE_BODY: &str = "----------------------------211628740782087473305609\r\nContent-Disposition: form-data; name=\"name\"\r\n\r\nJohn Doe\r\n----------------------------211628740782087473305609\r\nContent-Disposition: form-data; name=\"file\"; filename=\"a.txt\"\r\nContent-Type: text/plain\r\n\r\nhello\n\r\n----------------------------211628740782087473305609\r\nContent-Disposition: form-data; name=\"file\"; filename=\"a.txt\"\r\nContent-Type: text/plain\r\n\r\nhello\n\r\n----------------------------211628740782087473305609\r\nContent-Disposition: form-data; name=\"gender\"\r\n\r\nmale\r\n----------------------------211628740782087473305609--\r\n";
1268    const SAMPLE_BODY_2: &str = "--boundary123\r\nContent-Disposition: form-data; name=\"field1\"\r\n\r\nvalue1\r\n\r\n--boundary123\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example.txt\"\r\nContent-Type: text/plain\r\n\r\nThis is the content of the file.\r\n--boundary123\r\nContent-Disposition: form-data; name=\"field2\"\r\n\r\nvalue2\r\n--boundary123--\r\n";
1269
1270    #[test]
1271    fn test_parser() {
1272        let mut reader = ChunkReader::new(SAMPLE_BODY_2, 0);
1273        let request_chunk_result = reader.get_exact(SAMPLE_BODY_2.len());
1274        assert_eq!(true, request_chunk_result.is_ok());
1275
1276        let mut headers: Headers = HashMap::new();
1277        // let content_type = vec!["multipart/form-data; boundary=--------------------------211628740782087473305609".to_string()];
1278        let content_type = vec!["multipart/form-data; boundary=boundary123".to_string()];
1279        headers.insert("Content-Type".to_string(), content_type);
1280
1281        let partial_body = request_chunk_result.unwrap();
1282        let parse_result = parse(partial_body, &headers, reader, Limits::none());
1283        match parse_result {
1284            Ok(form_parts) => {
1285                println!("Parsing success:");
1286
1287                for form_part in form_parts.iter() {
1288                    println!("Name: {}", form_part.name.as_ref().unwrap());
1289                    if form_part.value.as_ref().is_some() {
1290                        println!("Value: {:?}", String::from_utf8(form_part.value.as_ref().unwrap().to_vec()));
1291                    }
1292                }
1293            }
1294
1295            Err(error) => {
1296                println!("Error: {:?}", error);
1297            }
1298        }
1299    }
1300
1301    #[test]
1302    fn test_header_parser() {
1303        let header_sample_1 = "\r\nContent-Disposition: form-data; name=\"John Doe\"\r\n\r\n";
1304        let parsing_result = parse_form_part_header(header_sample_1.to_string());
1305        assert_eq!(true, parsing_result.is_ok());
1306        let form_part = parsing_result.unwrap();
1307        assert_eq!("John Doe", form_part.name.unwrap());
1308
1309        let header_sample_2 = "Content-Disposition: form-data; name=\"file\"; filename=\"a.txt\"\r\n\
1310        Content-Type: text/plain\r\n\r\n";
1311        let parsing_result = parse_form_part_header(header_sample_2.to_string());
1312        assert_eq!(true, parsing_result.is_ok());
1313        let form_part = parsing_result.unwrap();
1314
1315        assert_eq!(form_part.name.unwrap(), "file");
1316        assert_eq!(form_part.filename.unwrap(), "a.txt");
1317        assert_eq!(form_part.content_type.unwrap(), "text/plain");
1318    }
1319
1320    #[test]
1321    fn test_extract_file_body() {
1322        let sample_body = "John Doe\r\n\r\n----------------------------163905767229441796406063\r\nContent-Disposition...";
1323
1324        for _ in 0..10 {
1325            let mut form_part = FormPart {
1326                name: Some("file".to_string()),
1327                filename: Some("file.txt".to_string()),
1328                content_type: Some("text/html".to_string()),
1329                temp_file: None,
1330                value: None,
1331            };
1332
1333            let mut reader = ChunkReader::new(sample_body, 0);
1334            let mut body_buffer = reader.get_chunk().unwrap();
1335            // let mut body_buffer = Vec::new();
1336
1337            let boundary = "--------------------------163905767229441796406063".to_string();
1338            let result = extract_form_part_body(&mut reader, &mut body_buffer,
1339                                                &boundary, &mut form_part, &Limits::none());
1340            match result {
1341                Ok(res) => {
1342                    println!("{:?}", res);
1343                    let mut temp_file = &form_part.temp_file.unwrap();
1344                    // Example to copy temp file
1345                    // let filename = &form_part.filename.unwrap();
1346                    // let owned = filename.to_owned();
1347                    // let path = temp_file.path();
1348                    // std::fs::copy(path, owned).expect("Error copying");
1349
1350                    let mut content = String::new();
1351                    temp_file.read_to_string(&mut content).expect("Error reading temporary file");
1352                    assert_eq!(content, "John Doe");
1353                }
1354
1355                Err(_) => {
1356                    panic!("Multipart body parsing returned error.");
1357                }
1358            }
1359        }
1360    }
1361
1362    #[test]
1363    fn test_extract_form_value() {
1364        let sample_body = "John Doe\r\n----------------------------163905767229441796406063\r\nContent-Disposition";
1365        let mut reader = ChunkReader::new(sample_body, 0);
1366        let mut body_buffer = reader.get_chunk().unwrap();
1367        let boundary = "--------------------------163905767229441796406063".to_string();
1368        let mut form_part = FormPart::empty();
1369
1370        let result = extract_form_value(
1371            &mut reader,
1372            &mut body_buffer,
1373            &boundary,
1374            &mut form_part,
1375            None,
1376        );
1377
1378        assert_eq!(true, result.is_ok());
1379        assert_eq!(b"John Doe", &form_part.value.unwrap().as_slice());
1380    }
1381}