multer/
constraints.rs

1use crate::size_limit::SizeLimit;
2
3/// Represents some rules to be applied on the stream and field's content size
4/// to prevent DoS attacks.
5///
6/// It's recommended to add some rules on field (specially text field) size to
7/// avoid potential DoS attacks from attackers running the server out of memory.
8/// This type provides some API to apply constraints on very granular level to
9/// make `multipart/form-data` safe. By default, it does not apply any
10/// constraint.
11///
12/// # Examples
13///
14/// ```
15/// use multer::{Multipart, Constraints, SizeLimit};
16/// # use bytes::Bytes;
17/// # use std::convert::Infallible;
18/// # use futures_util::stream::once;
19///
20/// # async fn run() {
21/// # let data = "--X-BOUNDARY\r\nContent-Disposition: form-data; name=\"my_text_field\"\r\n\r\nabcd\r\n--X-BOUNDARY--\r\n";
22/// # let some_stream = once(async move { Result::<Bytes, Infallible>::Ok(Bytes::from(data)) });
23/// // Create some constraints to be applied to the fields to prevent DoS attack.
24/// let constraints = Constraints::new()
25///      // We only accept `my_text_field` and `my_file_field` fields,
26///      // For any unknown field, we will throw an error.
27///      .allowed_fields(vec!["my_text_field", "my_file_field"])
28///      .size_limit(
29///          SizeLimit::new()
30///              // Set 15mb as size limit for the whole stream body.
31///              .whole_stream(15 * 1024 * 1024)
32///              // Set 10mb as size limit for all fields.
33///              .per_field(10 * 1024 * 1024)
34///              // Set 30kb as size limit for our text field only.
35///              .for_field("my_text_field", 30 * 1024),
36///      );
37///
38/// // Create a `Multipart` instance from a stream and the constraints.
39/// let mut multipart = Multipart::with_constraints(some_stream, "X-BOUNDARY", constraints);
40///
41/// while let Some(field) = multipart.next_field().await.unwrap() {
42///     let content = field.text().await.unwrap();
43///     assert_eq!(content, "abcd");
44/// }
45/// # }
46/// # tokio::runtime::Runtime::new().unwrap().block_on(run());
47/// ```
48#[derive(Debug, Default)]
49pub struct Constraints {
50    pub(crate) size_limit: SizeLimit,
51    pub(crate) allowed_fields: Option<Vec<String>>,
52}
53
54impl Constraints {
55    /// Creates a set of rules with default behaviour.
56    pub fn new() -> Constraints {
57        Constraints::default()
58    }
59
60    /// Applies rules on field's content length.
61    pub fn size_limit(self, size_limit: SizeLimit) -> Constraints {
62        Constraints {
63            size_limit,
64            allowed_fields: self.allowed_fields,
65        }
66    }
67
68    /// Specify which fields should be allowed, for any unknown field, the
69    /// [`next_field`](crate::Multipart::next_field) will throw an error.
70    pub fn allowed_fields<N: Into<String>>(self, allowed_fields: Vec<N>) -> Constraints {
71        let allowed_fields = allowed_fields.into_iter().map(|item| item.into()).collect();
72
73        Constraints {
74            size_limit: self.size_limit,
75            allowed_fields: Some(allowed_fields),
76        }
77    }
78
79    pub(crate) fn is_it_allowed(&self, field: Option<&str>) -> bool {
80        if let Some(ref allowed_fields) = self.allowed_fields {
81            field
82                .map(|field| allowed_fields.iter().any(|item| item == field))
83                .unwrap_or(false)
84        } else {
85            true
86        }
87    }
88}