diff --git a/server/client.go b/server/client.go index ba0ce263..7ff1c4e2 100644 --- a/server/client.go +++ b/server/client.go @@ -435,6 +435,7 @@ type clientOpts struct { Protocol int `json:"protocol"` Account string `json:"account,omitempty"` AccountNew bool `json:"new_account,omitempty"` + Headers bool `json:"headers,omitempty"` // Routes only Import *SubjectPermission `json:"import,omitempty"` @@ -1414,6 +1415,9 @@ func (c *client) processConnect(arg []byte) error { account := c.opts.Account accountNew := c.opts.AccountNew ujwt := c.opts.JWT + // For headers both need to support. If the server supports headers + /// it will have been set to true before this is called. + c.headers = c.headers && c.opts.Headers c.mu.Unlock() if srv != nil { @@ -1845,6 +1849,10 @@ func (c *client) processPong() { // Header pubs take form HPUB [reply] \r\n func (c *client) processHeaderPub(arg []byte) error { + if !c.headers { + return ErrMsgHeadersNotSupported + } + // Unroll splitArgs to avoid runtime/heap issues a := [MAX_HPUB_ARGS][]byte{} args := a[:0] diff --git a/server/client_test.go b/server/client_test.go index 9e78bc11..91594f6e 100644 --- a/server/client_test.go +++ b/server/client_test.go @@ -195,6 +195,7 @@ func TestServerHeaderSupport(t *testing.T) { opts := defaultServerOptions opts.Port = -1 s := New(&opts) + c, _, l := newClientForServer(s) defer c.close() @@ -212,6 +213,7 @@ func TestServerHeaderSupport(t *testing.T) { opts.NoHeaderSupport = true opts.Port = -1 s = New(&opts) + c, _, l = newClientForServer(s) defer c.close() @@ -223,6 +225,43 @@ func TestServerHeaderSupport(t *testing.T) { } } +// This test specifically is not testing how headers are encoded in a raw msg. +// It wants to make sure the serve and clients agreement on when to use headers +// is bi-directional and functions properly. +func TestClientHeaderSupport(t *testing.T) { + opts := defaultServerOptions + opts.Port = -1 + s := New(&opts) + + c, _, _ := newClientForServer(s) + defer c.close() + + // Even though the server supports headers we need to explicitly say we do in the + // CONNECT. If we do not we should get an error. + if err := c.parse([]byte("CONNECT {}\r\nHPUB foo 0 2\r\nok\r\n")); err != ErrMsgHeadersNotSupported { + t.Fatalf("Expected to receive an error, got %v", err) + } + + // This should succeed. + c, _, _ = newClientForServer(s) + defer c.close() + + if err := c.parse([]byte("CONNECT {\"headers\":true}\r\nHPUB foo 0 2\r\nok\r\n")); err != nil { + t.Fatalf("Unexpected error %v", err) + } + + // Now start a server without support. + opts.NoHeaderSupport = true + opts.Port = -1 + s = New(&opts) + + c, _, _ = newClientForServer(s) + defer c.close() + if err := c.parse([]byte("CONNECT {\"headers\":true}\r\nHPUB foo 0 2\r\nok\r\n")); err != ErrMsgHeadersNotSupported { + t.Fatalf("Expected to receive an error, got %v", err) + } +} + func TestNonTLSConnectionState(t *testing.T) { _, c, _ := setupClient() defer c.close() diff --git a/server/parser_test.go b/server/parser_test.go index 945f514d..7afd269d 100644 --- a/server/parser_test.go +++ b/server/parser_test.go @@ -299,6 +299,7 @@ func TestParsePubBadSize(t *testing.T) { func TestParseHeaderPub(t *testing.T) { c := dummyClient() + c.headers = true hpub := []byte("HPUB foo 12 17\r\nname:derek\r\nHELLO\r") if err := c.parse(hpub); err != nil || c.state != MSG_END_N { @@ -360,6 +361,7 @@ func TestParseHeaderPub(t *testing.T) { func TestParseHeaderPubArg(t *testing.T) { c := dummyClient() + c.headers = true for _, test := range []struct { arg string