Skip to content

Commit

Permalink
fix: Assume file extensions are 32 chars max and don't contain whites…
Browse files Browse the repository at this point in the history
…pace (#5338)

Before file extensions were also limited to 32 chars, but extra chars in the beginning were just cut
off, e.g. "file.with_lots_of_characters_behind_point_and_double_ending.tar.gz" was considered to
have an extension "d_point_and_double_ending.tar.gz". Better to take only "tar.gz" then.

Also don't include whitespace-containing parts in extensions. File extensions generally don't
contain whitespaces.
  • Loading branch information
iequidoo committed Apr 27, 2024
1 parent 204f747 commit 562c4f8
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 30 deletions.
29 changes: 16 additions & 13 deletions src/blob.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,41 +232,44 @@ impl<'a> BlobObject<'a> {

/// Get a file extension if any, including the dot, in lower case, otherwise an empty string.
fn get_extension(name: &str) -> String {
let mut name = name.to_string();
let mut name = name;
for part in name.rsplit('/') {
if !part.is_empty() {
name = part.to_string();
name = part;
break;
}
}
for part in name.rsplit('\\') {
if !part.is_empty() {
name = part.to_string();
name = part;
break;
}
}

// Let's take the tricky filename
// "file.with_lots_of_characters_behind_point_and_double_ending.tar.gz" as an example.
// Split it into "file" and "with_lots_of_characters_behind_point_and_double_ending.tar.gz":
let mut iter = name.splitn(2, '.');
iter.next();

let ext_chars = iter.next().unwrap_or_default().chars();
let ext: String = ext_chars
// Assume that the extension is 32 chars maximum.
let ext: String = name
.chars()
.rev()
.take(32)
.take_while(|c| !c.is_whitespace())
.take(33)
.collect::<Vec<_>>()
.iter()
.rev()
.collect();
// ext == "d_point_and_double_ending.tar.gz"
// ext == "nd_point_and_double_ending.tar.gz"

// Split it into "nd_point_and_double_ending" and "tar.gz":
let mut iter = ext.splitn(2, '.');
iter.next();

let ext = iter.next().unwrap_or_default();
if ext.is_empty() {
ext
String::new()
} else {
format!(".{ext}").to_lowercase()
// Return ".d_point_and_double_ending.tar.gz", which is not perfect but acceptable.
// Return ".tar.gz".
}
}

Expand Down
52 changes: 35 additions & 17 deletions src/receive_imf/tests.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::time::Duration;

use regex::Regex;
use tokio::fs;

use super::*;
Expand Down Expand Up @@ -2960,20 +2961,27 @@ Reply from different address
}

#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_long_and_duplicated_filenames() -> Result<()> {
async fn test_weird_and_duplicated_filenames() -> Result<()> {
let mut tcm = TestContextManager::new();
let alice = tcm.alice().await;
let bob = tcm.bob().await;

for filename_sent in &[
"foo.bar very long file name test baz.tar.gz",
"foobarabababababababbababababverylongfilenametestbaz.tar.gz",
"fooo...tar.gz",
"foo. .tar.gz",
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.tar.gz",
"a.tar.gz",
"a.tar.gz",
"a.a..a.a.a.a.tar.gz",
for (filename_sent, expected_ext) in &[
("foo.bar very long file name test baz.tar.gz", "tar.gz"),
(
"foo.barabababababababbababababverylongfilenametestbaz.tar.gz",
"tar.gz",
),
("fooo...tar.gz", "..tar.gz"),
("foo. .tar.gz", "tar.gz"),
(
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.tar.gz",
"tar.gz",
),
("a.tar.gz", "tar.gz"),
("a.tar.gz", "tar.gz"),
("a.a..a.a.a.a.tar.gz", "a..a.a.a.a.tar.gz"),
("a. tar.tar.gz", "tar.gz"),
] {
let attachment = alice.blobdir.join(filename_sent);
let content = format!("File content of {filename_sent}");
Expand All @@ -2987,23 +2995,33 @@ async fn test_long_and_duplicated_filenames() -> Result<()> {

let msg_bob = bob.recv_msg(&sent).await;

async fn check_message(msg: &Message, t: &TestContext, filename: &str, content: &str) {
async fn check_message(
msg: &Message,
t: &TestContext,
filename: &str,
expected_ext: &str,
content: &str,
) {
assert_eq!(msg.get_viewtype(), Viewtype::File);
let resulting_filename = msg.get_filename().unwrap();
assert_eq!(resulting_filename, filename);
let path = msg.get_file(t).unwrap();
if !msg.get_state().is_outgoing() {
let re =
Regex::new(&("^[[:xdigit:]]{16}.".to_string() + expected_ext + "$")).unwrap();
assert!(
re.is_match(path.file_name().unwrap().to_str().unwrap()),
"invalid path {path:?}"
);
}
let path2 = path.with_file_name("saved.txt");
msg.save_file(t, &path2).await.unwrap();
assert!(
path.to_str().unwrap().ends_with(".tar.gz"),
"path {path:?} doesn't end with .tar.gz"
);
assert_eq!(fs::read_to_string(&path).await.unwrap(), content);
assert_eq!(fs::read_to_string(&path2).await.unwrap(), content);
fs::remove_file(path2).await.unwrap();
}
check_message(&msg_alice, &alice, filename_sent, &content).await;
check_message(&msg_bob, &bob, filename_sent, &content).await;
check_message(&msg_alice, &alice, filename_sent, expected_ext, &content).await;
check_message(&msg_bob, &bob, filename_sent, expected_ext, &content).await;
}

Ok(())
Expand Down

0 comments on commit 562c4f8

Please sign in to comment.