From add4553570879b26283c3345f23c146de8c36c2a Mon Sep 17 00:00:00 2001 From: Tomasz Pietrek Date: Tue, 11 Apr 2023 23:39:24 +0200 Subject: [PATCH] Fix consumer reply subject escaping If the Consumer had a name containing `%`, it could result in reply subject failing to format with `fmt.Sprintf`, as the `%` was not properly escaped with `%%`. Signed-off-by: Tomasz Pietrek --- server/consumer.go | 5 +++-- server/jetstream_test.go | 31 +++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/server/consumer.go b/server/consumer.go index 066c600f800..10b6d9adea8 100644 --- a/server/consumer.go +++ b/server/consumer.go @@ -823,8 +823,9 @@ func (mset *stream) addConsumerWithAssignment(config *ConsumerConfig, oname stri // Set up the ack subscription for this consumer. Will use wildcard for all acks. // We will remember the template to generate replies with sequence numbers and use // that to scanf them back in. - mn := mset.cfg.Name - pre := fmt.Sprintf(jsAckT, mn, o.name) + mn := strings.ReplaceAll(mset.cfg.Name, "%", "%%") // Escape '%' as `pre` is used as a template later in consumer.ackReply(), + // resulting in erroneous formatting of the ack subject. + pre := fmt.Sprintf(jsAckT, mn, strings.ReplaceAll(o.name, "%", "%%")) o.ackReplyT = fmt.Sprintf("%s.%%d.%%d.%%d.%%d.%%d", pre) o.ackSubj = fmt.Sprintf("%s.*.*.*.*.*", pre) o.nextMsgSubj = fmt.Sprintf(JSApiRequestNextT, mn, o.name) diff --git a/server/jetstream_test.go b/server/jetstream_test.go index 9b381c110e4..cdf3abccf22 100644 --- a/server/jetstream_test.go +++ b/server/jetstream_test.go @@ -19784,3 +19784,34 @@ func TestJetStreamConsumerAckFloorWithExpired(t *testing.T) { require_True(t, ci.NumPending == 0) require_True(t, ci.NumRedelivered == 0) } + +func TestJetStreamConsumerWithFormattingSymbol(t *testing.T) { + s := RunBasicJetStreamServer(t) + defer s.Shutdown() + + nc, js := jsClientConnect(t, s) + defer nc.Close() + + _, err := js.AddStream(&nats.StreamConfig{ + Name: "Test%123", + Subjects: []string{"foo"}, + }) + require_NoError(t, err) + + for i := 0; i < 10; i++ { + sendStreamMsg(t, nc, "foo", "OK") + } + + _, err = js.AddConsumer("Test%123", &nats.ConsumerConfig{ + Durable: "Test%123", + FilterSubject: "foo", + DeliverSubject: "bar", + }) + require_NoError(t, err) + + sub, err := js.SubscribeSync("foo", nats.Bind("Test%123", "Test%123")) + require_NoError(t, err) + + _, err = sub.NextMsg(time.Second * 5) + require_NoError(t, err) +}