Content-Disposition header is required in multipart

This commit is contained in:
Craig Pastro 2021-03-19 11:01:48 +09:00
parent b75b5114c3
commit 51b705a629
3 changed files with 29 additions and 9 deletions

View File

@ -72,7 +72,7 @@ impl<'a> From<&'a str> for DispositionType {
#[derive(Clone, Debug, PartialEq)]
#[allow(clippy::large_enum_variant)]
pub enum DispositionParam {
/// For [`DispositionType::FormData`] (i.e. *multipart/form-data*), the name of an field from
/// For [`DispositionType::FormData`] (i.e. *multipart/form-data*), the name of a field from
/// the form.
Name(String),
/// A plain file name.

View File

@ -10,6 +10,9 @@ pub enum MultipartError {
/// Content-Type header is not found
#[display(fmt = "No Content-type header found")]
NoContentType,
/// Content-Disposition header satisfying RFC7578 is not found (see https://tools.ietf.org/html/rfc7578#section-4.2)
#[display(fmt = "No content-disposition header satisfying RFC7578 found")]
NoContentDisposition,
/// Can not parse Content-Type header
#[display(fmt = "Can not parse Content-Type header")]
ParseContentType,

View File

@ -13,7 +13,10 @@ use futures_util::stream::{LocalBoxStream, Stream, StreamExt};
use actix_utils::task::LocalWaker;
use actix_web::error::{ParseError, PayloadError};
use actix_web::http::header::{self, ContentDisposition, HeaderMap, HeaderName, HeaderValue};
use actix_web::http::header::{
self, ContentDisposition, DispositionParam, DispositionType, HeaderMap, HeaderName,
HeaderValue,
};
use crate::error::MultipartError;
@ -402,14 +405,28 @@ impl Field {
}
/// Get the content disposition of the field, if it exists
pub fn content_disposition(&self) -> Option<ContentDisposition> {
pub fn content_disposition(&self) -> Result<ContentDisposition, MultipartError> {
// RFC 7578: 'Each part MUST contain a Content-Disposition header field
// where the disposition type is "form-data".'
if let Some(content_disposition) = self.headers.get(&header::CONTENT_DISPOSITION) {
ContentDisposition::from_raw(content_disposition).ok()
} else {
None
}
// where the disposition type is "form-data". The Content-Disposition
// header field MUST also contain an additional parameter of "name"; the
// value of the "name" parameter is the original field name from the
// form.
self.headers
.get(&header::CONTENT_DISPOSITION)
.and_then(|content_disposition| {
ContentDisposition::from_raw(content_disposition).ok()
})
.filter(|content_disposition| {
content_disposition.disposition == DispositionType::FormData
&& content_disposition
.parameters
.iter()
.any(|param| match param {
DispositionParam::Name(_) => true,
_ => false,
})
})
.ok_or(MultipartError::NoContentDisposition)
}
}