Skip to content

Commit

Permalink
Support unquoted 'name' and 'filename'.
Browse files Browse the repository at this point in the history
Add support for unquoted names and filenames, for compatibility with
older clients that may not quote them.

Resolves #41.
  • Loading branch information
Pomes, Matthew authored and SergioBenitez committed Jul 12, 2022
1 parent fcae488 commit 677ce5c
Showing 1 changed file with 32 additions and 4 deletions.
36 changes: 32 additions & 4 deletions src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,15 @@ pub(crate) enum ContentDispositionAttr {
}

impl ContentDispositionAttr {
/// Extract ContentDisposition Attribute from header.
///
/// Some older clients may not quote the name or filename, so we allow them,
/// but require them to be percent encoded. Only allocates if percent
/// decoding, and there are characters that need to be decoded.
pub fn extract_from<'h>(&self, header: &'h [u8]) -> Option<&'h [u8]> {
let prefix = match self {
ContentDispositionAttr::Name => &b"name=\""[..],
ContentDispositionAttr::FileName => &b"filename=\""[..],
ContentDispositionAttr::Name => &b"name="[..],
ContentDispositionAttr::FileName => &b"filename="[..],
};

if let Some(i) = memchr::memmem::find(header, prefix) {
Expand All @@ -28,10 +33,18 @@ impl ContentDispositionAttr {
return None;
}

// Find the end of attribute.
let rest = &header[(i + prefix.len())..];
if let Some(j) = memchr::memmem::find(rest, b"\"") {
return Some(&rest[..j]);
let j = memchr::memchr(b';', rest).unwrap_or(rest.len());

// Handle quoted strings.
let content = &rest[..j];
if content.starts_with(b"\"") {
let k = memchr::memchr(b'"', &content[1..])?;
return Some(&content[1..(k + 1)]);
}

return Some(content);
}

None
Expand Down Expand Up @@ -88,4 +101,19 @@ mod tests {
assert_eq!(filename.unwrap(), "কখগ-你好.txt".as_bytes());
assert!(name.is_none());
}

#[test]
fn test_content_disposition_name_unquoted() {
let val = br#"form-data; name=my_field"#;
let name = ContentDispositionAttr::Name.extract_from(val);
let filename = ContentDispositionAttr::FileName.extract_from(val);
assert_eq!(name.unwrap(), b"my_field");
assert!(filename.is_none());

let val = br#"form-data; name=my_field; filename=file-name.txt"#;
let name = ContentDispositionAttr::Name.extract_from(val);
let filename = ContentDispositionAttr::FileName.extract_from(val);
assert_eq!(name.unwrap(), b"my_field");
assert_eq!(filename.unwrap(), b"file-name.txt");
}
}

0 comments on commit 677ce5c

Please sign in to comment.