mirror of https://github.com/fafhrd91/actix-web
perf(files): drop some needless allocations (#4042)
This commit is contained in:
parent
0a0b193c01
commit
da2d74ec28
|
|
@ -117,14 +117,35 @@ pub(crate) fn get_content_type_and_disposition(
|
||||||
};
|
};
|
||||||
|
|
||||||
// replace special characters in filenames which could occur on some filesystems
|
// replace special characters in filenames which could occur on some filesystems
|
||||||
let filename_s = filename
|
let mut escaped_len = filename.len();
|
||||||
.replace('\n', "%0A") // \n line break
|
for byte in filename.bytes() {
|
||||||
.replace('\x0B', "%0B") // \v vertical tab
|
if matches!(byte, b'\n' | b'\x0B' | b'\x0C' | b'\r') {
|
||||||
.replace('\x0C', "%0C") // \f form feed
|
escaped_len += 2;
|
||||||
.replace('\r', "%0D"); // \r carriage return
|
}
|
||||||
let mut parameters = vec![DispositionParam::Filename(filename_s)];
|
}
|
||||||
|
|
||||||
if !filename.is_ascii() {
|
let filename_s = if escaped_len == filename.len() {
|
||||||
|
filename.to_string()
|
||||||
|
} else {
|
||||||
|
let mut escaped = String::with_capacity(escaped_len);
|
||||||
|
for ch in filename.chars() {
|
||||||
|
match ch {
|
||||||
|
'\n' => escaped.push_str("%0A"), // \n line break
|
||||||
|
'\x0B' => escaped.push_str("%0B"), // \v vertical tab
|
||||||
|
'\x0C' => escaped.push_str("%0C"), // \f form feed
|
||||||
|
'\r' => escaped.push_str("%0D"), // \r carriage return
|
||||||
|
ch => escaped.push(ch),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
escaped
|
||||||
|
};
|
||||||
|
|
||||||
|
let is_ascii = filename.is_ascii();
|
||||||
|
|
||||||
|
let mut parameters = Vec::with_capacity(if is_ascii { 1 } else { 2 });
|
||||||
|
parameters.push(DispositionParam::Filename(filename_s));
|
||||||
|
|
||||||
|
if !is_ascii {
|
||||||
parameters.push(DispositionParam::FilenameExt(ExtendedValue {
|
parameters.push(DispositionParam::FilenameExt(ExtendedValue {
|
||||||
charset: Charset::Ext(String::from("UTF-8")),
|
charset: Charset::Ext(String::from("UTF-8")),
|
||||||
language_tag: None,
|
language_tag: None,
|
||||||
|
|
@ -735,4 +756,15 @@ mod tests {
|
||||||
let (_ct, cd) = get_content_type_and_disposition(Path::new("sound.mp3")).unwrap();
|
let (_ct, cd) = get_content_type_and_disposition(Path::new("sound.mp3")).unwrap();
|
||||||
assert_eq!(cd.disposition, DispositionType::Inline);
|
assert_eq!(cd.disposition, DispositionType::Inline);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn special_chars_are_escaped_in_content_disposition_filename() {
|
||||||
|
let (_ct, cd) =
|
||||||
|
get_content_type_and_disposition(Path::new("test\n\x0B\x0C\rnewline.text")).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
cd.to_string(),
|
||||||
|
"inline; filename=\"test%0A%0B%0C%0Dnewline.text\"",
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
use std::{
|
use std::{
|
||||||
|
borrow::Cow,
|
||||||
path::{Component, Path, PathBuf},
|
path::{Component, Path, PathBuf},
|
||||||
str::FromStr,
|
str::FromStr,
|
||||||
};
|
};
|
||||||
|
|
@ -70,8 +71,10 @@ impl PathBufWrap {
|
||||||
.map_err(|_| UriSegmentError::NotValidUtf8)?;
|
.map_err(|_| UriSegmentError::NotValidUtf8)?;
|
||||||
|
|
||||||
// disallow decoding `%2F` into `/`
|
// disallow decoding `%2F` into `/`
|
||||||
if segment_count != path.matches('/').count() + 1 {
|
if let Cow::Owned(ref path) = path {
|
||||||
return Err(UriSegmentError::BadChar('/'));
|
if segment_count != path.matches('/').count() + 1 {
|
||||||
|
return Err(UriSegmentError::BadChar('/'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for segment in path.split('/') {
|
for segment in path.split('/') {
|
||||||
|
|
@ -199,6 +202,14 @@ mod tests {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn encoded_slash_is_rejected() {
|
||||||
|
assert_eq!(
|
||||||
|
PathBufWrap::parse_path("/test%2Ffile.txt", false),
|
||||||
|
Err(UriSegmentError::BadChar('/'))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg_attr(windows, should_panic)]
|
#[cfg_attr(windows, should_panic)]
|
||||||
fn windows_drive_traversal() {
|
fn windows_drive_traversal() {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue