From e30a74532e6ada47db5f0759fb4214eb6c7a2beb Mon Sep 17 00:00:00 2001 From: Ivan Kozlovic Date: Thu, 7 Oct 2021 11:56:25 -0600 Subject: [PATCH] [FIXED] JetStream: queue name cannot contain "." when used as durable When calling `js.QueueSubscribe[Sync](subject, queue_name)`, if no durable name is provided, the queue name is used as the durable name, so the same restriction applies Resolves #840 Signed-off-by: Ivan Kozlovic --- js.go | 21 ++++++++++++++++++--- jsm.go | 4 ++-- test/js_test.go | 7 +++++++ 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/js.go b/js.go index d020285e7..d3f5dc9d0 100644 --- a/js.go +++ b/js.go @@ -169,6 +169,7 @@ type JetStream interface { // QueueSubscribe creates a Subscription with a queue group. // If no optional durable name nor binding options are specified, the queue name will be used as a durable name. + // In that case, the queue name cannot contain dots ".", same restriction that is applied to a durable name. // See important note in Subscribe() QueueSubscribe(subj, queue string, cb MsgHandler, opts ...SubOpt) (*Subscription, error) @@ -1168,7 +1169,10 @@ func (js *js) subscribe(subj, queue string, cb MsgHandler, ch chan *Msg, isSync, // If this is a queue subscription and no consumer nor durable name was specified, // then we will use the queue name as a durable name. - if queue != _EMPTY_ && o.consumer == _EMPTY_ && o.cfg.Durable == _EMPTY_ { + if o.consumer == _EMPTY_ && o.cfg.Durable == _EMPTY_ { + if err := checkDurName(queue); err != nil { + return nil, err + } o.cfg.Durable = queue } } @@ -1890,7 +1894,18 @@ func Description(description string) SubOpt { }) } +// Check that the durable name is valid, that is, that it does not contain +// any ".", and if it does return ErrInvalidDurableName, otherwise nil. +func checkDurName(dur string) error { + if strings.Contains(dur, ".") { + return ErrInvalidDurableName + } + return nil +} + // Durable defines the consumer name for JetStream durable subscribers. +// This function will return ErrInvalidDurableName in the name contains +// any dot ".". func Durable(consumer string) SubOpt { return subOptFn(func(opts *subOpts) error { if opts.cfg.Durable != _EMPTY_ { @@ -1899,8 +1914,8 @@ func Durable(consumer string) SubOpt { if opts.consumer != _EMPTY_ && opts.consumer != consumer { return fmt.Errorf("nats: duplicate consumer names (%s and %s)", opts.consumer, consumer) } - if strings.Contains(consumer, ".") { - return ErrInvalidDurableName + if err := checkDurName(consumer); err != nil { + return err } opts.cfg.Durable = consumer diff --git a/jsm.go b/jsm.go index f40086b29..a23a4941a 100644 --- a/jsm.go +++ b/jsm.go @@ -239,8 +239,8 @@ func (js *js) AddConsumer(stream string, cfg *ConsumerConfig, opts ...JSOpt) (*C var ccSubj string if cfg != nil && cfg.Durable != _EMPTY_ { - if strings.Contains(cfg.Durable, ".") { - return nil, ErrInvalidDurableName + if err := checkDurName(cfg.Durable); err != nil { + return nil, err } ccSubj = fmt.Sprintf(apiDurableCreateT, stream, cfg.Durable) } else { diff --git a/test/js_test.go b/test/js_test.go index b74cd93fc..7482b3f07 100644 --- a/test/js_test.go +++ b/test/js_test.go @@ -350,6 +350,13 @@ func TestJetStreamSubscribe(t *testing.T) { t.Fatalf("Unexpected error: %v", err) } + // Check that Queue subscribe without durable name requires queue name + // to not have "." in the name. + _, err = js.QueueSubscribeSync("foo", "bar.baz") + if err != nats.ErrInvalidDurableName { + t.Fatalf("Unexpected error: %v", err) + } + msg := []byte("Hello JS") // Basic publish like NATS core.