diff --git a/server/client.go b/server/client.go index 83435241..e43b10c3 100644 --- a/server/client.go +++ b/server/client.go @@ -3653,9 +3653,16 @@ func getHeader(key string, hdr []byte) []byte { if len(hdr) == 0 { return nil } + + // Fast-path is for when headers use canonical case. index := bytes.Index(hdr, []byte(key)) if index < 0 { - return nil + // To make JetStream headers case insensitive, do another lookup + // with headers in lowercase. + index = bytes.Index(hdr, bytes.ToLower([]byte(key))) + if index < 0 { + return nil + } } index += len(key) if index >= len(hdr) { diff --git a/server/jetstream_test.go b/server/jetstream_test.go index 2d4f7f98..d22c32d1 100644 --- a/server/jetstream_test.go +++ b/server/jetstream_test.go @@ -3427,6 +3427,30 @@ func TestJetStreamPublishExpect(t *testing.T) { t.Fatalf("Expected an error, got %q", resp.Data) } + // Check with JS Headers in different cases. + m = nats.NewMsg("foo.bar") + m.Data = []byte("HI") + m.Header[JSExpectedLastSeq] = []string{"5"} + resp, err = nc.RequestMsg(m, 100*time.Millisecond) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + if pa := getPubAckResponse(resp.Data); pa == nil || pa.Error == nil { + t.Fatalf("Expected an error, got %q", resp.Data) + } + + // Try with JS Header in lower case. + // nats-expected-last-sequence: 5 + m = nats.NewMsg("foo.bar") + m.Header[strings.ToLower(JSExpectedLastSeq)] = []string{"5"} + resp, err = nc.RequestMsg(m, 100*time.Millisecond) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + if pa := getPubAckResponse(resp.Data); pa == nil || pa.Error == nil { + t.Fatalf("Expected an error, got %q", resp.Data) + } + // Restart the server and make sure we remember/rebuild last seq and last msgId. // Stop current sd := s.JetStreamConfig().StoreDir