1
0
mirror of https://github.com/fafhrd91/actix-web synced 2025-08-31 17:07:01 +02:00

multipart: parse and validate Content-Disposition

This commit is contained in:
axon-q
2018-06-06 14:06:01 +00:00
parent 2d0b609c68
commit 936ba2a368
7 changed files with 193 additions and 44 deletions

View File

@@ -8,6 +8,7 @@ use bytes::{Bytes, BytesMut};
use mime::Mime;
use modhttp::header::GetAll;
use modhttp::Error as HttpError;
use percent_encoding;
pub use modhttp::header::*;
@@ -259,3 +260,122 @@ where
}
Ok(())
}
// From hyper v0.11.27 src/header/parsing.rs
/// An extended header parameter value (i.e., tagged with a character set and optionally,
/// a language), as defined in [RFC 5987](https://tools.ietf.org/html/rfc5987#section-3.2).
#[derive(Clone, Debug, PartialEq)]
pub struct ExtendedValue {
/// The character set that is used to encode the `value` to a string.
pub charset: Charset,
/// The human language details of the `value`, if available.
pub language_tag: Option<LanguageTag>,
/// The parameter value, as expressed in octets.
pub value: Vec<u8>,
}
/// Parses extended header parameter values (`ext-value`), as defined in
/// [RFC 5987](https://tools.ietf.org/html/rfc5987#section-3.2).
///
/// Extended values are denoted by parameter names that end with `*`.
///
/// ## ABNF
///
/// ```text
/// ext-value = charset "'" [ language ] "'" value-chars
/// ; like RFC 2231's <extended-initial-value>
/// ; (see [RFC2231], Section 7)
///
/// charset = "UTF-8" / "ISO-8859-1" / mime-charset
///
/// mime-charset = 1*mime-charsetc
/// mime-charsetc = ALPHA / DIGIT
/// / "!" / "#" / "$" / "%" / "&"
/// / "+" / "-" / "^" / "_" / "`"
/// / "{" / "}" / "~"
/// ; as <mime-charset> in Section 2.3 of [RFC2978]
/// ; except that the single quote is not included
/// ; SHOULD be registered in the IANA charset registry
///
/// language = <Language-Tag, defined in [RFC5646], Section 2.1>
///
/// value-chars = *( pct-encoded / attr-char )
///
/// pct-encoded = "%" HEXDIG HEXDIG
/// ; see [RFC3986], Section 2.1
///
/// attr-char = ALPHA / DIGIT
/// / "!" / "#" / "$" / "&" / "+" / "-" / "."
/// / "^" / "_" / "`" / "|" / "~"
/// ; token except ( "*" / "'" / "%" )
/// ```
pub fn parse_extended_value(val: &str) -> Result<ExtendedValue, ::error::ParseError> {
// Break into three pieces separated by the single-quote character
let mut parts = val.splitn(3,'\'');
// Interpret the first piece as a Charset
let charset: Charset = match parts.next() {
None => return Err(::error::ParseError::Header),
Some(n) => FromStr::from_str(n).map_err(|_| ::error::ParseError::Header)?,
};
// Interpret the second piece as a language tag
let lang: Option<LanguageTag> = match parts.next() {
None => return Err(::error::ParseError::Header),
Some("") => None,
Some(s) => match s.parse() {
Ok(lt) => Some(lt),
Err(_) => return Err(::error::ParseError::Header),
}
};
// Interpret the third piece as a sequence of value characters
let value: Vec<u8> = match parts.next() {
None => return Err(::error::ParseError::Header),
Some(v) => percent_encoding::percent_decode(v.as_bytes()).collect(),
};
Ok(ExtendedValue {
charset: charset,
language_tag: lang,
value: value,
})
}
impl fmt::Display for ExtendedValue {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let encoded_value =
percent_encoding::percent_encode(&self.value[..], self::percent_encoding_http::HTTP_VALUE);
if let Some(ref lang) = self.language_tag {
write!(f, "{}'{}'{}", self.charset, lang, encoded_value)
} else {
write!(f, "{}''{}", self.charset, encoded_value)
}
}
}
/// Percent encode a sequence of bytes with a character set defined in
/// [https://tools.ietf.org/html/rfc5987#section-3.2][url]
///
/// [url]: https://tools.ietf.org/html/rfc5987#section-3.2
pub fn http_percent_encode(f: &mut fmt::Formatter, bytes: &[u8]) -> fmt::Result {
let encoded = percent_encoding::percent_encode(bytes, self::percent_encoding_http::HTTP_VALUE);
fmt::Display::fmt(&encoded, f)
}
mod percent_encoding_http {
use percent_encoding;
// internal module because macro is hard-coded to make a public item
// but we don't want to public export this item
define_encode_set! {
// This encode set is used for HTTP header values and is defined at
// https://tools.ietf.org/html/rfc5987#section-3.2
pub HTTP_VALUE = [percent_encoding::SIMPLE_ENCODE_SET] | {
' ', '"', '%', '\'', '(', ')', '*', ',', '/', ':', ';', '<', '-', '>', '?',
'[', '\\', ']', '{', '}'
}
}
}