implement IMAP extension COMPRESS=DEFLATE, rfc 4978

to compress the entire IMAP connection. tested with thunderbird, meli, k9, ios
mail. the initial implementation had interoperability issues with some of these
clients: if they write the deflate stream and flush in "partial mode", the go
stdlib flate reader does not return any data (until there is an explicit
zero-length "sync flush" block, or until the history/sliding window is full),
blocking progress, resulting in clients closing the seemingly stuck connection
after considering the connection timed out. this includes a coy of the flate
package with a new reader that returns partially flushed blocks earlier.

this also adds imap trace logging to imapclient.Conn, which was useful for
debugging.
This commit is contained in:
Mechiel Lukkien
2025-02-20 19:33:09 +01:00
parent 3f6c45a41f
commit f40f94670e
25 changed files with 3623 additions and 69 deletions

View File

@ -1,6 +1,8 @@
package imapserver
import (
"bufio"
"io"
"net"
)
@ -26,3 +28,18 @@ func (c *prefixConn) Read(buf []byte) (int, error) {
}
return c.Conn.Read(buf)
}
// xprefixConn returns either the original net.Conn passed as parameter, or returns
// a *prefixConn returning the buffered data available in br followed data from the
// net.Conn passed in.
func xprefixConn(c net.Conn, br *bufio.Reader) net.Conn {
n := br.Buffered()
if n == 0 {
return c
}
buf := make([]byte, n)
_, err := io.ReadFull(c, buf)
xcheckf(err, "get buffered data")
return &prefixConn{buf, c}
}