Skip to content

Commit c61c648

Browse files
committed
Enhance Options Buffer for >16 Message Unmarshaling
Previously, the connection was being closed due to unmarshaling failures when more than 16 options were included in the message. This fix addresses the issue by increasing the buffer size to accommodate a higher number of options.
1 parent 39a46aa commit c61c648

File tree

2 files changed

+46
-1
lines changed

2 files changed

+46
-1
lines changed

message/pool/message.go

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -523,14 +523,28 @@ func (r *Message) MarshalWithEncoder(encoder Encoder) ([]byte, error) {
523523
return r.bufferMarshal, nil
524524
}
525525

526+
func (r *Message) decode(decoder Decoder) (int, error) {
527+
var n int
528+
var err error
529+
for {
530+
n, err = decoder.Decode(r.bufferUnmarshal, &r.msg)
531+
if errors.Is(err, message.ErrOptionsTooSmall) {
532+
// increase buffer size and try again
533+
r.msg.Options = make(message.Options, 0, len(r.msg.Options)*2)
534+
continue
535+
}
536+
return n, err
537+
}
538+
}
539+
526540
func (r *Message) UnmarshalWithDecoder(decoder Decoder, data []byte) (int, error) {
527541
if len(r.bufferUnmarshal) < len(data) {
528542
r.bufferUnmarshal = append(r.bufferUnmarshal, make([]byte, len(data)-len(r.bufferUnmarshal))...)
529543
}
530544
copy(r.bufferUnmarshal, data)
531545
r.body = nil
532546
r.bufferUnmarshal = r.bufferUnmarshal[:len(data)]
533-
n, err := decoder.Decode(r.bufferUnmarshal, &r.msg)
547+
n, err := r.decode(decoder)
534548
if err != nil {
535549
return n, err
536550
}

message/pool/message_test.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@ import (
44
"bytes"
55
"context"
66
"errors"
7+
"fmt"
78
"strings"
89
"testing"
910

1011
"github.com/plgd-dev/go-coap/v3/message"
1112
"github.com/plgd-dev/go-coap/v3/message/pool"
13+
"github.com/plgd-dev/go-coap/v3/tcp/coder"
1214
"github.com/plgd-dev/go-coap/v3/test/net"
1315
"github.com/stretchr/testify/require"
1416
)
@@ -360,3 +362,32 @@ func TestMessageClone(t *testing.T) {
360362
require.Error(t, err)
361363
require.Contains(t, err.Error(), "read error")
362364
}
365+
366+
func TestUnmarshalMessageWithMultipleOptions(t *testing.T) {
367+
tests := []struct {
368+
numOptions int
369+
}{
370+
{numOptions: 0},
371+
{numOptions: 8},
372+
{numOptions: 16},
373+
{numOptions: 32},
374+
{numOptions: 64},
375+
{numOptions: 1023},
376+
}
377+
378+
for _, tt := range tests {
379+
t.Run(fmt.Sprintf("num-options-%v", tt.numOptions), func(t *testing.T) {
380+
req := pool.NewMessage(context.Background())
381+
for i := 0; i < 64; i++ {
382+
req.AddOptionUint32(message.URIQuery, uint32(i))
383+
}
384+
data, err := req.MarshalWithEncoder(coder.DefaultCoder)
385+
require.NoError(t, err)
386+
msg := pool.NewMessage(context.Background())
387+
n, err := msg.UnmarshalWithDecoder(coder.DefaultCoder, data)
388+
require.NoError(t, err)
389+
require.Equal(t, n, len(data))
390+
require.Equal(t, req.Options(), msg.Options())
391+
})
392+
}
393+
}

0 commit comments

Comments
 (0)