Skip to content

Commit b04fb94

Browse files
fix(GODT-2218): Fix invalid UID/Seq ID Sequence range
Ensure that sequence set intervals with request interval "N:*" in a mailbox with N-1 messages behaves correctly. Refactor some of the Snapshot to make it easier to test.
1 parent 76e4e7e commit b04fb94

4 files changed

Lines changed: 292 additions & 164 deletions

File tree

benchmarks/gluon_bench/imap_benchmarks/append.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ func (a *Append) Setup(ctx context.Context, addr net.Addr) error {
3939
}
4040

4141
func (a *Append) TearDown(ctx context.Context, addr net.Addr) error {
42-
return a.cleanupWithAddr(addr)
42+
//return a.cleanupWithAddr(addr)
43+
return nil
4344
}
4445

4546
func (a *Append) Run(ctx context.Context, addr net.Addr) error {

internal/state/snapshot.go

Lines changed: 6 additions & 163 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ package state
22

33
import (
44
"context"
5-
"fmt"
6-
"strconv"
75
"strings"
86

97
"github.com/ProtonMail/gluon/imap"
@@ -171,47 +169,7 @@ func (snap *snapshot) resolveSeqInterval(seq *proto.SequenceSet) ([]SeqInterval,
171169
return nil, err
172170
}
173171

174-
res := make([]SeqInterval, 0, len(seqSet))
175-
176-
for _, seqRange := range seqSet {
177-
switch len(seqRange) {
178-
case 1:
179-
seq, err := snap.resolveSeq(seqRange[0])
180-
if err != nil {
181-
return nil, err
182-
}
183-
184-
res = append(res, SeqInterval{
185-
begin: seq,
186-
end: seq,
187-
})
188-
189-
case 2:
190-
begin, err := snap.resolveSeq(seqRange[0])
191-
if err != nil {
192-
return nil, err
193-
}
194-
195-
end, err := snap.resolveSeq(seqRange[1])
196-
if err != nil {
197-
return nil, err
198-
}
199-
200-
if begin > end {
201-
begin, end = end, begin
202-
}
203-
204-
res = append(res, SeqInterval{
205-
begin: begin,
206-
end: end,
207-
})
208-
209-
default:
210-
return nil, fmt.Errorf("bad sequence range")
211-
}
212-
}
213-
214-
return res, nil
172+
return snap.messages.resolveSeqInterval(seqSet)
215173
}
216174

217175
func (snap *snapshot) resolveUIDInterval(seq *proto.SequenceSet) ([]UIDInterval, error) {
@@ -220,104 +178,25 @@ func (snap *snapshot) resolveUIDInterval(seq *proto.SequenceSet) ([]UIDInterval,
220178
return nil, err
221179
}
222180

223-
res := make([]UIDInterval, 0, len(seqSet))
224-
225-
for _, uidRange := range seqSet {
226-
switch len(uidRange) {
227-
case 1:
228-
uid, err := snap.resolveUID(uidRange[0])
229-
if err != nil {
230-
return nil, err
231-
}
232-
233-
res = append(res, UIDInterval{
234-
begin: uid,
235-
end: uid,
236-
})
237-
238-
case 2:
239-
begin, err := snap.resolveUID(uidRange[0])
240-
if err != nil {
241-
return nil, err
242-
}
243-
244-
end, err := snap.resolveUID(uidRange[1])
245-
if err != nil {
246-
return nil, err
247-
}
248-
249-
if begin > end {
250-
begin, end = end, begin
251-
}
252-
253-
res = append(res, UIDInterval{
254-
begin: begin,
255-
end: end,
256-
})
257-
258-
default:
259-
return nil, fmt.Errorf("bad sequence range")
260-
}
261-
}
262-
263-
return res, nil
181+
return snap.messages.resolveUIDInterval(seqSet)
264182
}
265183

266184
func (snap *snapshot) getMessagesInSeqRange(seq *proto.SequenceSet) ([]snapMsgWithSeq, error) {
267-
var res []snapMsgWithSeq
268-
269-
intervals, err := snap.resolveSeqInterval(seq)
185+
seqSet, err := toSeqSet(seq)
270186
if err != nil {
271187
return nil, err
272188
}
273189

274-
for _, seqRange := range intervals {
275-
if seqRange.begin == seqRange.end {
276-
msg, ok := snap.messages.getWithSeqID(seqRange.begin)
277-
if !ok {
278-
return nil, ErrNoSuchMessage
279-
}
280-
281-
res = append(res, msg)
282-
} else {
283-
if !snap.messages.existsWithSeqID(seqRange.begin) || !snap.messages.existsWithSeqID(seqRange.end) {
284-
return nil, ErrNoSuchMessage
285-
}
286-
287-
res = append(res, snap.messages.seqRange(seqRange.begin, seqRange.end)...)
288-
}
289-
}
290-
291-
return res, nil
190+
return snap.messages.getMessagesInSeqRange(seqSet)
292191
}
293192

294193
func (snap *snapshot) getMessagesInUIDRange(seq *proto.SequenceSet) ([]snapMsgWithSeq, error) {
295-
var res []snapMsgWithSeq
296-
297-
// If there are no messages in the mailbox, we still resolve without error.
298-
if snap.messages.len() == 0 {
299-
return nil, nil
300-
}
301-
302-
intervals, err := snap.resolveUIDInterval(seq)
194+
seqSet, err := toSeqSet(seq)
303195
if err != nil {
304196
return nil, err
305197
}
306198

307-
for _, uidRange := range intervals {
308-
if uidRange.begin == uidRange.end {
309-
msg, ok := snap.messages.getWithUID(uidRange.begin)
310-
if !ok {
311-
continue
312-
}
313-
314-
res = append(res, msg)
315-
} else {
316-
res = append(res, snap.messages.uidRange(uidRange.begin, uidRange.end)...)
317-
}
318-
}
319-
320-
return res, nil
199+
return snap.messages.getMessagesInUIDRange(seqSet)
321200
}
322201

323202
func (snap *snapshot) firstMessageWithFlag(flag string) (snapMsgWithSeq, bool) {
@@ -421,39 +300,3 @@ func (snap *snapshot) updateMessageRemoteID(internalID imap.InternalMessageID, r
421300

422301
return nil
423302
}
424-
425-
// resolveSeq converts a textual sequence number into an integer.
426-
// According to RFC 3501, the definition of seq-number, page 89, for message sequence numbers
427-
// - No sequence number is valid if mailbox is empty, not even "*"
428-
// - "*" is converted to the number of messages in the mailbox
429-
// - when used in a range, the order of the indexes in irrelevant.
430-
func (snap *snapshot) resolveSeq(number string) (imap.SeqID, error) {
431-
if number == "*" {
432-
return imap.SeqID(snap.messages.len()), nil
433-
}
434-
435-
num, err := strconv.ParseUint(number, 10, 32)
436-
if err != nil {
437-
return 0, fmt.Errorf("failed to parse sequence number: %w", err)
438-
}
439-
440-
return imap.SeqID(num), nil
441-
}
442-
443-
// resolveUID converts a textual message UID into an integer.
444-
func (snap *snapshot) resolveUID(number string) (imap.UID, error) {
445-
if snap.messages.len() == 0 {
446-
return 0, ErrNoSuchMessage
447-
}
448-
449-
if number == "*" {
450-
return snap.messages.last().UID, nil
451-
}
452-
453-
num, err := strconv.ParseUint(number, 10, 32)
454-
if err != nil {
455-
return 0, fmt.Errorf("failed to parse UID number: %w", err)
456-
}
457-
458-
return imap.UID(num), nil
459-
}

0 commit comments

Comments
 (0)