Fix IMAP: Pipelined STORE and EXPUNGE can execute out of order

This commit is contained in:
Maurus Decimus
2026-07-19 16:02:20 +02:00
parent f967132971
commit 2c04d4473c
3 changed files with 18 additions and 4 deletions

View File

@@ -30,11 +30,14 @@ impl<T: SessionStream> Session<T> {
let mut bytes = bytes.iter();
let mut requests = Vec::with_capacity(2);
let mut needs_literal = None;
let mut has_expunge = false;
loop {
match self.receiver.parse(&mut bytes) {
Ok(request) => match self.is_allowed(request).await {
Ok(request) => {
has_expunge |=
matches!(request.command, Command::Expunge(_) | Command::Close);
requests.push(request);
}
Err(err) => {
@@ -140,7 +143,7 @@ impl<T: SessionStream> Session<T> {
.await
.map(|_| SessionResult::Continue),
Command::Store(is_uid) => self
.handle_store(request, is_uid)
.handle_store(request, is_uid, !has_expunge)
.await
.map(|_| SessionResult::Continue),
Command::Copy(is_uid) => self

View File

@@ -43,6 +43,7 @@ impl<T: SessionStream> Session<T> {
&mut self,
request: Request<Command>,
is_uid: bool,
spawn: bool,
) -> trc::Result<()> {
// Validate access
self.assert_has_permission(Permission::ImapStore)?;
@@ -52,13 +53,21 @@ impl<T: SessionStream> Session<T> {
let (data, mailbox) = self.state.select_data();
let is_condstore = self.is_condstore || mailbox.is_condstore;
spawn_op!(data, {
if spawn {
spawn_op!(data, {
let response = data
.store(arguments, mailbox, is_uid, is_condstore, op_start)
.await?;
data.write_bytes(response).await
})
} else {
let response = data
.store(arguments, mailbox, is_uid, is_condstore, op_start)
.await?;
data.write_bytes(response).await
})
}
}
}