github.com/nats-io/nats-server/v2@v2.11.0-preview.2/server/parser_test.go (about)

     1  // Copyright 2012-2024 The NATS Authors
     2  // Licensed under the Apache License, Version 2.0 (the "License");
     3  // you may not use this file except in compliance with the License.
     4  // You may obtain a copy of the License at
     5  //
     6  // http://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software
     9  // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package server
    15  
    16  import (
    17  	"bytes"
    18  	"testing"
    19  )
    20  
    21  func dummyClient() *client {
    22  	return &client{srv: New(&defaultServerOptions), msubs: -1, mpay: -1, mcl: MAX_CONTROL_LINE_SIZE}
    23  }
    24  
    25  func dummyRouteClient() *client {
    26  	return &client{srv: New(&defaultServerOptions), kind: ROUTER}
    27  }
    28  
    29  func TestParsePing(t *testing.T) {
    30  	c := dummyClient()
    31  	if c.state != OP_START {
    32  		t.Fatalf("Expected OP_START vs %d\n", c.state)
    33  	}
    34  	ping := []byte("PING\r\n")
    35  	err := c.parse(ping[:1])
    36  	if err != nil || c.state != OP_P {
    37  		t.Fatalf("Unexpected: %d : %v\n", c.state, err)
    38  	}
    39  	err = c.parse(ping[1:2])
    40  	if err != nil || c.state != OP_PI {
    41  		t.Fatalf("Unexpected: %d : %v\n", c.state, err)
    42  	}
    43  	err = c.parse(ping[2:3])
    44  	if err != nil || c.state != OP_PIN {
    45  		t.Fatalf("Unexpected: %d : %v\n", c.state, err)
    46  	}
    47  	err = c.parse(ping[3:4])
    48  	if err != nil || c.state != OP_PING {
    49  		t.Fatalf("Unexpected: %d : %v\n", c.state, err)
    50  	}
    51  	err = c.parse(ping[4:5])
    52  	if err != nil || c.state != OP_PING {
    53  		t.Fatalf("Unexpected: %d : %v\n", c.state, err)
    54  	}
    55  	err = c.parse(ping[5:6])
    56  	if err != nil || c.state != OP_START {
    57  		t.Fatalf("Unexpected: %d : %v\n", c.state, err)
    58  	}
    59  	err = c.parse(ping)
    60  	if err != nil || c.state != OP_START {
    61  		t.Fatalf("Unexpected: %d : %v\n", c.state, err)
    62  	}
    63  	// Should tolerate spaces
    64  	ping = []byte("PING  \r")
    65  	err = c.parse(ping)
    66  	if err != nil || c.state != OP_PING {
    67  		t.Fatalf("Unexpected: %d : %v\n", c.state, err)
    68  	}
    69  	c.state = OP_START
    70  	ping = []byte("PING  \r  \n")
    71  	err = c.parse(ping)
    72  	if err != nil || c.state != OP_START {
    73  		t.Fatalf("Unexpected: %d : %v\n", c.state, err)
    74  	}
    75  }
    76  
    77  func TestParsePong(t *testing.T) {
    78  	c := dummyClient()
    79  	if c.state != OP_START {
    80  		t.Fatalf("Expected OP_START vs %d\n", c.state)
    81  	}
    82  	pong := []byte("PONG\r\n")
    83  	err := c.parse(pong[:1])
    84  	if err != nil || c.state != OP_P {
    85  		t.Fatalf("Unexpected: %d : %v\n", c.state, err)
    86  	}
    87  	err = c.parse(pong[1:2])
    88  	if err != nil || c.state != OP_PO {
    89  		t.Fatalf("Unexpected: %d : %v\n", c.state, err)
    90  	}
    91  	err = c.parse(pong[2:3])
    92  	if err != nil || c.state != OP_PON {
    93  		t.Fatalf("Unexpected: %d : %v\n", c.state, err)
    94  	}
    95  	err = c.parse(pong[3:4])
    96  	if err != nil || c.state != OP_PONG {
    97  		t.Fatalf("Unexpected: %d : %v\n", c.state, err)
    98  	}
    99  	err = c.parse(pong[4:5])
   100  	if err != nil || c.state != OP_PONG {
   101  		t.Fatalf("Unexpected: %d : %v\n", c.state, err)
   102  	}
   103  	err = c.parse(pong[5:6])
   104  	if err != nil || c.state != OP_START {
   105  		t.Fatalf("Unexpected: %d : %v\n", c.state, err)
   106  	}
   107  	if c.ping.out != 0 {
   108  		t.Fatalf("Unexpected ping.out value: %d vs 0\n", c.ping.out)
   109  	}
   110  	err = c.parse(pong)
   111  	if err != nil || c.state != OP_START {
   112  		t.Fatalf("Unexpected: %d : %v\n", c.state, err)
   113  	}
   114  	if c.ping.out != 0 {
   115  		t.Fatalf("Unexpected ping.out value: %d vs 0\n", c.ping.out)
   116  	}
   117  	// Should tolerate spaces
   118  	pong = []byte("PONG  \r")
   119  	err = c.parse(pong)
   120  	if err != nil || c.state != OP_PONG {
   121  		t.Fatalf("Unexpected: %d : %v\n", c.state, err)
   122  	}
   123  	c.state = OP_START
   124  	pong = []byte("PONG  \r  \n")
   125  	err = c.parse(pong)
   126  	if err != nil || c.state != OP_START {
   127  		t.Fatalf("Unexpected: %d : %v\n", c.state, err)
   128  	}
   129  	if c.ping.out != 0 {
   130  		t.Fatalf("Unexpected ping.out value: %d vs 0\n", c.ping.out)
   131  	}
   132  
   133  	// Should be adjusting c.pout (Pings Outstanding): reset to 0
   134  	c.state = OP_START
   135  	c.ping.out = 10
   136  	pong = []byte("PONG\r\n")
   137  	err = c.parse(pong)
   138  	if err != nil || c.state != OP_START {
   139  		t.Fatalf("Unexpected: %d : %v\n", c.state, err)
   140  	}
   141  	if c.ping.out != 0 {
   142  		t.Fatalf("Unexpected ping.out: %d vs 0\n", c.ping.out)
   143  	}
   144  }
   145  
   146  func TestParseConnect(t *testing.T) {
   147  	c := dummyClient()
   148  	connect := []byte("CONNECT {\"verbose\":false,\"pedantic\":true,\"tls_required\":false}\r\n")
   149  	err := c.parse(connect)
   150  	if err != nil || c.state != OP_START {
   151  		t.Fatalf("Unexpected: %d : %v\n", c.state, err)
   152  	}
   153  	// Check saved state
   154  	if c.as != 8 {
   155  		t.Fatalf("ArgStart state incorrect: 8 vs %d\n", c.as)
   156  	}
   157  }
   158  
   159  func TestParseSub(t *testing.T) {
   160  	c := dummyClient()
   161  	sub := []byte("SUB foo 1\r")
   162  	err := c.parse(sub)
   163  	if err != nil || c.state != SUB_ARG {
   164  		t.Fatalf("Unexpected: %d : %v\n", c.state, err)
   165  	}
   166  	// Check saved state
   167  	if c.as != 4 {
   168  		t.Fatalf("ArgStart state incorrect: 4 vs %d\n", c.as)
   169  	}
   170  	if c.drop != 1 {
   171  		t.Fatalf("Drop state incorrect: 1 vs %d\n", c.as)
   172  	}
   173  	if !bytes.Equal(sub[c.as:], []byte("foo 1\r")) {
   174  		t.Fatalf("Arg state incorrect: %s\n", sub[c.as:])
   175  	}
   176  }
   177  
   178  func TestParsePub(t *testing.T) {
   179  	c := dummyClient()
   180  
   181  	pub := []byte("PUB foo 5\r\nhello\r")
   182  	err := c.parse(pub)
   183  	if err != nil || c.state != MSG_END_N {
   184  		t.Fatalf("Unexpected: %d : %v\n", c.state, err)
   185  	}
   186  	if !bytes.Equal(c.pa.subject, []byte("foo")) {
   187  		t.Fatalf("Did not parse subject correctly: 'foo' vs '%s'\n", string(c.pa.subject))
   188  	}
   189  	if c.pa.reply != nil {
   190  		t.Fatalf("Did not parse reply correctly: 'nil' vs '%s'\n", string(c.pa.reply))
   191  	}
   192  	if c.pa.size != 5 {
   193  		t.Fatalf("Did not parse msg size correctly: 5 vs %d\n", c.pa.size)
   194  	}
   195  
   196  	// Clear snapshots
   197  	c.argBuf, c.msgBuf, c.state = nil, nil, OP_START
   198  
   199  	pub = []byte("PUB foo.bar INBOX.22 11\r\nhello world\r")
   200  	err = c.parse(pub)
   201  	if err != nil || c.state != MSG_END_N {
   202  		t.Fatalf("Unexpected: %d : %v\n", c.state, err)
   203  	}
   204  	if !bytes.Equal(c.pa.subject, []byte("foo.bar")) {
   205  		t.Fatalf("Did not parse subject correctly: 'foo' vs '%s'\n", string(c.pa.subject))
   206  	}
   207  	if !bytes.Equal(c.pa.reply, []byte("INBOX.22")) {
   208  		t.Fatalf("Did not parse reply correctly: 'INBOX.22' vs '%s'\n", string(c.pa.reply))
   209  	}
   210  	if c.pa.size != 11 {
   211  		t.Fatalf("Did not parse msg size correctly: 11 vs %d\n", c.pa.size)
   212  	}
   213  
   214  	// Clear snapshots
   215  	c.argBuf, c.msgBuf, c.state = nil, nil, OP_START
   216  
   217  	// This is the case when data has more bytes than expected by size.
   218  	pub = []byte("PUB foo.bar 11\r\nhello world hello world\r")
   219  	err = c.parse(pub)
   220  	if err == nil {
   221  		t.Fatalf("Expected an error parsing longer than expected message body")
   222  	}
   223  	if c.msgBuf != nil {
   224  		t.Fatalf("Did not expect a c.msgBuf to be non-nil")
   225  	}
   226  }
   227  
   228  // https://www.twistlock.com/labs-blog/finding-dos-vulnerability-nats-go-fuzz-cve-2019-13126/
   229  func TestParsePubSizeOverflow(t *testing.T) {
   230  	c := dummyClient()
   231  
   232  	pub := []byte("PUB foo 3333333333333333333333333333333333333333333333333333333333333333\r\n")
   233  	if err := c.parse(pub); err == nil {
   234  		t.Fatalf("Expected an error")
   235  	}
   236  }
   237  
   238  func TestParsePubArg(t *testing.T) {
   239  	c := dummyClient()
   240  
   241  	for _, test := range []struct {
   242  		arg     string
   243  		subject string
   244  		reply   string
   245  		size    int
   246  		szb     string
   247  	}{
   248  		{arg: "a 2", subject: "a", reply: "", size: 2, szb: "2"},
   249  		{arg: "a 222", subject: "a", reply: "", size: 222, szb: "222"},
   250  		{arg: "foo 22", subject: "foo", reply: "", size: 22, szb: "22"},
   251  		{arg: " foo 22", subject: "foo", reply: "", size: 22, szb: "22"},
   252  		{arg: "foo 22 ", subject: "foo", reply: "", size: 22, szb: "22"},
   253  		{arg: "foo   22", subject: "foo", reply: "", size: 22, szb: "22"},
   254  		{arg: " foo 22 ", subject: "foo", reply: "", size: 22, szb: "22"},
   255  		{arg: " foo   22 ", subject: "foo", reply: "", size: 22, szb: "22"},
   256  		{arg: "foo bar 22", subject: "foo", reply: "bar", size: 22, szb: "22"},
   257  		{arg: " foo bar 22", subject: "foo", reply: "bar", size: 22, szb: "22"},
   258  		{arg: "foo bar 22 ", subject: "foo", reply: "bar", size: 22, szb: "22"},
   259  		{arg: "foo  bar  22", subject: "foo", reply: "bar", size: 22, szb: "22"},
   260  		{arg: " foo bar 22 ", subject: "foo", reply: "bar", size: 22, szb: "22"},
   261  		{arg: "  foo   bar  22  ", subject: "foo", reply: "bar", size: 22, szb: "22"},
   262  		{arg: "  foo   bar  2222  ", subject: "foo", reply: "bar", size: 2222, szb: "2222"},
   263  		{arg: "  foo     2222  ", subject: "foo", reply: "", size: 2222, szb: "2222"},
   264  		{arg: "a\t2", subject: "a", reply: "", size: 2, szb: "2"},
   265  		{arg: "a\t222", subject: "a", reply: "", size: 222, szb: "222"},
   266  		{arg: "foo\t22", subject: "foo", reply: "", size: 22, szb: "22"},
   267  		{arg: "\tfoo\t22", subject: "foo", reply: "", size: 22, szb: "22"},
   268  		{arg: "foo\t22\t", subject: "foo", reply: "", size: 22, szb: "22"},
   269  		{arg: "foo\t\t\t22", subject: "foo", reply: "", size: 22, szb: "22"},
   270  		{arg: "\tfoo\t22\t", subject: "foo", reply: "", size: 22, szb: "22"},
   271  		{arg: "\tfoo\t\t\t22\t", subject: "foo", reply: "", size: 22, szb: "22"},
   272  		{arg: "foo\tbar\t22", subject: "foo", reply: "bar", size: 22, szb: "22"},
   273  		{arg: "\tfoo\tbar\t22", subject: "foo", reply: "bar", size: 22, szb: "22"},
   274  		{arg: "foo\tbar\t22\t", subject: "foo", reply: "bar", size: 22, szb: "22"},
   275  		{arg: "foo\t\tbar\t\t22", subject: "foo", reply: "bar", size: 22, szb: "22"},
   276  		{arg: "\tfoo\tbar\t22\t", subject: "foo", reply: "bar", size: 22, szb: "22"},
   277  		{arg: "\t \tfoo\t \t \tbar\t \t22\t \t", subject: "foo", reply: "bar", size: 22, szb: "22"},
   278  		{arg: "\t\tfoo\t\t\tbar\t\t2222\t\t", subject: "foo", reply: "bar", size: 2222, szb: "2222"},
   279  		{arg: "\t \tfoo\t \t \t\t\t2222\t \t", subject: "foo", reply: "", size: 2222, szb: "2222"},
   280  	} {
   281  		t.Run(test.arg, func(t *testing.T) {
   282  			if err := c.processPub([]byte(test.arg)); err != nil {
   283  				t.Fatalf("Unexpected parse error: %v\n", err)
   284  			}
   285  			if !bytes.Equal(c.pa.subject, []byte(test.subject)) {
   286  				t.Fatalf("Mismatched subject: '%s'\n", c.pa.subject)
   287  			}
   288  			if !bytes.Equal(c.pa.reply, []byte(test.reply)) {
   289  				t.Fatalf("Mismatched reply subject: '%s'\n", c.pa.reply)
   290  			}
   291  			if !bytes.Equal(c.pa.szb, []byte(test.szb)) {
   292  				t.Fatalf("Bad size buf: '%s'\n", c.pa.szb)
   293  			}
   294  			if c.pa.size != test.size {
   295  				t.Fatalf("Bad size: %d\n", c.pa.size)
   296  			}
   297  		})
   298  	}
   299  }
   300  
   301  func TestParsePubBadSize(t *testing.T) {
   302  	c := dummyClient()
   303  	// Setup localized max payload
   304  	c.mpay = 32768
   305  	if err := c.processPub([]byte("foo 2222222222222222")); err == nil {
   306  		t.Fatalf("Expected parse error for size too large")
   307  	}
   308  }
   309  
   310  func TestParseHeaderPub(t *testing.T) {
   311  	c := dummyClient()
   312  	c.headers = true
   313  
   314  	hpub := []byte("HPUB foo 12 17\r\nname:derek\r\nHELLO\r")
   315  	if err := c.parse(hpub); err != nil || c.state != MSG_END_N {
   316  		t.Fatalf("Unexpected: %d : %v\n", c.state, err)
   317  	}
   318  	if !bytes.Equal(c.pa.subject, []byte("foo")) {
   319  		t.Fatalf("Did not parse subject correctly: 'foo' vs '%s'", c.pa.subject)
   320  	}
   321  	if c.pa.reply != nil {
   322  		t.Fatalf("Did not parse reply correctly: 'nil' vs '%s'", c.pa.reply)
   323  	}
   324  	if c.pa.hdr != 12 {
   325  		t.Fatalf("Did not parse msg header size correctly: 12 vs %d", c.pa.hdr)
   326  	}
   327  	if !bytes.Equal(c.pa.hdb, []byte("12")) {
   328  		t.Fatalf("Did not parse or capture the header size as bytes correctly: %q", c.pa.hdb)
   329  	}
   330  	if c.pa.size != 17 {
   331  		t.Fatalf("Did not parse msg size correctly: 17 vs %d", c.pa.size)
   332  	}
   333  
   334  	// Clear snapshots
   335  	c.argBuf, c.msgBuf, c.state = nil, nil, OP_START
   336  
   337  	hpub = []byte("HPUB foo INBOX.22 12 17\r\nname:derek\r\nHELLO\r")
   338  	if err := c.parse(hpub); err != nil || c.state != MSG_END_N {
   339  		t.Fatalf("Unexpected: %d : %v\n", c.state, err)
   340  	}
   341  	if !bytes.Equal(c.pa.subject, []byte("foo")) {
   342  		t.Fatalf("Did not parse subject correctly: 'foo' vs '%s'", c.pa.subject)
   343  	}
   344  	if !bytes.Equal(c.pa.reply, []byte("INBOX.22")) {
   345  		t.Fatalf("Did not parse reply correctly: 'INBOX.22' vs '%s'", c.pa.reply)
   346  	}
   347  	if c.pa.hdr != 12 {
   348  		t.Fatalf("Did not parse msg header size correctly: 12 vs %d", c.pa.hdr)
   349  	}
   350  	if !bytes.Equal(c.pa.hdb, []byte("12")) {
   351  		t.Fatalf("Did not parse or capture the header size as bytes correctly: %q", c.pa.hdb)
   352  	}
   353  	if c.pa.size != 17 {
   354  		t.Fatalf("Did not parse msg size correctly: 17 vs %d", c.pa.size)
   355  	}
   356  
   357  	// Clear snapshots
   358  	c.argBuf, c.msgBuf, c.state = nil, nil, OP_START
   359  
   360  	hpub = []byte("HPUB foo INBOX.22 0 5\r\nHELLO\r")
   361  	if err := c.parse(hpub); err != nil || c.state != MSG_END_N {
   362  		t.Fatalf("Unexpected: %d : %v\n", c.state, err)
   363  	}
   364  	if !bytes.Equal(c.pa.subject, []byte("foo")) {
   365  		t.Fatalf("Did not parse subject correctly: 'foo' vs '%s'\n", c.pa.subject)
   366  	}
   367  	if !bytes.Equal(c.pa.reply, []byte("INBOX.22")) {
   368  		t.Fatalf("Did not parse reply correctly: 'INBOX.22' vs '%s'\n", c.pa.reply)
   369  	}
   370  	if c.pa.hdr != 0 {
   371  		t.Fatalf("Did not parse msg header size correctly: 0 vs %d\n", c.pa.hdr)
   372  	}
   373  	if !bytes.Equal(c.pa.hdb, []byte("0")) {
   374  		t.Fatalf("Did not parse or capture the header size as bytes correctly: %q", c.pa.hdb)
   375  	}
   376  	if c.pa.size != 5 {
   377  		t.Fatalf("Did not parse msg size correctly: 5 vs %d\n", c.pa.size)
   378  	}
   379  }
   380  
   381  func TestParseHeaderPubArg(t *testing.T) {
   382  	c := dummyClient()
   383  	c.headers = true
   384  
   385  	for _, test := range []struct {
   386  		arg     string
   387  		subject string
   388  		reply   string
   389  		hdr     int
   390  		size    int
   391  		szb     string
   392  	}{
   393  		{arg: "a 2 4", subject: "a", reply: "", hdr: 2, size: 4, szb: "4"},
   394  		{arg: "a 22 222", subject: "a", reply: "", hdr: 22, size: 222, szb: "222"},
   395  		{arg: "foo 3 22", subject: "foo", reply: "", hdr: 3, size: 22, szb: "22"},
   396  		{arg: " foo   1 22", subject: "foo", reply: "", hdr: 1, size: 22, szb: "22"},
   397  		{arg: "foo 0   22 ", subject: "foo", reply: "", hdr: 0, size: 22, szb: "22"},
   398  		{arg: "foo  0     22", subject: "foo", reply: "", hdr: 0, size: 22, szb: "22"},
   399  		{arg: " foo 1 22 ", subject: "foo", reply: "", hdr: 1, size: 22, szb: "22"},
   400  		{arg: " foo   3 22 ", subject: "foo", reply: "", hdr: 3, size: 22, szb: "22"},
   401  		{arg: "foo bar 1 22", subject: "foo", reply: "bar", hdr: 1, size: 22, szb: "22"},
   402  		{arg: " foo bar 11 22", subject: "foo", reply: "bar", hdr: 11, size: 22, szb: "22"},
   403  		{arg: "foo bar 11 22 ", subject: "foo", reply: "bar", hdr: 11, size: 22, szb: "22"},
   404  		{arg: "foo  bar  11  22", subject: "foo", reply: "bar", hdr: 11, size: 22, szb: "22"},
   405  		{arg: " foo bar  11 22 ", subject: "foo", reply: "bar", hdr: 11, size: 22, szb: "22"},
   406  		{arg: "  foo   bar  11   22  ", subject: "foo", reply: "bar", hdr: 11, size: 22, szb: "22"},
   407  		{arg: "  foo   bar  22   2222  ", subject: "foo", reply: "bar", hdr: 22, size: 2222, szb: "2222"},
   408  		{arg: "  foo 1    2222  ", subject: "foo", reply: "", hdr: 1, size: 2222, szb: "2222"},
   409  		{arg: "a\t2\t22", subject: "a", reply: "", hdr: 2, size: 22, szb: "22"},
   410  		{arg: "a\t2\t\t222", subject: "a", reply: "", hdr: 2, size: 222, szb: "222"},
   411  		{arg: "foo\t2 22", subject: "foo", reply: "", hdr: 2, size: 22, szb: "22"},
   412  		{arg: "\tfoo\t11\t  22", subject: "foo", reply: "", hdr: 11, size: 22, szb: "22"},
   413  		{arg: "foo\t11\t22\t", subject: "foo", reply: "", hdr: 11, size: 22, szb: "22"},
   414  		{arg: "foo\t\t\t11 22", subject: "foo", reply: "", hdr: 11, size: 22, szb: "22"},
   415  		{arg: "\tfoo\t11\t \t 22\t", subject: "foo", reply: "", hdr: 11, size: 22, szb: "22"},
   416  		{arg: "\tfoo\t\t\t11 22\t", subject: "foo", reply: "", hdr: 11, size: 22, szb: "22"},
   417  		{arg: "foo\tbar\t2 22", subject: "foo", reply: "bar", hdr: 2, size: 22, szb: "22"},
   418  		{arg: "\tfoo\tbar\t11\t22", subject: "foo", reply: "bar", hdr: 11, size: 22, szb: "22"},
   419  		{arg: "foo\tbar\t11\t\t22\t ", subject: "foo", reply: "bar", hdr: 11, size: 22, szb: "22"},
   420  		{arg: "foo\t\tbar\t\t11\t\t\t22", subject: "foo", reply: "bar", hdr: 11, size: 22, szb: "22"},
   421  		{arg: "\tfoo\tbar\t11\t22\t", subject: "foo", reply: "bar", hdr: 11, size: 22, szb: "22"},
   422  		{arg: "\t \tfoo\t \t \tbar\t \t11\t 22\t \t", subject: "foo", reply: "bar", hdr: 11, size: 22, szb: "22"},
   423  		{arg: "\t\tfoo\t\t\tbar\t\t22\t\t\t2222\t\t", subject: "foo", reply: "bar", hdr: 22, size: 2222, szb: "2222"},
   424  		{arg: "\t \tfoo\t \t \t\t\t11\t\t 2222\t \t", subject: "foo", reply: "", hdr: 11, size: 2222, szb: "2222"},
   425  	} {
   426  		t.Run(test.arg, func(t *testing.T) {
   427  			if err := c.processHeaderPub([]byte(test.arg), nil); err != nil {
   428  				t.Fatalf("Unexpected parse error: %v\n", err)
   429  			}
   430  			if !bytes.Equal(c.pa.subject, []byte(test.subject)) {
   431  				t.Fatalf("Mismatched subject: '%s'\n", c.pa.subject)
   432  			}
   433  			if !bytes.Equal(c.pa.reply, []byte(test.reply)) {
   434  				t.Fatalf("Mismatched reply subject: '%s'\n", c.pa.reply)
   435  			}
   436  			if !bytes.Equal(c.pa.szb, []byte(test.szb)) {
   437  				t.Fatalf("Bad size buf: '%s'\n", c.pa.szb)
   438  			}
   439  			if c.pa.hdr != test.hdr {
   440  				t.Fatalf("Bad header size: %d\n", c.pa.hdr)
   441  			}
   442  			if c.pa.size != test.size {
   443  				t.Fatalf("Bad size: %d\n", c.pa.size)
   444  			}
   445  		})
   446  	}
   447  }
   448  
   449  func TestParseRoutedHeaderMsg(t *testing.T) {
   450  	c := dummyRouteClient()
   451  	c.route = &route{}
   452  
   453  	pub := []byte("HMSG $foo foo 10 8\r\nXXXhello\r")
   454  	if err := c.parse(pub); err == nil {
   455  		t.Fatalf("Expected an error")
   456  	}
   457  
   458  	// Clear snapshots
   459  	c.argBuf, c.msgBuf, c.state = nil, nil, OP_START
   460  
   461  	pub = []byte("HMSG $foo foo 3 8\r\nXXXhello\r")
   462  	err := c.parse(pub)
   463  	if err != nil || c.state != MSG_END_N {
   464  		t.Fatalf("Unexpected: %d : %v\n", c.state, err)
   465  	}
   466  	if !bytes.Equal(c.pa.account, []byte("$foo")) {
   467  		t.Fatalf("Did not parse account correctly: '$foo' vs '%s'\n", c.pa.account)
   468  	}
   469  	if !bytes.Equal(c.pa.subject, []byte("foo")) {
   470  		t.Fatalf("Did not parse subject correctly: 'foo' vs '%s'\n", c.pa.subject)
   471  	}
   472  	if c.pa.reply != nil {
   473  		t.Fatalf("Did not parse reply correctly: 'nil' vs '%s'\n", c.pa.reply)
   474  	}
   475  	if c.pa.hdr != 3 {
   476  		t.Fatalf("Did not parse header size correctly: 3 vs %d\n", c.pa.hdr)
   477  	}
   478  	if c.pa.size != 8 {
   479  		t.Fatalf("Did not parse msg size correctly: 8 vs %d\n", c.pa.size)
   480  	}
   481  
   482  	// Clear snapshots
   483  	c.argBuf, c.msgBuf, c.state = nil, nil, OP_START
   484  
   485  	pub = []byte("HMSG $G foo.bar INBOX.22 3 14\r\nOK:hello world\r")
   486  	err = c.parse(pub)
   487  	if err != nil || c.state != MSG_END_N {
   488  		t.Fatalf("Unexpected: %d : %v\n", c.state, err)
   489  	}
   490  	if !bytes.Equal(c.pa.account, []byte("$G")) {
   491  		t.Fatalf("Did not parse account correctly: '$G' vs '%s'\n", c.pa.account)
   492  	}
   493  	if !bytes.Equal(c.pa.subject, []byte("foo.bar")) {
   494  		t.Fatalf("Did not parse subject correctly: 'foo' vs '%s'\n", c.pa.subject)
   495  	}
   496  	if !bytes.Equal(c.pa.reply, []byte("INBOX.22")) {
   497  		t.Fatalf("Did not parse reply correctly: 'INBOX.22' vs '%s'\n", c.pa.reply)
   498  	}
   499  	if c.pa.hdr != 3 {
   500  		t.Fatalf("Did not parse header size correctly: 3 vs %d\n", c.pa.hdr)
   501  	}
   502  	if c.pa.size != 14 {
   503  		t.Fatalf("Did not parse msg size correctly: 14 vs %d\n", c.pa.size)
   504  	}
   505  
   506  	// Clear snapshots
   507  	c.argBuf, c.msgBuf, c.state = nil, nil, OP_START
   508  
   509  	pub = []byte("HMSG $G foo.bar + reply baz 3 14\r\nOK:hello world\r")
   510  	err = c.parse(pub)
   511  	if err != nil || c.state != MSG_END_N {
   512  		t.Fatalf("Unexpected: %d : %v\n", c.state, err)
   513  	}
   514  	if !bytes.Equal(c.pa.account, []byte("$G")) {
   515  		t.Fatalf("Did not parse account correctly: '$G' vs '%s'\n", c.pa.account)
   516  	}
   517  	if !bytes.Equal(c.pa.subject, []byte("foo.bar")) {
   518  		t.Fatalf("Did not parse subject correctly: 'foo' vs '%s'\n", c.pa.subject)
   519  	}
   520  	if !bytes.Equal(c.pa.reply, []byte("reply")) {
   521  		t.Fatalf("Did not parse reply correctly: 'reply' vs '%s'\n", c.pa.reply)
   522  	}
   523  	if len(c.pa.queues) != 1 {
   524  		t.Fatalf("Expected 1 queue, got %d", len(c.pa.queues))
   525  	}
   526  	if !bytes.Equal(c.pa.queues[0], []byte("baz")) {
   527  		t.Fatalf("Did not parse queues correctly: 'baz' vs '%q'\n", c.pa.queues[0])
   528  	}
   529  	if c.pa.hdr != 3 {
   530  		t.Fatalf("Did not parse header size correctly: 3 vs %d\n", c.pa.hdr)
   531  	}
   532  	if c.pa.size != 14 {
   533  		t.Fatalf("Did not parse msg size correctly: 14 vs %d\n", c.pa.size)
   534  	}
   535  
   536  	// Clear snapshots
   537  	c.argBuf, c.msgBuf, c.state = nil, nil, OP_START
   538  
   539  	pub = []byte("HMSG $G foo.bar | baz 3 14\r\nOK:hello world\r")
   540  	err = c.parse(pub)
   541  	if err != nil || c.state != MSG_END_N {
   542  		t.Fatalf("Unexpected: %d : %v\n", c.state, err)
   543  	}
   544  	if !bytes.Equal(c.pa.account, []byte("$G")) {
   545  		t.Fatalf("Did not parse account correctly: '$G' vs '%s'\n", c.pa.account)
   546  	}
   547  	if !bytes.Equal(c.pa.subject, []byte("foo.bar")) {
   548  		t.Fatalf("Did not parse subject correctly: 'foo' vs '%s'\n", c.pa.subject)
   549  	}
   550  	if !bytes.Equal(c.pa.reply, []byte("")) {
   551  		t.Fatalf("Did not parse reply correctly: '' vs '%s'\n", c.pa.reply)
   552  	}
   553  	if len(c.pa.queues) != 1 {
   554  		t.Fatalf("Expected 1 queue, got %d", len(c.pa.queues))
   555  	}
   556  	if !bytes.Equal(c.pa.queues[0], []byte("baz")) {
   557  		t.Fatalf("Did not parse queues correctly: 'baz' vs '%q'\n", c.pa.queues[0])
   558  	}
   559  	if c.pa.hdr != 3 {
   560  		t.Fatalf("Did not parse header size correctly: 3 vs %d\n", c.pa.hdr)
   561  	}
   562  	if c.pa.size != 14 {
   563  		t.Fatalf("Did not parse msg size correctly: 14 vs %d\n", c.pa.size)
   564  	}
   565  }
   566  
   567  func TestParseRouteMsg(t *testing.T) {
   568  	c := dummyRouteClient()
   569  	c.route = &route{}
   570  
   571  	pub := []byte("MSG $foo foo 5\r\nhello\r")
   572  	err := c.parse(pub)
   573  	if err == nil {
   574  		t.Fatalf("Expected an error, got none")
   575  	}
   576  	pub = []byte("RMSG $foo foo 5\r\nhello\r")
   577  	err = c.parse(pub)
   578  	if err != nil || c.state != MSG_END_N {
   579  		t.Fatalf("Unexpected: %d : %v\n", c.state, err)
   580  	}
   581  	if !bytes.Equal(c.pa.account, []byte("$foo")) {
   582  		t.Fatalf("Did not parse account correctly: '$foo' vs '%s'\n", c.pa.account)
   583  	}
   584  	if !bytes.Equal(c.pa.subject, []byte("foo")) {
   585  		t.Fatalf("Did not parse subject correctly: 'foo' vs '%s'\n", c.pa.subject)
   586  	}
   587  	if c.pa.reply != nil {
   588  		t.Fatalf("Did not parse reply correctly: 'nil' vs '%s'\n", c.pa.reply)
   589  	}
   590  	if c.pa.size != 5 {
   591  		t.Fatalf("Did not parse msg size correctly: 5 vs %d\n", c.pa.size)
   592  	}
   593  
   594  	// Clear snapshots
   595  	c.argBuf, c.msgBuf, c.state = nil, nil, OP_START
   596  
   597  	pub = []byte("RMSG $G foo.bar INBOX.22 11\r\nhello world\r")
   598  	err = c.parse(pub)
   599  	if err != nil || c.state != MSG_END_N {
   600  		t.Fatalf("Unexpected: %d : %v\n", c.state, err)
   601  	}
   602  	if !bytes.Equal(c.pa.account, []byte("$G")) {
   603  		t.Fatalf("Did not parse account correctly: '$G' vs '%s'\n", c.pa.account)
   604  	}
   605  	if !bytes.Equal(c.pa.subject, []byte("foo.bar")) {
   606  		t.Fatalf("Did not parse subject correctly: 'foo' vs '%s'\n", c.pa.subject)
   607  	}
   608  	if !bytes.Equal(c.pa.reply, []byte("INBOX.22")) {
   609  		t.Fatalf("Did not parse reply correctly: 'INBOX.22' vs '%s'\n", c.pa.reply)
   610  	}
   611  	if c.pa.size != 11 {
   612  		t.Fatalf("Did not parse msg size correctly: 11 vs %d\n", c.pa.size)
   613  	}
   614  
   615  	// Clear snapshots
   616  	c.argBuf, c.msgBuf, c.state = nil, nil, OP_START
   617  
   618  	pub = []byte("RMSG $G foo.bar + reply baz 11\r\nhello world\r")
   619  	err = c.parse(pub)
   620  	if err != nil || c.state != MSG_END_N {
   621  		t.Fatalf("Unexpected: %d : %v\n", c.state, err)
   622  	}
   623  	if !bytes.Equal(c.pa.account, []byte("$G")) {
   624  		t.Fatalf("Did not parse account correctly: '$G' vs '%s'\n", c.pa.account)
   625  	}
   626  	if !bytes.Equal(c.pa.subject, []byte("foo.bar")) {
   627  		t.Fatalf("Did not parse subject correctly: 'foo' vs '%s'\n", c.pa.subject)
   628  	}
   629  	if !bytes.Equal(c.pa.reply, []byte("reply")) {
   630  		t.Fatalf("Did not parse reply correctly: 'reply' vs '%s'\n", c.pa.reply)
   631  	}
   632  	if len(c.pa.queues) != 1 {
   633  		t.Fatalf("Expected 1 queue, got %d", len(c.pa.queues))
   634  	}
   635  	if !bytes.Equal(c.pa.queues[0], []byte("baz")) {
   636  		t.Fatalf("Did not parse queues correctly: 'baz' vs '%q'\n", c.pa.queues[0])
   637  	}
   638  
   639  	// Clear snapshots
   640  	c.argBuf, c.msgBuf, c.state = nil, nil, OP_START
   641  
   642  	pub = []byte("RMSG $G foo.bar | baz 11\r\nhello world\r")
   643  	err = c.parse(pub)
   644  	if err != nil || c.state != MSG_END_N {
   645  		t.Fatalf("Unexpected: %d : %v\n", c.state, err)
   646  	}
   647  	if !bytes.Equal(c.pa.account, []byte("$G")) {
   648  		t.Fatalf("Did not parse account correctly: '$G' vs '%s'\n", c.pa.account)
   649  	}
   650  	if !bytes.Equal(c.pa.subject, []byte("foo.bar")) {
   651  		t.Fatalf("Did not parse subject correctly: 'foo' vs '%s'\n", c.pa.subject)
   652  	}
   653  	if !bytes.Equal(c.pa.reply, []byte("")) {
   654  		t.Fatalf("Did not parse reply correctly: '' vs '%s'\n", c.pa.reply)
   655  	}
   656  	if len(c.pa.queues) != 1 {
   657  		t.Fatalf("Expected 1 queue, got %d", len(c.pa.queues))
   658  	}
   659  	if !bytes.Equal(c.pa.queues[0], []byte("baz")) {
   660  		t.Fatalf("Did not parse queues correctly: 'baz' vs '%q'\n", c.pa.queues[0])
   661  	}
   662  }
   663  
   664  func TestParseMsgSpace(t *testing.T) {
   665  	c := dummyRouteClient()
   666  
   667  	// Ivan bug he found
   668  	if err := c.parse([]byte("MSG \r\n")); err == nil {
   669  		t.Fatalf("Expected parse error for MSG <SPC>")
   670  	}
   671  
   672  	c = dummyClient()
   673  
   674  	// Anything with an M from a client should parse error
   675  	if err := c.parse([]byte("M")); err == nil {
   676  		t.Fatalf("Expected parse error for M* from a client")
   677  	}
   678  }
   679  
   680  func TestShouldFail(t *testing.T) {
   681  	wrongProtos := []string{
   682  		"xxx",
   683  		"Px", "PIx", "PINx", " PING",
   684  		"POx", "PONx",
   685  		"+x", "+Ox",
   686  		"-x", "-Ex", "-ERx", "-ERRx",
   687  		"Cx", "COx", "CONx", "CONNx", "CONNEx", "CONNECx", "CONNECx", "CONNECT \r\n",
   688  		"PUx", "PUB foo\r\n", "PUB  \r\n", "PUB foo bar       \r\n",
   689  		"PUB foo 2\r\nok \r\n", "PUB foo 2\r\nok\r \n",
   690  		"Sx", "SUx", "SUB\r\n", "SUB  \r\n", "SUB foo\r\n",
   691  		"SUB foo bar baz 22\r\n",
   692  		"Ux", "UNx", "UNSx", "UNSUx", "UNSUBx", "UNSUBUNSUB 1\r\n", "UNSUB_2\r\n",
   693  		"UNSUB_UNSUB_UNSUB 2\r\n", "UNSUB_\t2\r\n", "UNSUB\r\n", "UNSUB \r\n",
   694  		"UNSUB          \t       \r\n",
   695  		"Ix", "INx", "INFx", "INFO  \r\n",
   696  	}
   697  	for _, proto := range wrongProtos {
   698  		c := dummyClient()
   699  		if err := c.parse([]byte(proto)); err == nil {
   700  			t.Fatalf("Should have received a parse error for: %v", proto)
   701  		}
   702  	}
   703  
   704  	// Special case for MSG, type needs to not be client.
   705  	wrongProtos = []string{"Mx", "MSx", "MSGx", "MSG  \r\n"}
   706  	for _, proto := range wrongProtos {
   707  		c := dummyClient()
   708  		c.kind = ROUTER
   709  		if err := c.parse([]byte(proto)); err == nil {
   710  			t.Fatalf("Should have received a parse error for: %v", proto)
   711  		}
   712  	}
   713  }
   714  
   715  func TestProtoSnippet(t *testing.T) {
   716  	sample := []byte("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
   717  
   718  	tests := []struct {
   719  		input    int
   720  		expected string
   721  	}{
   722  		{0, `"abcdefghijklmnopqrstuvwxyzABCDEF"`},
   723  		{1, `"bcdefghijklmnopqrstuvwxyzABCDEFG"`},
   724  		{2, `"cdefghijklmnopqrstuvwxyzABCDEFGH"`},
   725  		{3, `"defghijklmnopqrstuvwxyzABCDEFGHI"`},
   726  		{4, `"efghijklmnopqrstuvwxyzABCDEFGHIJ"`},
   727  		{5, `"fghijklmnopqrstuvwxyzABCDEFGHIJK"`},
   728  		{6, `"ghijklmnopqrstuvwxyzABCDEFGHIJKL"`},
   729  		{7, `"hijklmnopqrstuvwxyzABCDEFGHIJKLM"`},
   730  		{8, `"ijklmnopqrstuvwxyzABCDEFGHIJKLMN"`},
   731  		{9, `"jklmnopqrstuvwxyzABCDEFGHIJKLMNO"`},
   732  		{10, `"klmnopqrstuvwxyzABCDEFGHIJKLMNOP"`},
   733  		{11, `"lmnopqrstuvwxyzABCDEFGHIJKLMNOPQ"`},
   734  		{12, `"mnopqrstuvwxyzABCDEFGHIJKLMNOPQR"`},
   735  		{13, `"nopqrstuvwxyzABCDEFGHIJKLMNOPQRS"`},
   736  		{14, `"opqrstuvwxyzABCDEFGHIJKLMNOPQRST"`},
   737  		{15, `"pqrstuvwxyzABCDEFGHIJKLMNOPQRSTU"`},
   738  		{16, `"qrstuvwxyzABCDEFGHIJKLMNOPQRSTUV"`},
   739  		{17, `"rstuvwxyzABCDEFGHIJKLMNOPQRSTUVW"`},
   740  		{18, `"stuvwxyzABCDEFGHIJKLMNOPQRSTUVWX"`},
   741  		{19, `"tuvwxyzABCDEFGHIJKLMNOPQRSTUVWXY"`},
   742  		{20, `"uvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"`},
   743  		{21, `"vwxyzABCDEFGHIJKLMNOPQRSTUVWXY"`},
   744  		{22, `"wxyzABCDEFGHIJKLMNOPQRSTUVWXY"`},
   745  		{23, `"xyzABCDEFGHIJKLMNOPQRSTUVWXY"`},
   746  		{24, `"yzABCDEFGHIJKLMNOPQRSTUVWXY"`},
   747  		{25, `"zABCDEFGHIJKLMNOPQRSTUVWXY"`},
   748  		{26, `"ABCDEFGHIJKLMNOPQRSTUVWXY"`},
   749  		{27, `"BCDEFGHIJKLMNOPQRSTUVWXY"`},
   750  		{28, `"CDEFGHIJKLMNOPQRSTUVWXY"`},
   751  		{29, `"DEFGHIJKLMNOPQRSTUVWXY"`},
   752  		{30, `"EFGHIJKLMNOPQRSTUVWXY"`},
   753  		{31, `"FGHIJKLMNOPQRSTUVWXY"`},
   754  		{32, `"GHIJKLMNOPQRSTUVWXY"`},
   755  		{33, `"HIJKLMNOPQRSTUVWXY"`},
   756  		{34, `"IJKLMNOPQRSTUVWXY"`},
   757  		{35, `"JKLMNOPQRSTUVWXY"`},
   758  		{36, `"KLMNOPQRSTUVWXY"`},
   759  		{37, `"LMNOPQRSTUVWXY"`},
   760  		{38, `"MNOPQRSTUVWXY"`},
   761  		{39, `"NOPQRSTUVWXY"`},
   762  		{40, `"OPQRSTUVWXY"`},
   763  		{41, `"PQRSTUVWXY"`},
   764  		{42, `"QRSTUVWXY"`},
   765  		{43, `"RSTUVWXY"`},
   766  		{44, `"STUVWXY"`},
   767  		{45, `"TUVWXY"`},
   768  		{46, `"UVWXY"`},
   769  		{47, `"VWXY"`},
   770  		{48, `"WXY"`},
   771  		{49, `"XY"`},
   772  		{50, `"Y"`},
   773  		{51, `""`},
   774  		{52, `""`},
   775  		{53, `""`},
   776  		{54, `""`},
   777  	}
   778  
   779  	for _, tt := range tests {
   780  		got := protoSnippet(tt.input, PROTO_SNIPPET_SIZE, sample)
   781  		if tt.expected != got {
   782  			t.Errorf("Expected protocol snippet to be %s when start=%d but got %s\n", tt.expected, tt.input, got)
   783  		}
   784  	}
   785  }
   786  
   787  func TestParseOK(t *testing.T) {
   788  	c := dummyClient()
   789  	if c.state != OP_START {
   790  		t.Fatalf("Expected OP_START vs %d\n", c.state)
   791  	}
   792  	okProto := []byte("+OK\r\n")
   793  	err := c.parse(okProto[:1])
   794  	if err != nil || c.state != OP_PLUS {
   795  		t.Fatalf("Unexpected: %d : %v\n", c.state, err)
   796  	}
   797  	err = c.parse(okProto[1:2])
   798  	if err != nil || c.state != OP_PLUS_O {
   799  		t.Fatalf("Unexpected: %d : %v\n", c.state, err)
   800  	}
   801  	err = c.parse(okProto[2:3])
   802  	if err != nil || c.state != OP_PLUS_OK {
   803  		t.Fatalf("Unexpected: %d : %v\n", c.state, err)
   804  	}
   805  	err = c.parse(okProto[3:4])
   806  	if err != nil || c.state != OP_PLUS_OK {
   807  		t.Fatalf("Unexpected: %d : %v\n", c.state, err)
   808  	}
   809  	err = c.parse(okProto[4:5])
   810  	if err != nil || c.state != OP_START {
   811  		t.Fatalf("Unexpected: %d : %v\n", c.state, err)
   812  	}
   813  }
   814  
   815  func TestMaxControlLine(t *testing.T) {
   816  	for _, test := range []struct {
   817  		name       string
   818  		kind       int
   819  		shouldFail bool
   820  	}{
   821  		{"client", CLIENT, true},
   822  		{"leaf", LEAF, false},
   823  		{"route", ROUTER, false},
   824  		{"gateway", GATEWAY, false},
   825  	} {
   826  		t.Run(test.name, func(t *testing.T) {
   827  			pub := []byte("PUB foo.bar.baz 2\r\nok\r\n")
   828  
   829  			setupClient := func() *client {
   830  				c := dummyClient()
   831  				c.setNoReconnect()
   832  				c.flags.set(connectReceived)
   833  				c.kind = test.kind
   834  				switch test.kind {
   835  				case ROUTER:
   836  					c.route = &route{}
   837  				case GATEWAY:
   838  					c.gw = &gateway{outbound: false, connected: true, insim: make(map[string]*insie)}
   839  				}
   840  				c.mcl = 8
   841  				return c
   842  			}
   843  
   844  			c := setupClient()
   845  			// First try with a partial:
   846  			// PUB foo.bar.baz 2\r\nok\r\n
   847  			// .............^
   848  			err := c.parse(pub[:14])
   849  			switch test.shouldFail {
   850  			case true:
   851  				if !ErrorIs(err, ErrMaxControlLine) {
   852  					t.Fatalf("Expected an error parsing longer than expected control line")
   853  				}
   854  			case false:
   855  				if err != nil {
   856  					t.Fatalf("Should not have failed, got %v", err)
   857  				}
   858  			}
   859  
   860  			// Now with full protocol (no split) and we should still enforce.
   861  			c = setupClient()
   862  			err = c.parse(pub)
   863  			switch test.shouldFail {
   864  			case true:
   865  				if !ErrorIs(err, ErrMaxControlLine) {
   866  					t.Fatalf("Expected an error parsing longer than expected control line")
   867  				}
   868  			case false:
   869  				if err != nil {
   870  					t.Fatalf("Should not have failed, got %v", err)
   871  				}
   872  			}
   873  		})
   874  	}
   875  }