melib/nntp: limit LIST ACTIVE command length to 512 octets
According to RFC 3977: > Command lines MUST NOT exceed 512 octets, which includes the > terminating CRLF pair Sending a `LIST ACTIVE` command with lots of newgroups and passing the 512 byte limit is therefore invalid. This commit splits the mailboxes in chunks and sends a separate command for each maximal chunk that has a valid length. Fixes #269. Reported-by: r3k2pull/270/head
parent
40d4ecefa0
commit
4e654d2d02
|
@ -731,39 +731,65 @@ impl NntpType {
|
|||
pub async fn nntp_mailboxes(connection: &Arc<FutureMutex<NntpConnection>>) -> Result<()> {
|
||||
let mut res = String::with_capacity(8 * 1024);
|
||||
let mut conn = connection.lock().await;
|
||||
let command = {
|
||||
let mut mailboxes = {
|
||||
let mailboxes_lck = conn.uid_store.mailboxes.lock().await;
|
||||
mailboxes_lck
|
||||
.values()
|
||||
.fold("LIST ACTIVE ".to_string(), |mut acc, x| {
|
||||
if acc.len() != "LIST ACTIVE ".len() {
|
||||
acc.push(',');
|
||||
}
|
||||
acc.push_str(x.name());
|
||||
acc
|
||||
})
|
||||
.map(|m| m.name().to_string())
|
||||
.collect::<SmallVec<[String; 16]>>()
|
||||
};
|
||||
conn.send_command(command.as_bytes()).await?;
|
||||
conn.read_response(&mut res, true, &["215 "])
|
||||
.await
|
||||
.chain_err_summary(|| {
|
||||
format!(
|
||||
"Could not get newsgroups {}: expected LIST ACTIVE response but got: {}",
|
||||
&conn.uid_store.account_name, res
|
||||
)
|
||||
})?;
|
||||
debug!(&res);
|
||||
let mut mailboxes_lck = conn.uid_store.mailboxes.lock().await;
|
||||
for l in res.split_rn().skip(1) {
|
||||
let s = l.split_whitespace().collect::<SmallVec<[&str; 4]>>();
|
||||
if s.len() != 3 {
|
||||
continue;
|
||||
mailboxes.reverse();
|
||||
while !mailboxes.is_empty() {
|
||||
let mut command = "LIST ACTIVE ".to_string();
|
||||
'batch: while let Some(m) = mailboxes.pop() {
|
||||
/* first check if the group name itself is too big for `LIST ACTIVE`. */
|
||||
if "LIST ACTIVE ".len() + m.len() + "\r\n".len() >= 512 {
|
||||
log::warn!(
|
||||
"{}: Newsgroup named {} has a name that exceeds RFC 3977 limits of \
|
||||
maximum command lines (512 octets) with LIST ACTIVE. Skipping it.",
|
||||
&conn.uid_store.account_name,
|
||||
m
|
||||
);
|
||||
continue 'batch;
|
||||
}
|
||||
if command.len() != "LIST ACTIVE ".len() {
|
||||
command.push(',');
|
||||
}
|
||||
// RFC 3977
|
||||
// 3. Basic Concepts
|
||||
// 3.1. Commands and Responses
|
||||
// Command lines MUST NOT exceed 512 octets, which includes the terminating CRLF
|
||||
// pair.
|
||||
if command.len() + m.len() + "\r\n".len() >= 512 {
|
||||
mailboxes.push(m);
|
||||
if command.ends_with(',') {
|
||||
command.pop();
|
||||
}
|
||||
break 'batch;
|
||||
}
|
||||
command.push_str(&m);
|
||||
}
|
||||
conn.send_command(command.as_bytes()).await?;
|
||||
conn.read_response(&mut res, true, &["215 "])
|
||||
.await
|
||||
.chain_err_summary(|| {
|
||||
format!(
|
||||
"Could not get newsgroups {}: expected LIST ACTIVE response but got: {}",
|
||||
&conn.uid_store.account_name, res
|
||||
)
|
||||
})?;
|
||||
let mut mailboxes_lck = conn.uid_store.mailboxes.lock().await;
|
||||
for l in res.split_rn().skip(1) {
|
||||
let s = l.split_whitespace().collect::<SmallVec<[&str; 4]>>();
|
||||
if s.len() != 3 {
|
||||
continue;
|
||||
}
|
||||
let mailbox_hash = MailboxHash(get_path_hash!(&s[0]));
|
||||
mailboxes_lck.entry(mailbox_hash).and_modify(|m| {
|
||||
*m.high_watermark.lock().unwrap() = usize::from_str(s[1]).unwrap_or(0);
|
||||
*m.low_watermark.lock().unwrap() = usize::from_str(s[2]).unwrap_or(0);
|
||||
});
|
||||
}
|
||||
let mailbox_hash = MailboxHash(get_path_hash!(&s[0]));
|
||||
mailboxes_lck.entry(mailbox_hash).and_modify(|m| {
|
||||
*m.high_watermark.lock().unwrap() = usize::from_str(s[1]).unwrap_or(0);
|
||||
*m.low_watermark.lock().unwrap() = usize::from_str(s[2]).unwrap_or(0);
|
||||
});
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue