diff --git a/server/jetstream_api.go b/server/jetstream_api.go index 24fcc3f3..26897c93 100644 --- a/server/jetstream_api.go +++ b/server/jetstream_api.go @@ -664,6 +664,11 @@ func (js *jetStream) apiDispatch(sub *subscription, c *client, acc *Account, sub // Shortcircuit. if len(rr.psubs)+len(rr.qsubs) == 0 { + ci, acc, _, msg, err := s.getRequestInfo(c, rmsg) + if err == nil { + resp := &ApiResponse{Type: JSApiOverloadedType, Error: NewJSBadRequestError()} + s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) + } return } diff --git a/server/jetstream_cluster_test.go b/server/jetstream_cluster_test.go index e7c07f42..c893c4d0 100644 --- a/server/jetstream_cluster_test.go +++ b/server/jetstream_cluster_test.go @@ -11659,6 +11659,35 @@ func TestJetStreamClusterMemoryConsumerCompactVsSnapshot(t *testing.T) { } +func TestJetStreamClusterSendBadRequestResponseOnInvalidAPIRequest(t *testing.T) { + s := RunBasicJetStreamServer() + if config := s.JetStreamConfig(); config != nil { + defer removeDir(t, config.StoreDir) + } + defer s.Shutdown() + + c := createJetStreamClusterExplicit(t, "JSC", 3) + defer c.shutdown() + + checkBadRequest := func(t *testing.T, s *Server) { + nc := natsConnect(t, s.ClientURL()) + defer nc.Close() + + // Send a consumer info but with a bad consumer name. + // Use low-level here to by-bass validity checks done in the client library. + msg, err := nc.Request(fmt.Sprintf(JSApiConsumerInfoT, "BAD_REQUESTS", "bad.consumer.name"), nil, time.Second) + require_NoError(t, err) + + var resp JSApiConsumerInfoResponse + err = json.Unmarshal(msg.Data, &resp) + require_NoError(t, err) + require_Error(t, resp.Error, NewJSBadRequestError()) + } + + t.Run("Single", func(t *testing.T) { checkBadRequest(t, s) }) + t.Run("Clustered", func(t *testing.T) { checkBadRequest(t, c.randomServer()) }) +} + // Support functions // Used to setup superclusters for tests.