Skip to content

Commit 49c300d

Browse files
committed
test: Check headers absense straightforwardly
In the `test` cfg, introduce `MimeMessage::headers_removed` hash set and `header_exists()` function returning whether the header exists in any part of the parsed message. `get_header()` shouldn't be used in tests for checking absense of headers because it returns `None` for removed ("ignored") headers.
1 parent 0e3277b commit 49c300d

File tree

4 files changed

+61
-25
lines changed

4 files changed

+61
-25
lines changed

src/chat/chat_tests.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2553,10 +2553,8 @@ async fn test_broadcast() -> Result<()> {
25532553
let sent_msg = alice.pop_sent_msg().await;
25542554
let msg = bob.parse_msg(&sent_msg).await;
25552555
assert!(msg.was_encrypted());
2556-
assert!(msg
2557-
.get_header(HeaderDef::ChatGroupMemberTimestamps)
2558-
.is_none());
2559-
assert!(msg.get_header(HeaderDef::AutocryptGossip).is_none());
2556+
assert!(!msg.header_exists(HeaderDef::ChatGroupMemberTimestamps));
2557+
assert!(!msg.header_exists(HeaderDef::AutocryptGossip));
25602558
let msg = bob.recv_msg(&sent_msg).await;
25612559
assert_eq!(msg.get_text(), "ola!");
25622560
assert_eq!(msg.subject, "Broadcast list");

src/mimefactory/mimefactory_tests.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -893,10 +893,7 @@ async fn test_dont_remove_self() -> Result<()> {
893893
let mime_message = MimeMessage::from_bytes(alice, sent.payload.as_bytes(), None)
894894
.await
895895
.unwrap();
896-
assert_eq!(
897-
mime_message.get_header(HeaderDef::ChatGroupPastMembers),
898-
None
899-
);
896+
assert!(!mime_message.header_exists(HeaderDef::ChatGroupPastMembers));
900897
assert_eq!(
901898
mime_message.chat_group_member_timestamps().unwrap().len(),
902899
1 // There is a timestamp for Bob, not for Alice

src/mimeparser.rs

Lines changed: 54 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ pub(crate) struct MimeMessage {
5757
/// Message headers.
5858
headers: HashMap<String, String>,
5959

60+
#[cfg(test)]
61+
/// Names of removed (ignored) headers. Used by `header_exists()` needed for tests.
62+
headers_removed: HashSet<String>,
63+
6064
/// List of addresses from the `To` and `Cc` headers.
6165
///
6266
/// Addresses are normalized and lowercase.
@@ -236,6 +240,7 @@ impl MimeMessage {
236240
let mut hop_info = parse_receive_headers(&mail.get_headers());
237241

238242
let mut headers = Default::default();
243+
let mut headers_removed = HashSet::<String>::new();
239244
let mut recipients = Default::default();
240245
let mut past_members = Default::default();
241246
let mut from = Default::default();
@@ -253,7 +258,12 @@ impl MimeMessage {
253258
&mut chat_disposition_notification_to,
254259
&mail.headers,
255260
);
256-
headers.retain(|k, _| !is_hidden(k));
261+
headers.retain(|k, _| {
262+
!is_hidden(k) || {
263+
headers_removed.insert(k.clone());
264+
false
265+
}
266+
});
257267

258268
// Parse hidden headers.
259269
let mimetype = mail.ctype.mimetype.parse::<Mime>()?;
@@ -298,9 +308,11 @@ impl MimeMessage {
298308
// Overwrite Message-ID with X-Microsoft-Original-Message-ID.
299309
// However if we later find Message-ID in the protected part,
300310
// it will overwrite both.
301-
if let Some(microsoft_message_id) =
302-
headers.remove(HeaderDef::XMicrosoftOriginalMessageId.get_headername())
303-
{
311+
if let Some(microsoft_message_id) = remove_header(
312+
&mut headers,
313+
HeaderDef::XMicrosoftOriginalMessageId.get_headername(),
314+
&mut headers_removed,
315+
) {
304316
headers.insert(
305317
HeaderDef::MessageId.get_headername().to_string(),
306318
microsoft_message_id,
@@ -309,7 +321,7 @@ impl MimeMessage {
309321

310322
// Remove headers that are allowed _only_ in the encrypted+signed part. It's ok to leave
311323
// them in signed-only emails, but has no value currently.
312-
Self::remove_secured_headers(&mut headers);
324+
Self::remove_secured_headers(&mut headers, &mut headers_removed);
313325

314326
let mut from = from.context("No from in message")?;
315327
let private_keyring = load_self_secret_keyring(context).await?;
@@ -442,7 +454,7 @@ impl MimeMessage {
442454
HeaderDef::ChatEdit,
443455
HeaderDef::ChatUserAvatar,
444456
] {
445-
headers.remove(h.get_headername());
457+
remove_header(&mut headers, h.get_headername(), &mut headers_removed);
446458
}
447459
}
448460

@@ -506,7 +518,7 @@ impl MimeMessage {
506518
}
507519
}
508520
if signatures.is_empty() {
509-
Self::remove_secured_headers(&mut headers);
521+
Self::remove_secured_headers(&mut headers, &mut headers_removed);
510522

511523
// If it is not a read receipt, degrade encryption.
512524
if let (Some(peerstate), Ok(mail)) = (&mut peerstate, mail) {
@@ -530,6 +542,9 @@ impl MimeMessage {
530542
let mut parser = MimeMessage {
531543
parts: Vec::new(),
532544
headers,
545+
#[cfg(test)]
546+
headers_removed,
547+
533548
recipients,
534549
past_members,
535550
list_post,
@@ -931,6 +946,16 @@ impl MimeMessage {
931946
.map(|s| s.as_str())
932947
}
933948

949+
#[cfg(test)]
950+
/// Returns whether the header exists in any part of the parsed message.
951+
///
952+
/// Use this to check for header absense. Header presense should be checked using
953+
/// `get_header(...).is_some()` as it also checks that the header isn't ignored.
954+
pub(crate) fn header_exists(&self, headerdef: HeaderDef) -> bool {
955+
let hname = headerdef.get_headername();
956+
self.headers.contains_key(hname) || self.headers_removed.contains(hname)
957+
}
958+
934959
/// Returns `Chat-Group-ID` header value if it is a valid group ID.
935960
pub fn get_chat_group_id(&self) -> Option<&str> {
936961
self.get_header(HeaderDef::ChatGroupId)
@@ -1526,14 +1551,17 @@ impl MimeMessage {
15261551
.and_then(|msgid| parse_message_id(msgid).ok())
15271552
}
15281553

1529-
fn remove_secured_headers(headers: &mut HashMap<String, String>) {
1530-
headers.remove("secure-join-fingerprint");
1531-
headers.remove("secure-join-auth");
1532-
headers.remove("chat-verified");
1533-
headers.remove("autocrypt-gossip");
1554+
fn remove_secured_headers(
1555+
headers: &mut HashMap<String, String>,
1556+
removed: &mut HashSet<String>,
1557+
) {
1558+
remove_header(headers, "secure-join-fingerprint", removed);
1559+
remove_header(headers, "secure-join-auth", removed);
1560+
remove_header(headers, "chat-verified", removed);
1561+
remove_header(headers, "autocrypt-gossip", removed);
15341562

15351563
// Secure-Join is secured unless it is an initial "vc-request"/"vg-request".
1536-
if let Some(secure_join) = headers.remove("secure-join") {
1564+
if let Some(secure_join) = remove_header(headers, "secure-join", removed) {
15371565
if secure_join == "vc-request" || secure_join == "vg-request" {
15381566
headers.insert("secure-join".to_string(), secure_join);
15391567
}
@@ -1861,6 +1889,19 @@ impl MimeMessage {
18611889
}
18621890
}
18631891

1892+
fn remove_header(
1893+
headers: &mut HashMap<String, String>,
1894+
key: &str,
1895+
removed: &mut HashSet<String>,
1896+
) -> Option<String> {
1897+
if let Some((k, v)) = headers.remove_entry(key) {
1898+
removed.insert(k);
1899+
Some(v)
1900+
} else {
1901+
None
1902+
}
1903+
}
1904+
18641905
/// Parses `Autocrypt-Gossip` headers from the email and applies them to peerstates.
18651906
/// Params:
18661907
/// from: The address which sent the message currently being parsed

src/securejoin/securejoin_tests.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ async fn test_setup_contact_ex(case: SetupContactCase) {
120120
assert!(!msg.was_encrypted());
121121
assert_eq!(msg.get_header(HeaderDef::SecureJoin).unwrap(), "vc-request");
122122
assert!(msg.get_header(HeaderDef::SecureJoinInvitenumber).is_some());
123-
assert!(msg.get_header(HeaderDef::AutoSubmitted).is_none());
123+
assert!(!msg.header_exists(HeaderDef::AutoSubmitted));
124124

125125
// Step 3: Alice receives vc-request, sends vc-auth-required
126126
alice.recv_msg_trash(&sent).await;
@@ -523,15 +523,15 @@ async fn test_secure_join() -> Result<()> {
523523
assert!(!msg.was_encrypted());
524524
assert_eq!(msg.get_header(HeaderDef::SecureJoin).unwrap(), "vg-request");
525525
assert!(msg.get_header(HeaderDef::SecureJoinInvitenumber).is_some());
526-
assert!(msg.get_header(HeaderDef::AutoSubmitted).is_none());
526+
assert!(!msg.header_exists(HeaderDef::AutoSubmitted));
527527

528528
// Old Delta Chat core sent `Secure-Join-Group` header in `vg-request`,
529529
// but it was only used by Alice in `vg-request-with-auth`.
530530
// New Delta Chat versions do not use `Secure-Join-Group` header at all
531531
// and it is deprecated.
532532
// Now `Secure-Join-Group` header
533533
// is only sent in `vg-request-with-auth` for compatibility.
534-
assert!(msg.get_header(HeaderDef::SecureJoinGroup).is_none());
534+
assert!(!msg.header_exists(HeaderDef::SecureJoinGroup));
535535

536536
// Step 3: Alice receives vg-request, sends vg-auth-required
537537
alice.recv_msg_trash(&sent).await;
@@ -606,7 +606,7 @@ async fn test_secure_join() -> Result<()> {
606606
// Formally this message is auto-submitted, but as the member addition is a result of an
607607
// explicit user action, the Auto-Submitted header shouldn't be present. Otherwise it would
608608
// be strange to have it in "member-added" messages of verified groups only.
609-
assert!(msg.get_header(HeaderDef::AutoSubmitted).is_none());
609+
assert!(!msg.header_exists(HeaderDef::AutoSubmitted));
610610
// This is a two-member group, but Alice must Autocrypt-gossip to her other devices.
611611
assert!(msg.get_header(HeaderDef::AutocryptGossip).is_some());
612612

0 commit comments

Comments
 (0)