actix_xml/config.rs
1use std::sync::Arc;
2
3use actix_web::{web, HttpMessage, HttpRequest};
4
5use crate::error::XMLPayloadError;
6
7/// XML extractor configuration
8///
9/// # Example
10///
11/// ```rust
12/// use actix_web::{error, web, App, FromRequest, HttpResponse};
13/// use actix_xml::{Xml, XmlConfig};
14/// use serde::Deserialize;
15///
16/// #[derive(Deserialize)]
17/// struct Info {
18/// username: String,
19/// }
20///
21/// /// deserialize `Info` from request's body, max payload size is 4kb
22/// async fn index(info: Xml<Info>) -> String {
23/// format!("Welcome {}!", info.username)
24/// }
25///
26/// fn main() {
27/// let app = App::new().service(
28/// web::resource("/index.html")
29/// .app_data(
30/// // Json extractor configuration for this resource.
31/// XmlConfig::default()
32/// .limit(4096) // Limit request payload size
33/// .content_type(|mime| { // <- accept text/plain content type
34/// mime.type_() == mime::TEXT && mime.subtype() == mime::PLAIN
35/// })
36/// )
37/// .route(web::post().to(index))
38/// );
39/// }
40/// ```
41///
42#[derive(Clone)]
43pub struct XmlConfig {
44 pub(crate) limit: usize,
45 content_type: Option<Arc<dyn Fn(mime::Mime) -> bool + Send + Sync>>,
46}
47
48const DEFAULT_CONFIG: XmlConfig = XmlConfig {
49 limit: 262_144,
50 content_type: None,
51};
52
53impl Default for XmlConfig {
54 fn default() -> Self {
55 DEFAULT_CONFIG.clone()
56 }
57}
58
59impl XmlConfig {
60 pub fn new() -> Self {
61 Default::default()
62 }
63
64 /// Change max size of payload. By default max size is 256Kb
65 pub fn limit(mut self, limit: usize) -> Self {
66 self.limit = limit;
67 self
68 }
69
70 /// Set predicate for allowed content types
71 pub fn content_type<F>(mut self, predicate: F) -> Self
72 where
73 F: Fn(mime::Mime) -> bool + Send + Sync + 'static,
74 {
75 self.content_type = Some(Arc::new(predicate));
76 self
77 }
78
79 pub(crate) fn check_content_type(&self, req: &HttpRequest) -> Result<(), XMLPayloadError> {
80 // check content-type
81 if let Ok(Some(mime)) = req.mime_type() {
82 if mime == "text/xml"
83 || mime == "application/xml"
84 || self
85 .content_type
86 .as_ref()
87 .map_or(false, |predicate| predicate(mime))
88 {
89 Ok(())
90 } else {
91 Err(XMLPayloadError::ContentType)
92 }
93 } else {
94 Err(XMLPayloadError::ContentType)
95 }
96 }
97
98 /// Extract payload config from app data. Check both `T` and `Data<T>`, in that order, and fall
99 /// back to the default payload config.
100 pub(crate) fn from_req(req: &HttpRequest) -> &Self {
101 req.app_data::<Self>()
102 .or_else(|| req.app_data::<web::Data<Self>>().map(|d| d.as_ref()))
103 .unwrap_or(&DEFAULT_CONFIG)
104 }
105}