mco_http/multipart/
mult_part.rs1use std::io::{ErrorKind, Read, Write};
2use crate::multipart::{Node, Part, FilePart};
3use mime::{Mime, TopLevel, SubLevel};
4use crate::multipart::error::Error;
5use crate::header::{ContentDisposition, ContentType, DispositionParam, DispositionType, Headers};
6
7#[derive(Clone, Debug)]
11pub struct FormData {
12 pub fields: Vec<(String, String)>,
15 pub files: Vec<(String, FilePart)>,
18}
19
20impl FormData {
21 pub fn new() -> FormData {
22 FormData { fields: vec![], files: vec![] }
23 }
24
25 pub fn to_multipart(&mut self) -> Result<Vec<Node>, Error> {
27 let mut nodes: Vec<Node> = Vec::with_capacity(self.fields.len() + self.files.len());
29
30 for &(ref name, ref value) in &self.fields {
31 let mut h = crate::header::Headers::with_capacity(2);
32 h.set(ContentType(Mime(TopLevel::Text, SubLevel::Plain, vec![])));
33 h.set(ContentDisposition {
34 disposition: DispositionType::Ext("form-data".to_owned()),
35 parameters: vec![DispositionParam::Ext("name".to_owned(), name.clone())],
36 });
37 nodes.push(Node::Part(Part {
38 headers: h,
39 body: value.as_bytes().to_owned(),
40 }));
41 }
42
43 for &(ref name, ref filepart) in &self.files {
44 let mut filepart = filepart.clone();
45 while filepart.headers.remove::<ContentDisposition>() {};
48 let filename = match filepart.filename() {
49 Ok(fname) => fname.to_string(),
50 Err(_) => return Err(Error::Io(std::io::Error::new(ErrorKind::InvalidData, "not a file"))),
51 };
52 filepart.headers.set(ContentDisposition {
53 disposition: DispositionType::Ext("form-data".to_owned()),
54 parameters: vec![DispositionParam::Ext("name".to_owned(), name.clone()),
55 DispositionParam::Ext("filename".to_owned(), filename)],
56 });
57 nodes.push(Node::File(filepart));
58 }
59
60 Ok(nodes)
61 }
62}
63
64
65pub fn read_formdata<S: Read>(stream: &mut S, headers: &Headers, f: Option<fn(name: &mut FilePart) -> std::io::Result<()>>) -> Result<FormData, Error>
67{
68 let nodes = crate::multipart::read_multipart_body(stream, headers, false, f)?;
69 let mut formdata = FormData::new();
70 fill_formdata(&mut formdata, nodes)?;
71 Ok(formdata)
72}
73
74fn fill_formdata(formdata: &mut FormData, nodes: Vec<Node>) -> Result<(), Error>
79{
80 for node in nodes {
81 match node {
82 Node::Part(part) => {
83 let cd_name: Option<String> = {
84 let cd: &ContentDisposition = match part.headers.get() {
85 Some(cd) => cd,
86 None => return Err(Error::MissingDisposition),
87 };
88 get_content_disposition_name(&cd)
89 };
90 let key = cd_name.ok_or(Error::NoName)?;
91 let val = String::from_utf8(part.body)?;
92 formdata.fields.push((key, val));
93 }
94 Node::File(part) => {
95 let cd_name: Option<String> = {
96 let cd: &ContentDisposition = match part.headers.get() {
97 Some(cd) => cd,
98 None => return Err(Error::MissingDisposition),
99 };
100 get_content_disposition_name(&cd)
101 };
102 let key = cd_name.ok_or(Error::NoName)?;
103 formdata.files.push((key, part));
104 }
105 Node::Multipart((headers, nodes)) => {
106 let cd_name: Option<String> = {
107 let cd: &ContentDisposition = match headers.get() {
108 Some(cd) => cd,
109 None => return Err(Error::MissingDisposition),
110 };
111 get_content_disposition_name(&cd)
112 };
113 let key = cd_name.ok_or(Error::NoName)?;
114 for node in nodes {
115 match node {
116 Node::Part(part) => {
117 let val = String::from_utf8(part.body)?;
118 formdata.fields.push((key.clone(), val));
119 }
120 Node::File(part) => {
121 formdata.files.push((key.clone(), part));
122 }
123 _ => {} }
125 }
126 }
127 }
128 }
129 Ok(())
130}
131
132#[inline]
133pub fn get_content_disposition_name(cd: &ContentDisposition) -> Option<String> {
134 if let Some(&DispositionParam::Ext(_, ref value)) = cd.parameters.iter()
135 .find(|&x| match *x {
136 DispositionParam::Ext(ref token, _) => &*token == "name",
137 _ => false,
138 })
139 {
140 Some(value.clone())
141 } else {
142 None
143 }
144}
145
146
147pub fn write_formdata<S: Write,W:Write>(stream: &mut S, boundary: &Vec<u8>, formdata: &mut FormData, w: Option<fn(name: &mut FilePart) -> std::io::Result<()>>)
151 -> Result<usize, Error>
152{
153 let mut nodes = formdata.to_multipart()?;
154
155 let count = crate::multipart::write_multipart(stream, boundary, &mut nodes,w)?;
157
158 Ok(count)
159}
160
161pub fn write_formdata_chunked<S: Write>(stream: &mut S, boundary: &Vec<u8>, formdata: &mut FormData)
165 -> Result<(), Error>
166{
167 let nodes = formdata.to_multipart()?;
168
169 crate::multipart::write_multipart_chunked(stream, boundary, &nodes)?;
171
172 Ok(())
173}