2018-04-30 20:22:48 +00:00
|
|
|
/*
|
|
|
|
* This file is part of Actix Form Data.
|
|
|
|
*
|
|
|
|
* Copyright © 2018 Riley Trautman
|
|
|
|
*
|
|
|
|
* Actix Form Data is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* Actix Form Data is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with Actix Form Data. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2020-05-15 16:59:31 +00:00
|
|
|
use crate::Error;
|
|
|
|
use bytes::Bytes;
|
|
|
|
use futures::Stream;
|
|
|
|
use log::trace;
|
|
|
|
use mime::Mime;
|
2018-10-09 23:35:10 +00:00
|
|
|
use std::{
|
|
|
|
collections::{HashMap, VecDeque},
|
|
|
|
fmt,
|
2020-05-15 16:59:31 +00:00
|
|
|
pin::Pin,
|
2018-10-09 23:35:10 +00:00
|
|
|
};
|
2018-04-29 22:31:06 +00:00
|
|
|
|
2020-05-15 16:59:31 +00:00
|
|
|
pub struct FileStream {
|
|
|
|
pub filename: String,
|
|
|
|
pub content_type: Mime,
|
|
|
|
pub stream: Pin<Box<dyn Stream<Item = Result<Bytes, Error>>>>,
|
|
|
|
}
|
2018-04-29 22:31:06 +00:00
|
|
|
|
2020-05-15 16:59:31 +00:00
|
|
|
impl fmt::Debug for FileStream {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
f.debug_struct("FileStream")
|
|
|
|
.field("filename", &self.filename)
|
|
|
|
.field("content_type", &self.content_type)
|
|
|
|
.finish()
|
|
|
|
}
|
|
|
|
}
|
2018-04-29 22:31:06 +00:00
|
|
|
|
2018-04-30 20:22:48 +00:00
|
|
|
/// The result of a succesfull parse through a given multipart stream.
|
|
|
|
///
|
|
|
|
/// This type represents all possible variations in structure of a Multipart Form.
|
|
|
|
///
|
|
|
|
/// # Example usage
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// # use form_data::Value;
|
|
|
|
/// # use std::collections::HashMap;
|
|
|
|
/// # let mut hm = HashMap::new();
|
|
|
|
/// # hm.insert("field-name".to_owned(), Value::Int(32));
|
|
|
|
/// # let value = Value::Map(hm);
|
|
|
|
/// match value {
|
|
|
|
/// Value::Map(mut hashmap) => {
|
|
|
|
/// match hashmap.remove("field-name") {
|
|
|
|
/// Some(value) => match value {
|
|
|
|
/// Value::Int(integer) => println!("{}", integer),
|
|
|
|
/// _ => (),
|
|
|
|
/// }
|
|
|
|
/// None => (),
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// _ => (),
|
|
|
|
/// }
|
|
|
|
/// ```
|
2020-05-15 16:59:31 +00:00
|
|
|
#[derive(Debug)]
|
2018-04-30 20:22:48 +00:00
|
|
|
pub enum Value {
|
|
|
|
Map(HashMap<String, Value>),
|
|
|
|
Array(Vec<Value>),
|
2020-05-15 16:59:31 +00:00
|
|
|
File(FileStream),
|
|
|
|
Bytes(Bytes),
|
2018-04-30 20:22:48 +00:00
|
|
|
Text(String),
|
|
|
|
Int(i64),
|
|
|
|
Float(f64),
|
2018-04-29 22:31:06 +00:00
|
|
|
}
|
|
|
|
|
2018-04-30 20:22:48 +00:00
|
|
|
impl Value {
|
|
|
|
pub(crate) fn merge(&mut self, rhs: Self) {
|
2020-05-15 16:59:31 +00:00
|
|
|
match self {
|
|
|
|
Value::Map(ref mut hm) => {
|
|
|
|
if let Value::Map(other) = rhs {
|
|
|
|
other.into_iter().fold(hm, |hm, (key, value)| {
|
|
|
|
if let Some(v) = hm.get_mut(&key) {
|
|
|
|
v.merge(value);
|
|
|
|
} else {
|
|
|
|
hm.insert(key.to_owned(), value);
|
|
|
|
}
|
|
|
|
|
|
|
|
hm
|
|
|
|
});
|
|
|
|
}
|
2018-04-30 20:22:48 +00:00
|
|
|
}
|
2020-05-15 16:59:31 +00:00
|
|
|
Value::Array(ref mut v) => {
|
|
|
|
if let Value::Array(other) = rhs {
|
|
|
|
v.extend(other);
|
|
|
|
}
|
2018-04-30 20:22:48 +00:00
|
|
|
}
|
|
|
|
_ => (),
|
2018-04-29 22:31:06 +00:00
|
|
|
}
|
|
|
|
}
|
2018-10-18 01:04:30 +00:00
|
|
|
|
|
|
|
pub fn map(self) -> Option<HashMap<String, Value>> {
|
|
|
|
match self {
|
|
|
|
Value::Map(map) => Some(map),
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn array(self) -> Option<Vec<Value>> {
|
|
|
|
match self {
|
|
|
|
Value::Array(vec) => Some(vec),
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-15 16:59:31 +00:00
|
|
|
pub fn file(self) -> Option<FileStream> {
|
|
|
|
match self {
|
|
|
|
Value::File(file_stream) => Some(file_stream),
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn bytes(self) -> Option<Bytes> {
|
2018-10-18 01:04:30 +00:00
|
|
|
match self {
|
2020-05-15 16:59:31 +00:00
|
|
|
Value::Bytes(bytes) => Some(bytes),
|
2018-10-18 01:04:30 +00:00
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn text(self) -> Option<String> {
|
|
|
|
match self {
|
|
|
|
Value::Text(text) => Some(text),
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn int(self) -> Option<i64> {
|
|
|
|
match self {
|
|
|
|
Value::Int(int) => Some(int),
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn float(self) -> Option<f64> {
|
|
|
|
match self {
|
|
|
|
Value::Float(float) => Some(float),
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
2018-04-29 22:31:06 +00:00
|
|
|
}
|
|
|
|
|
2018-04-30 20:22:48 +00:00
|
|
|
impl From<MultipartContent> for Value {
|
|
|
|
fn from(mc: MultipartContent) -> Self {
|
|
|
|
match mc {
|
2020-05-15 16:59:31 +00:00
|
|
|
MultipartContent::File(file_stream) => Value::File(file_stream),
|
|
|
|
MultipartContent::Bytes(bytes) => Value::Bytes(bytes),
|
2018-04-30 20:22:48 +00:00
|
|
|
MultipartContent::Text(string) => Value::Text(string),
|
|
|
|
MultipartContent::Int(i) => Value::Int(i),
|
|
|
|
MultipartContent::Float(f) => Value::Float(f),
|
2018-04-29 22:31:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-30 20:22:48 +00:00
|
|
|
/// The field type represents a field in the form-data that is allowed to be parsed.
|
2018-04-29 22:31:06 +00:00
|
|
|
#[derive(Clone)]
|
|
|
|
pub enum Field {
|
|
|
|
Array(Array),
|
|
|
|
Map(Map),
|
2020-05-15 16:59:31 +00:00
|
|
|
File,
|
|
|
|
Bytes,
|
2018-04-29 22:31:06 +00:00
|
|
|
Int,
|
|
|
|
Float,
|
|
|
|
Text,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Debug for Field {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
match *self {
|
|
|
|
Field::Array(ref arr) => write!(f, "Array({:?})", arr),
|
|
|
|
Field::Map(ref map) => write!(f, "Map({:?})", map),
|
2020-05-15 16:59:31 +00:00
|
|
|
Field::File => write!(f, "File"),
|
|
|
|
Field::Bytes => write!(f, "Bytes"),
|
2018-04-29 22:31:06 +00:00
|
|
|
Field::Int => write!(f, "Int"),
|
|
|
|
Field::Float => write!(f, "Float"),
|
|
|
|
Field::Text => write!(f, "Text"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Field {
|
2018-04-30 20:22:48 +00:00
|
|
|
/// Add a File field with a name generator.
|
|
|
|
///
|
|
|
|
/// The name generator will be called for each file matching this field's key. Keep in mind
|
|
|
|
/// that each key/file pair will have it's own name-generator, so sharing a name-generator
|
|
|
|
/// between fields is up to the user.
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
/// ```rust
|
2020-05-15 16:59:31 +00:00
|
|
|
/// # use form_data::{Form, Field};
|
|
|
|
/// #
|
|
|
|
/// let form = Form::new().field("file-field", Field::file());
|
2018-04-30 20:22:48 +00:00
|
|
|
/// ```
|
2020-05-15 16:59:31 +00:00
|
|
|
pub fn file() -> Self {
|
|
|
|
Field::File
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Add a Bytes field to a form
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
/// ```rust
|
|
|
|
/// # use form_data::{Form, Field};
|
|
|
|
/// let form = Form::new().field("text-field", Field::bytes());
|
|
|
|
pub fn bytes() -> Self {
|
|
|
|
Field::Bytes
|
2018-04-29 22:31:06 +00:00
|
|
|
}
|
|
|
|
|
2018-04-30 20:22:48 +00:00
|
|
|
/// Add a Text field to a form
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
/// ```rust
|
|
|
|
/// # use form_data::{Form, Field};
|
|
|
|
/// let form = Form::new().field("text-field", Field::text());
|
2018-04-29 22:31:06 +00:00
|
|
|
pub fn text() -> Self {
|
|
|
|
Field::Text
|
|
|
|
}
|
|
|
|
|
2018-04-30 20:22:48 +00:00
|
|
|
/// Add an Int field to a form
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
/// ```rust
|
|
|
|
/// # use form_data::{Form, Field};
|
|
|
|
/// let form = Form::new().field("int-field", Field::int());
|
|
|
|
/// ```
|
2018-04-29 22:31:06 +00:00
|
|
|
pub fn int() -> Self {
|
|
|
|
Field::Int
|
|
|
|
}
|
|
|
|
|
2018-04-30 20:22:48 +00:00
|
|
|
/// Add a Float field to a form
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
/// ```rust
|
|
|
|
/// # use form_data::{Form, Field};
|
|
|
|
/// let form = Form::new().field("float-field", Field::float());
|
|
|
|
/// ```
|
2018-04-29 22:31:06 +00:00
|
|
|
pub fn float() -> Self {
|
|
|
|
Field::Float
|
|
|
|
}
|
|
|
|
|
2018-04-30 20:22:48 +00:00
|
|
|
/// Add an Array to a form
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
/// ```rust
|
|
|
|
/// # extern crate form_data;
|
|
|
|
/// # use form_data::{Form, Field};
|
|
|
|
/// # fn main() {
|
|
|
|
/// let form = Form::new()
|
|
|
|
/// .field(
|
|
|
|
/// "array-field",
|
|
|
|
/// Field::array(Field::text())
|
|
|
|
/// );
|
|
|
|
/// # }
|
|
|
|
/// ```
|
2018-04-29 22:31:06 +00:00
|
|
|
pub fn array(field: Field) -> Self {
|
|
|
|
Field::Array(Array::new(field))
|
|
|
|
}
|
|
|
|
|
2018-04-30 20:22:48 +00:00
|
|
|
/// Add a Map to a form
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
/// ```rust
|
|
|
|
/// # extern crate form_data;
|
|
|
|
/// # use form_data::{Form, Field};
|
|
|
|
/// # fn main() {
|
|
|
|
/// let form = Form::new()
|
|
|
|
/// .field(
|
|
|
|
/// "map-field",
|
|
|
|
/// Field::map()
|
|
|
|
/// .field("sub-field", Field::text())
|
|
|
|
/// .field("sub-field-two", Field::text())
|
|
|
|
/// .finalize()
|
|
|
|
/// );
|
|
|
|
/// # }
|
|
|
|
/// ```
|
2018-04-29 22:31:06 +00:00
|
|
|
pub fn map() -> Map {
|
|
|
|
Map::new()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn valid_field(&self, name: VecDeque<NamePart>) -> Option<FieldTerminator> {
|
|
|
|
trace!("Checking {:?} and {:?}", self, name);
|
|
|
|
match *self {
|
|
|
|
Field::Array(ref arr) => arr.valid_field(name),
|
|
|
|
Field::Map(ref map) => map.valid_field(name),
|
2020-05-15 16:59:31 +00:00
|
|
|
Field::File => {
|
2018-10-09 23:35:10 +00:00
|
|
|
if name.is_empty() {
|
2020-05-15 16:59:31 +00:00
|
|
|
Some(FieldTerminator::File)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Field::Bytes => {
|
|
|
|
if name.is_empty() {
|
|
|
|
Some(FieldTerminator::Bytes)
|
2018-10-09 23:35:10 +00:00
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Field::Int => {
|
|
|
|
if name.is_empty() {
|
|
|
|
Some(FieldTerminator::Int)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Field::Float => {
|
|
|
|
if name.is_empty() {
|
|
|
|
Some(FieldTerminator::Float)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Field::Text => {
|
|
|
|
if name.is_empty() {
|
|
|
|
Some(FieldTerminator::Text)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
2018-04-29 22:31:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-30 20:22:48 +00:00
|
|
|
/// A definition of an array of type `Field` to be parsed from form data.
|
|
|
|
///
|
|
|
|
/// The `Array` type should only be constructed in the context of a Form. See the `Form`
|
|
|
|
/// documentation for more information.
|
2018-04-29 22:31:06 +00:00
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub struct Array {
|
|
|
|
inner: Box<Field>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Array {
|
|
|
|
fn new(field: Field) -> Self {
|
|
|
|
Array {
|
|
|
|
inner: Box::new(field),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn valid_field(&self, mut name: VecDeque<NamePart>) -> Option<FieldTerminator> {
|
|
|
|
trace!("Checking {:?} and {:?}", self, name);
|
|
|
|
match name.pop_front() {
|
|
|
|
Some(name_part) => match name_part {
|
|
|
|
NamePart::Array => self.inner.valid_field(name),
|
|
|
|
_ => None,
|
|
|
|
},
|
|
|
|
None => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-30 20:22:48 +00:00
|
|
|
/// A definition of key-value pairs to be parsed from form data.
|
2018-04-29 22:31:06 +00:00
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub struct Map {
|
|
|
|
inner: Vec<(String, Field)>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Map {
|
|
|
|
fn new() -> Self {
|
|
|
|
Map { inner: Vec::new() }
|
|
|
|
}
|
|
|
|
|
2018-04-30 20:22:48 +00:00
|
|
|
/// Add a `Field` to a map
|
|
|
|
/// # Example
|
|
|
|
/// ```rust
|
|
|
|
/// # use form_data::Field;
|
|
|
|
/// #
|
|
|
|
/// Field::map()
|
|
|
|
/// .field("sub-field", Field::text())
|
|
|
|
/// .field("sub-field-two", Field::text())
|
|
|
|
/// .finalize();
|
|
|
|
/// ```
|
2018-04-29 22:31:06 +00:00
|
|
|
pub fn field(mut self, key: &str, value: Field) -> Self {
|
|
|
|
self.inner.push((key.to_owned(), value));
|
|
|
|
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2018-04-30 20:22:48 +00:00
|
|
|
/// Finalize the map into a `Field`, so it can be added to a Form
|
|
|
|
/// ```rust
|
|
|
|
/// # use form_data::Field;
|
|
|
|
/// #
|
|
|
|
/// Field::map()
|
|
|
|
/// .field("sub-field", Field::text())
|
|
|
|
/// .field("sub-field-two", Field::text())
|
|
|
|
/// .finalize();
|
|
|
|
/// ```
|
2018-04-29 22:31:06 +00:00
|
|
|
pub fn finalize(self) -> Field {
|
|
|
|
Field::Map(self)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn valid_field(&self, mut name: VecDeque<NamePart>) -> Option<FieldTerminator> {
|
|
|
|
trace!("Checking {:?} and {:?}", self, name);
|
|
|
|
match name.pop_front() {
|
|
|
|
Some(name_part) => match name_part {
|
2018-10-09 23:35:10 +00:00
|
|
|
NamePart::Map(part_name) => self
|
|
|
|
.inner
|
2018-04-29 22:31:06 +00:00
|
|
|
.iter()
|
2018-04-30 20:44:17 +00:00
|
|
|
.find(|&&(ref item, _)| *item == part_name)
|
|
|
|
.and_then(|&(_, ref field)| field.valid_field(name)),
|
2018-04-29 22:31:06 +00:00
|
|
|
_ => None,
|
|
|
|
},
|
|
|
|
None => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-30 20:22:48 +00:00
|
|
|
/// A structure that defines the fields expected in form data
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
/// ```rust
|
2020-05-15 16:59:31 +00:00
|
|
|
/// # use form_data::{Form, Field};
|
2018-04-30 20:22:48 +00:00
|
|
|
/// let form = Form::new()
|
|
|
|
/// .field("field-name", Field::text())
|
|
|
|
/// .field("second-field", Field::int())
|
|
|
|
/// .field("third-field", Field::float())
|
2020-05-15 16:59:31 +00:00
|
|
|
/// .field("fifth-field", Field::file())
|
2018-04-30 20:22:48 +00:00
|
|
|
/// .field(
|
|
|
|
/// "map-field",
|
|
|
|
/// Field::map()
|
|
|
|
/// .field("sub-field", Field::text())
|
|
|
|
/// .field("sub-field-two", Field::text())
|
|
|
|
/// .finalize()
|
|
|
|
/// )
|
|
|
|
/// .field(
|
|
|
|
/// "array-field",
|
|
|
|
/// Field::array(Field::text())
|
|
|
|
/// );
|
|
|
|
/// ```
|
2018-04-29 22:31:06 +00:00
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct Form {
|
|
|
|
pub max_fields: u32,
|
2018-04-30 20:22:48 +00:00
|
|
|
pub max_field_size: usize,
|
2018-04-29 22:31:06 +00:00
|
|
|
pub max_files: u32,
|
2018-04-30 20:22:48 +00:00
|
|
|
pub max_file_size: usize,
|
2018-04-29 22:31:06 +00:00
|
|
|
inner: Map,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Form {
|
2018-04-30 20:22:48 +00:00
|
|
|
/// Create a new form
|
|
|
|
///
|
2019-05-08 23:11:26 +00:00
|
|
|
/// If you wish to provide your own executor, use the `with_executor` method.
|
2018-04-29 22:31:06 +00:00
|
|
|
pub fn new() -> Self {
|
2019-05-08 23:11:26 +00:00
|
|
|
Form {
|
|
|
|
max_fields: 100,
|
|
|
|
max_field_size: 10_000,
|
|
|
|
max_files: 20,
|
|
|
|
max_file_size: 10_000_000,
|
|
|
|
inner: Map::new(),
|
|
|
|
}
|
2018-04-29 22:31:06 +00:00
|
|
|
}
|
|
|
|
|
2018-04-30 20:22:48 +00:00
|
|
|
/// Set the maximum number of fields allowed in the upload
|
|
|
|
///
|
|
|
|
/// The upload will error if too many fields are provided.
|
2018-04-29 22:31:06 +00:00
|
|
|
pub fn max_fields(mut self, max: u32) -> Self {
|
|
|
|
self.max_fields = max;
|
|
|
|
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2018-04-30 20:22:48 +00:00
|
|
|
/// Set the maximum size of a field (in bytes)
|
|
|
|
///
|
|
|
|
/// The upload will error if a provided field is too large.
|
|
|
|
pub fn max_field_size(mut self, max: usize) -> Self {
|
2018-04-29 22:31:06 +00:00
|
|
|
self.max_field_size = max;
|
|
|
|
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2018-04-30 20:22:48 +00:00
|
|
|
/// Set the maximum number of files allowed in the upload
|
|
|
|
///
|
|
|
|
/// THe upload will error if too many files are provided.
|
2018-04-29 22:31:06 +00:00
|
|
|
pub fn max_files(mut self, max: u32) -> Self {
|
|
|
|
self.max_files = max;
|
|
|
|
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2018-04-30 20:22:48 +00:00
|
|
|
/// Set the maximum size for files (in bytes)
|
|
|
|
///
|
|
|
|
/// The upload will error if a provided file is too large.
|
|
|
|
pub fn max_file_size(mut self, max: usize) -> Self {
|
2018-04-29 22:31:06 +00:00
|
|
|
self.max_file_size = max;
|
|
|
|
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn field(mut self, name: &str, field: Field) -> Self {
|
|
|
|
self.inner = self.inner.field(name, field);
|
|
|
|
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2018-04-30 20:22:48 +00:00
|
|
|
pub(crate) fn valid_field(&self, name: VecDeque<NamePart>) -> Option<FieldTerminator> {
|
2018-04-29 22:31:06 +00:00
|
|
|
self.inner.valid_field(name.clone())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Debug for Form {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
write!(f, "Form({:?})", self.inner)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-29 23:15:00 +00:00
|
|
|
#[derive(Clone, Debug, PartialEq)]
|
2018-04-30 20:22:48 +00:00
|
|
|
pub(crate) struct ContentDisposition {
|
|
|
|
pub name: Option<String>,
|
|
|
|
pub filename: Option<String>,
|
2018-04-29 23:15:00 +00:00
|
|
|
}
|
2018-04-30 01:27:38 +00:00
|
|
|
|
2018-04-30 20:22:48 +00:00
|
|
|
impl ContentDisposition {
|
|
|
|
pub(crate) fn empty() -> Self {
|
|
|
|
ContentDisposition {
|
|
|
|
name: None,
|
|
|
|
filename: None,
|
|
|
|
}
|
|
|
|
}
|
2018-04-30 01:27:38 +00:00
|
|
|
}
|
|
|
|
|
2018-04-30 20:22:48 +00:00
|
|
|
#[derive(Clone, Debug, PartialEq)]
|
|
|
|
pub(crate) enum NamePart {
|
|
|
|
Map(String),
|
|
|
|
Array,
|
|
|
|
}
|
2018-04-30 01:27:38 +00:00
|
|
|
|
2018-04-30 20:22:48 +00:00
|
|
|
impl NamePart {
|
|
|
|
pub fn is_map(&self) -> bool {
|
|
|
|
match *self {
|
|
|
|
NamePart::Map(_) => true,
|
|
|
|
_ => false,
|
2018-04-30 01:27:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-30 20:22:48 +00:00
|
|
|
#[derive(Clone)]
|
|
|
|
pub(crate) enum FieldTerminator {
|
2020-05-15 16:59:31 +00:00
|
|
|
File,
|
2018-04-30 20:22:48 +00:00
|
|
|
Bytes,
|
|
|
|
Int,
|
|
|
|
Float,
|
|
|
|
Text,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Debug for FieldTerminator {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
match *self {
|
2020-05-15 16:59:31 +00:00
|
|
|
FieldTerminator::File => write!(f, "File"),
|
2018-04-30 20:22:48 +00:00
|
|
|
FieldTerminator::Bytes => write!(f, "Bytes"),
|
|
|
|
FieldTerminator::Int => write!(f, "Int"),
|
|
|
|
FieldTerminator::Float => write!(f, "Float"),
|
|
|
|
FieldTerminator::Text => write!(f, "Text"),
|
2018-04-30 01:27:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-30 20:22:48 +00:00
|
|
|
pub(crate) type MultipartHash = (Vec<NamePart>, MultipartContent);
|
|
|
|
pub(crate) type MultipartForm = Vec<MultipartHash>;
|
2018-04-30 01:27:38 +00:00
|
|
|
|
2020-05-15 16:59:31 +00:00
|
|
|
#[derive(Debug)]
|
2018-04-30 20:22:48 +00:00
|
|
|
pub(crate) enum MultipartContent {
|
2020-05-15 16:59:31 +00:00
|
|
|
File(FileStream),
|
2018-04-30 20:22:48 +00:00
|
|
|
Bytes(Bytes),
|
|
|
|
Text(String),
|
|
|
|
Int(i64),
|
|
|
|
Float(f64),
|
2018-04-30 01:27:38 +00:00
|
|
|
}
|