• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

nats-io / nats-server / 30686292815

30 Jul 2026 01:36PM UTC coverage: 76.029% (-1.3%) from 77.29%
30686292815

push

github

neilalexander
[FIXED] Certificate users authenticatable by username on other listeners

Signed-off-by: Maurice van Veen <github@mauricevanveen.com>

72142 of 94888 relevant lines covered (76.03%)

380706.71 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

81.95
/server/parser.go
1
// Copyright 2012-2025 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
        "bufio"
18
        "bytes"
19
        "fmt"
20
        "net/http"
21
        "net/textproto"
22
)
23

24
type parserState int
25
type parseState struct {
26
        state   parserState
27
        op      byte
28
        as      int
29
        drop    int
30
        pa      pubArg
31
        argBuf  []byte
32
        msgBuf  []byte
33
        header  http.Header // access via getHeader
34
        scratch [MAX_CONTROL_LINE_SIZE]byte
35
        argsa   [MAX_HMSG_ARGS + 1][]byte // pre-allocated args array to avoid per-call heap escape
36
}
37

38
type pubArg struct {
39
        arg       []byte
40
        pacache   []byte
41
        origin    []byte
42
        account   []byte
43
        subject   []byte
44
        deliver   []byte
45
        mapped    []byte
46
        reply     []byte
47
        szb       []byte
48
        hdb       []byte
49
        queues    [][]byte
50
        size      int
51
        hdr       int
52
        psi       []*serviceImport
53
        trace     *msgTrace
54
        delivered bool // Only used for service imports
55
}
56

57
// Parser constants
58
const (
59
        OP_START parserState = iota
60
        OP_PLUS
61
        OP_PLUS_O
62
        OP_PLUS_OK
63
        OP_MINUS
64
        OP_MINUS_E
65
        OP_MINUS_ER
66
        OP_MINUS_ERR
67
        OP_MINUS_ERR_SPC
68
        MINUS_ERR_ARG
69
        OP_C
70
        OP_CO
71
        OP_CON
72
        OP_CONN
73
        OP_CONNE
74
        OP_CONNEC
75
        OP_CONNECT
76
        CONNECT_ARG
77
        OP_H
78
        OP_HP
79
        OP_HPU
80
        OP_HPUB
81
        OP_HPUB_SPC
82
        HPUB_ARG
83
        OP_HM
84
        OP_HMS
85
        OP_HMSG
86
        OP_HMSG_SPC
87
        HMSG_ARG
88
        OP_P
89
        OP_PU
90
        OP_PUB
91
        OP_PUB_SPC
92
        PUB_ARG
93
        OP_PI
94
        OP_PIN
95
        OP_PING
96
        OP_PO
97
        OP_PON
98
        OP_PONG
99
        MSG_PAYLOAD
100
        MSG_END_R
101
        MSG_END_N
102
        OP_S
103
        OP_SU
104
        OP_SUB
105
        OP_SUB_SPC
106
        SUB_ARG
107
        OP_A
108
        OP_ASUB
109
        OP_ASUB_SPC
110
        ASUB_ARG
111
        OP_AUSUB
112
        OP_AUSUB_SPC
113
        AUSUB_ARG
114
        OP_L
115
        OP_LS
116
        OP_R
117
        OP_RS
118
        OP_U
119
        OP_UN
120
        OP_UNS
121
        OP_UNSU
122
        OP_UNSUB
123
        OP_UNSUB_SPC
124
        UNSUB_ARG
125
        OP_M
126
        OP_MS
127
        OP_MSG
128
        OP_MSG_SPC
129
        MSG_ARG
130
        OP_I
131
        OP_IN
132
        OP_INF
133
        OP_INFO
134
        INFO_ARG
135
)
136

137
func (c *client) parse(buf []byte) error {
10,535,867✔
138
        // Branch out to mqtt clients. c.mqtt is immutable, but should it become
10,535,867✔
139
        // an issue (say data race detection), we could branch outside in readLoop
10,535,867✔
140
        if c.isMqtt() {
10,535,871✔
141
                return c.mqttParse(buf)
4✔
142
        }
4✔
143
        var i int
10,535,863✔
144
        var b byte
10,535,863✔
145
        var lmsg bool
10,535,863✔
146

10,535,863✔
147
        // Snapshots
10,535,863✔
148
        c.mu.Lock()
10,535,863✔
149
        // Snapshot and then reset when we receive a
10,535,863✔
150
        // proper CONNECT if needed.
10,535,863✔
151
        authSet := c.awaitingAuth()
10,535,863✔
152
        // Snapshot max control line as well.
10,535,863✔
153
        s, mcl, trace := c.srv, c.mcl, c.trace
10,535,863✔
154
        c.mu.Unlock()
10,535,863✔
155

10,535,863✔
156
        // Move to loop instead of range syntax to allow jumping of i
10,535,863✔
157
        for i = 0; i < len(buf); i++ {
714,048,885✔
158
                b = buf[i]
703,513,022✔
159

703,513,022✔
160
                switch c.state {
703,513,022✔
161
                case OP_START:
15,639,659✔
162
                        c.op = b
15,639,659✔
163
                        if b != 'C' && b != 'c' {
31,236,753✔
164
                                if authSet {
15,597,412✔
165
                                        if s == nil {
318✔
166
                                                goto authErr
×
167
                                        }
168
                                        var ok bool
318✔
169
                                        switch c.kind {
318✔
170
                                        case CLIENT:
5✔
171
                                                // Check here for NoAuthUser. If this is set allow non CONNECT protos as our first.
5✔
172
                                                // E.g. telnet proto demos.
5✔
173
                                                opts := s.getOpts()
5✔
174
                                                noAuthUser := opts.NoAuthUser
5✔
175
                                                if c.ws != nil {
5✔
176
                                                        if noAuthUserWS := opts.Websocket.NoAuthUser; noAuthUserWS != _EMPTY_ {
×
177
                                                                noAuthUser = noAuthUserWS
×
178
                                                        }
×
179
                                                }
180
                                                if noAuthUser != _EMPTY_ {
9✔
181
                                                        s.mu.Lock()
4✔
182
                                                        user, exists := s.users[noAuthUser]
4✔
183
                                                        s.mu.Unlock()
4✔
184
                                                        // Run the same authentication pipeline as CONNECT. In addition to
4✔
185
                                                        // the connection restrictions checked here, this delegates the
4✔
186
                                                        // decision to auth callouts or custom authenticators.
4✔
187
                                                        if exists && !user.ProxyRequired && c.connectionTypeAllowed(user.AllowedConnectionTypes) {
8✔
188
                                                                // Mirror processConnect: clear the auth-timeout timer and
4✔
189
                                                                // mark CONNECT received *before* authenticating. Auth may
4✔
190
                                                                // install a JWT/callout expiration timer into the same c.atmr
4✔
191
                                                                // slot, so clearing it afterwards would drop the expiration
4✔
192
                                                                // and leave the client connected past expiry. Setting
4✔
193
                                                                // connectReceived first also lets the expiration deadline be
4✔
194
                                                                // recorded on c.expires.
4✔
195
                                                                c.mu.Lock()
4✔
196
                                                                c.clearAuthTimer()
4✔
197
                                                                c.flags.set(connectReceived)
4✔
198
                                                                c.mu.Unlock()
4✔
199
                                                                if s.checkAuthentication(c) {
7✔
200
                                                                        authSet, ok = false, true
3✔
201
                                                                }
3✔
202
                                                        }
203
                                                }
204
                                        case LEAF:
294✔
205
                                                // Compressed inbound leaf-node negotiation may require INFO
294✔
206
                                                // before CONNECT. Without compression, leaf connections must
294✔
207
                                                // still start with CONNECT.
294✔
208
                                                ok = (b == 'I' || b == 'i') && needsCompression(s.getOpts().LeafNode.Compression.Mode)
294✔
209
                                        }
210
                                        if !ok {
341✔
211
                                                goto authErr
23✔
212
                                        }
213
                                }
214
                        }
215
                        switch b {
15,639,636✔
216
                        case 'P', 'p':
4,094,567✔
217
                                c.state = OP_P
4,094,567✔
218
                        case 'H', 'h':
1,536,784✔
219
                                c.state = OP_H
1,536,784✔
220
                        case 'S', 's':
130,613✔
221
                                c.state = OP_S
130,613✔
222
                        case 'U', 'u':
12,725✔
223
                                c.state = OP_U
12,725✔
224
                        case 'R', 'r':
9,677,403✔
225
                                if c.kind == CLIENT {
9,677,403✔
226
                                        goto parseErr
×
227
                                } else {
9,677,403✔
228
                                        c.state = OP_R
9,677,403✔
229
                                }
9,677,403✔
230
                        case 'L', 'l':
57,124✔
231
                                if c.kind != LEAF && c.kind != ROUTER {
57,124✔
232
                                        goto parseErr
×
233
                                } else {
57,124✔
234
                                        c.state = OP_L
57,124✔
235
                                }
57,124✔
236
                        case 'A', 'a':
17✔
237
                                if c.kind == CLIENT {
17✔
238
                                        goto parseErr
×
239
                                } else {
17✔
240
                                        c.state = OP_A
17✔
241
                                }
17✔
242
                        case 'C', 'c':
42,565✔
243
                                c.state = OP_C
42,565✔
244
                        case 'I', 'i':
87,696✔
245
                                c.state = OP_I
87,696✔
246
                        case '+':
×
247
                                c.state = OP_PLUS
×
248
                        case '-':
141✔
249
                                c.state = OP_MINUS
141✔
250
                        default:
1✔
251
                                goto parseErr
1✔
252
                        }
253
                case OP_H:
1,536,784✔
254
                        switch b {
1,536,784✔
255
                        case 'P', 'p':
915,440✔
256
                                c.state = OP_HP
915,440✔
257
                        case 'M', 'm':
621,344✔
258
                                c.state = OP_HM
621,344✔
259
                        default:
×
260
                                goto parseErr
×
261
                        }
262
                case OP_HP:
915,440✔
263
                        switch b {
915,440✔
264
                        case 'U', 'u':
915,440✔
265
                                c.state = OP_HPU
915,440✔
266
                        default:
×
267
                                goto parseErr
×
268
                        }
269
                case OP_HPU:
915,440✔
270
                        switch b {
915,440✔
271
                        case 'B', 'b':
915,440✔
272
                                c.state = OP_HPUB
915,440✔
273
                        default:
×
274
                                goto parseErr
×
275
                        }
276
                case OP_HPUB:
915,440✔
277
                        switch b {
915,440✔
278
                        case ' ', '\t':
915,440✔
279
                                c.state = OP_HPUB_SPC
915,440✔
280
                        default:
×
281
                                goto parseErr
×
282
                        }
283
                case OP_HPUB_SPC:
915,440✔
284
                        switch b {
915,440✔
285
                        case ' ', '\t':
×
286
                                continue
×
287
                        default:
915,440✔
288
                                c.pa.hdr = 0
915,440✔
289
                                c.state = HPUB_ARG
915,440✔
290
                                c.as = i
915,440✔
291
                        }
292
                case HPUB_ARG:
34,001,997✔
293
                        switch b {
34,001,997✔
294
                        case '\r':
915,440✔
295
                                c.drop = 1
915,440✔
296
                        case '\n':
915,440✔
297
                                var arg []byte
915,440✔
298
                                if c.argBuf != nil {
915,485✔
299
                                        arg = c.argBuf
45✔
300
                                        c.argBuf = nil
45✔
301
                                } else {
915,440✔
302
                                        arg = buf[c.as : i-c.drop]
915,395✔
303
                                }
915,395✔
304
                                if err := c.overMaxControlLineLimit(arg, mcl); err != nil {
915,440✔
305
                                        return err
×
306
                                }
×
307
                                if trace {
915,444✔
308
                                        c.traceInOp("HPUB", arg)
4✔
309
                                }
4✔
310
                                var remaining []byte
915,440✔
311
                                if i < len(buf) {
1,830,880✔
312
                                        remaining = buf[i+1:]
915,440✔
313
                                }
915,440✔
314
                                if err := c.processHeaderPub(arg, remaining); err != nil {
915,442✔
315
                                        return err
2✔
316
                                }
2✔
317

318
                                c.drop, c.as, c.state = 0, i+1, MSG_PAYLOAD
915,438✔
319
                                // If we don't have a saved buffer then jump ahead with
915,438✔
320
                                // the index. If this overruns what is left we fall out
915,438✔
321
                                // and process split buffer.
915,438✔
322
                                if c.msgBuf == nil {
1,830,876✔
323
                                        i = c.as + c.pa.size - LEN_CR_LF
915,438✔
324
                                }
915,438✔
325
                        default:
32,171,117✔
326
                                if c.argBuf != nil {
32,171,710✔
327
                                        c.argBuf = append(c.argBuf, b)
593✔
328
                                }
593✔
329
                        }
330
                case OP_HM:
621,344✔
331
                        switch b {
621,344✔
332
                        case 'S', 's':
621,344✔
333
                                c.state = OP_HMS
621,344✔
334
                        default:
×
335
                                goto parseErr
×
336
                        }
337
                case OP_HMS:
621,344✔
338
                        switch b {
621,344✔
339
                        case 'G', 'g':
621,344✔
340
                                c.state = OP_HMSG
621,344✔
341
                        default:
×
342
                                goto parseErr
×
343
                        }
344
                case OP_HMSG:
621,344✔
345
                        switch b {
621,344✔
346
                        case ' ', '\t':
621,344✔
347
                                c.state = OP_HMSG_SPC
621,344✔
348
                        default:
×
349
                                goto parseErr
×
350
                        }
351
                case OP_HMSG_SPC:
621,344✔
352
                        switch b {
621,344✔
353
                        case ' ', '\t':
×
354
                                continue
×
355
                        default:
621,344✔
356
                                c.pa.hdr = 0
621,344✔
357
                                c.state = HMSG_ARG
621,344✔
358
                                c.as = i
621,344✔
359
                        }
360
                case HMSG_ARG:
48,365,324✔
361
                        switch b {
48,365,324✔
362
                        case '\r':
621,344✔
363
                                c.drop = 1
621,344✔
364
                        case '\n':
621,344✔
365
                                var arg []byte
621,344✔
366
                                if c.argBuf != nil {
628,487✔
367
                                        arg = c.argBuf
7,143✔
368
                                        c.argBuf = nil
7,143✔
369
                                } else {
621,344✔
370
                                        arg = buf[c.as : i-c.drop]
614,201✔
371
                                }
614,201✔
372
                                if err := c.overMaxControlLineLimit(arg, mcl); err != nil {
621,344✔
373
                                        return err
×
374
                                }
×
375
                                var err error
621,344✔
376
                                if c.kind == ROUTER || c.kind == GATEWAY {
1,242,534✔
377
                                        if trace {
622,912✔
378
                                                c.traceInOp("HMSG", arg)
1,722✔
379
                                        }
1,722✔
380
                                        err = c.processRoutedHeaderMsgArgs(arg)
621,190✔
381
                                } else if c.kind == LEAF {
308✔
382
                                        if trace {
154✔
383
                                                c.traceInOp("HMSG", arg)
×
384
                                        }
×
385
                                        err = c.processLeafHeaderMsgArgs(arg)
154✔
386
                                }
387
                                if err != nil {
621,344✔
388
                                        return err
×
389
                                }
×
390
                                c.drop, c.as, c.state = 0, i+1, MSG_PAYLOAD
621,344✔
391

621,344✔
392
                                // jump ahead with the index. If this overruns
621,344✔
393
                                // what is left we fall out and process split
621,344✔
394
                                // buffer.
621,344✔
395
                                i = c.as + c.pa.size - LEN_CR_LF
621,344✔
396
                        default:
47,122,636✔
397
                                if c.argBuf != nil {
47,289,318✔
398
                                        c.argBuf = append(c.argBuf, b)
166,682✔
399
                                }
166,682✔
400
                        }
401
                case OP_P:
4,094,567✔
402
                        switch b {
4,094,567✔
403
                        case 'U', 'u':
4,023,435✔
404
                                c.state = OP_PU
4,023,435✔
405
                        case 'I', 'i':
39,825✔
406
                                c.state = OP_PI
39,825✔
407
                        case 'O', 'o':
31,307✔
408
                                c.state = OP_PO
31,307✔
409
                        default:
×
410
                                goto parseErr
×
411
                        }
412
                case OP_PU:
4,023,435✔
413
                        switch b {
4,023,435✔
414
                        case 'B', 'b':
4,023,435✔
415
                                c.state = OP_PUB
4,023,435✔
416
                        default:
×
417
                                goto parseErr
×
418
                        }
419
                case OP_PUB:
4,023,435✔
420
                        switch b {
4,023,435✔
421
                        case ' ', '\t':
4,023,434✔
422
                                c.state = OP_PUB_SPC
4,023,434✔
423
                        default:
1✔
424
                                goto parseErr
1✔
425
                        }
426
                case OP_PUB_SPC:
4,023,433✔
427
                        switch b {
4,023,433✔
428
                        case ' ', '\t':
×
429
                                continue
×
430
                        default:
4,023,433✔
431
                                c.pa.hdr = -1
4,023,433✔
432
                                c.state = PUB_ARG
4,023,433✔
433
                                c.as = i
4,023,433✔
434
                        }
435
                case PUB_ARG:
104,712,431✔
436
                        switch b {
104,712,431✔
437
                        case '\r':
4,023,424✔
438
                                c.drop = 1
4,023,424✔
439
                        case '\n':
4,023,424✔
440
                                var arg []byte
4,023,424✔
441
                                if c.argBuf != nil {
4,044,206✔
442
                                        arg = c.argBuf
20,782✔
443
                                        c.argBuf = nil
20,782✔
444
                                } else {
4,023,424✔
445
                                        arg = buf[c.as : i-c.drop]
4,002,642✔
446
                                }
4,002,642✔
447
                                if err := c.overMaxControlLineLimit(arg, mcl); err != nil {
4,023,424✔
448
                                        return err
×
449
                                }
×
450
                                if trace {
4,329,485✔
451
                                        c.traceInOp("PUB", arg)
306,061✔
452
                                }
306,061✔
453
                                if err := c.processPub(arg); err != nil {
4,023,428✔
454
                                        return err
4✔
455
                                }
4✔
456

457
                                c.drop, c.as, c.state = 0, i+1, MSG_PAYLOAD
4,023,420✔
458
                                // If we don't have a saved buffer then jump ahead with
4,023,420✔
459
                                // the index. If this overruns what is left we fall out
4,023,420✔
460
                                // and process split buffer.
4,023,420✔
461
                                if c.msgBuf == nil {
8,046,840✔
462
                                        i = c.as + c.pa.size - LEN_CR_LF
4,023,420✔
463
                                }
4,023,420✔
464
                        default:
96,665,583✔
465
                                if c.argBuf != nil {
97,098,437✔
466
                                        c.argBuf = append(c.argBuf, b)
432,854✔
467
                                }
432,854✔
468
                        }
469
                case MSG_PAYLOAD:
14,521,936✔
470
                        if c.msgBuf != nil {
16,127,226✔
471
                                // copy as much as we can to the buffer and skip ahead.
1,605,290✔
472
                                toCopy := c.pa.size - len(c.msgBuf)
1,605,290✔
473
                                avail := len(buf) - i
1,605,290✔
474
                                if avail < toCopy {
2,075,817✔
475
                                        toCopy = avail
470,527✔
476
                                }
470,527✔
477
                                if toCopy > 0 {
3,210,580✔
478
                                        start := len(c.msgBuf)
1,605,290✔
479
                                        // This is needed for copy to work.
1,605,290✔
480
                                        c.msgBuf = c.msgBuf[:start+toCopy]
1,605,290✔
481
                                        copy(c.msgBuf[start:], buf[i:i+toCopy])
1,605,290✔
482
                                        // Update our index
1,605,290✔
483
                                        i = (i + toCopy) - 1
1,605,290✔
484
                                } else {
1,605,290✔
485
                                        // Fall back to append if needed.
×
486
                                        c.msgBuf = append(c.msgBuf, b)
×
487
                                }
×
488
                                if len(c.msgBuf) >= c.pa.size {
2,740,053✔
489
                                        c.state = MSG_END_R
1,134,763✔
490
                                }
1,134,763✔
491
                        } else if i-c.as+1 >= c.pa.size {
25,833,292✔
492
                                c.state = MSG_END_R
12,916,646✔
493
                        }
12,916,646✔
494
                case MSG_END_R:
14,051,408✔
495
                        if b != '\r' {
14,051,409✔
496
                                goto parseErr
1✔
497
                        }
498
                        if c.msgBuf != nil {
15,201,400✔
499
                                c.msgBuf = append(c.msgBuf, b)
1,149,993✔
500
                        }
1,149,993✔
501
                        c.state = MSG_END_N
14,051,407✔
502
                case MSG_END_N:
14,051,407✔
503
                        if b != '\n' {
14,051,407✔
504
                                goto parseErr
×
505
                        }
506
                        if c.msgBuf != nil {
15,208,127✔
507
                                c.msgBuf = append(c.msgBuf, b)
1,156,720✔
508
                        } else {
14,051,407✔
509
                                c.msgBuf = buf[c.as : i+1]
12,894,687✔
510
                        }
12,894,687✔
511

512
                        var mt *msgTrace
14,051,407✔
513
                        var skip bool
14,051,407✔
514
                        if c.pa.hdr > 0 {
15,588,284✔
515
                                skip, mt = c.initMsgTrace(c.msgBuf[:c.pa.hdr], nil)
1,536,877✔
516
                        }
1,536,877✔
517
                        if !skip {
28,102,814✔
518
                                // Check for mappings.
14,051,407✔
519
                                if (c.kind == CLIENT || c.kind == LEAF) && c.in.flags.isSet(hasMappings) {
14,072,314✔
520
                                        changed := c.selectMappedSubject()
20,907✔
521
                                        if changed {
31,364✔
522
                                                if trace {
10,457✔
523
                                                        c.traceInOp("MAPPING", []byte(fmt.Sprintf("%s -> %s", c.pa.mapped, c.pa.subject)))
×
524
                                                }
×
525
                                                // c.pa.subject is the subject the original is now mapped to.
526
                                                mt.addSubjectMappingEvent(c.pa.subject)
10,457✔
527
                                        }
528
                                }
529
                                if trace {
14,363,418✔
530
                                        c.traceMsg(c.msgBuf)
312,011✔
531
                                }
312,011✔
532

533
                                c.processInboundMsg(c.msgBuf)
14,051,407✔
534

14,051,407✔
535
                                mt.sendEvent()
14,051,407✔
536
                        }
537
                        c.argBuf, c.msgBuf, c.header = nil, nil, nil
14,051,407✔
538
                        c.drop, c.as, c.state = 0, i+1, OP_START
14,051,407✔
539
                        // Drop all pub args
14,051,407✔
540
                        c.pa.arg, c.pa.pacache, c.pa.origin, c.pa.account, c.pa.subject, c.pa.mapped = nil, nil, nil, nil, nil, nil
14,051,407✔
541
                        c.pa.reply, c.pa.hdr, c.pa.size, c.pa.szb, c.pa.hdb, c.pa.queues = nil, -1, 0, nil, nil, nil
14,051,407✔
542
                        c.pa.trace = nil
14,051,407✔
543
                        c.pa.delivered = false
14,051,407✔
544
                        lmsg = false
14,051,407✔
545
                case OP_A:
17✔
546
                        switch b {
17✔
547
                        case '+':
4✔
548
                                c.state = OP_ASUB
4✔
549
                        case '-', 'u':
13✔
550
                                c.state = OP_AUSUB
13✔
551
                        default:
×
552
                                goto parseErr
×
553
                        }
554
                case OP_ASUB:
4✔
555
                        switch b {
4✔
556
                        case ' ', '\t':
4✔
557
                                c.state = OP_ASUB_SPC
4✔
558
                        default:
×
559
                                goto parseErr
×
560
                        }
561
                case OP_ASUB_SPC:
4✔
562
                        switch b {
4✔
563
                        case ' ', '\t':
×
564
                                continue
×
565
                        default:
4✔
566
                                c.state = ASUB_ARG
4✔
567
                                c.as = i
4✔
568
                        }
569
                case ASUB_ARG:
14✔
570
                        switch b {
14✔
571
                        case '\r':
4✔
572
                                c.drop = 1
4✔
573
                        case '\n':
4✔
574
                                var arg []byte
4✔
575
                                if c.argBuf != nil {
4✔
576
                                        arg = c.argBuf
×
577
                                        c.argBuf = nil
×
578
                                } else {
4✔
579
                                        arg = buf[c.as : i-c.drop]
4✔
580
                                }
4✔
581
                                if err := c.overMaxControlLineLimit(arg, mcl); err != nil {
4✔
582
                                        return err
×
583
                                }
×
584
                                if trace {
4✔
585
                                        c.traceInOp("A+", arg)
×
586
                                }
×
587
                                if err := c.processAccountSub(arg); err != nil {
4✔
588
                                        return err
×
589
                                }
×
590
                                c.drop, c.as, c.state = 0, i+1, OP_START
4✔
591
                        default:
6✔
592
                                if c.argBuf != nil {
6✔
593
                                        c.argBuf = append(c.argBuf, b)
×
594
                                }
×
595
                        }
596
                case OP_AUSUB:
13✔
597
                        switch b {
13✔
598
                        case ' ', '\t':
13✔
599
                                c.state = OP_AUSUB_SPC
13✔
600
                        default:
×
601
                                goto parseErr
×
602
                        }
603
                case OP_AUSUB_SPC:
13✔
604
                        switch b {
13✔
605
                        case ' ', '\t':
×
606
                                continue
×
607
                        default:
13✔
608
                                c.state = AUSUB_ARG
13✔
609
                                c.as = i
13✔
610
                        }
611
                case AUSUB_ARG:
47✔
612
                        switch b {
47✔
613
                        case '\r':
13✔
614
                                c.drop = 1
13✔
615
                        case '\n':
13✔
616
                                var arg []byte
13✔
617
                                if c.argBuf != nil {
13✔
618
                                        arg = c.argBuf
×
619
                                        c.argBuf = nil
×
620
                                } else {
13✔
621
                                        arg = buf[c.as : i-c.drop]
13✔
622
                                }
13✔
623
                                if err := c.overMaxControlLineLimit(arg, mcl); err != nil {
13✔
624
                                        return err
×
625
                                }
×
626
                                if trace {
15✔
627
                                        c.traceInOp("A-", arg)
2✔
628
                                }
2✔
629
                                c.processAccountUnsub(arg)
13✔
630
                                c.drop, c.as, c.state = 0, i+1, OP_START
13✔
631
                        default:
21✔
632
                                if c.argBuf != nil {
21✔
633
                                        c.argBuf = append(c.argBuf, b)
×
634
                                }
×
635
                        }
636
                case OP_S:
130,613✔
637
                        switch b {
130,613✔
638
                        case 'U', 'u':
130,613✔
639
                                c.state = OP_SU
130,613✔
640
                        default:
×
641
                                goto parseErr
×
642
                        }
643
                case OP_SU:
130,613✔
644
                        switch b {
130,613✔
645
                        case 'B', 'b':
130,613✔
646
                                c.state = OP_SUB
130,613✔
647
                        default:
×
648
                                goto parseErr
×
649
                        }
650
                case OP_SUB:
1,160,981✔
651
                        switch b {
1,160,981✔
652
                        case ' ', '\t':
1,160,980✔
653
                                c.state = OP_SUB_SPC
1,160,980✔
654
                        default:
1✔
655
                                goto parseErr
1✔
656
                        }
657
                case OP_SUB_SPC:
1,160,980✔
658
                        switch b {
1,160,980✔
659
                        case ' ', '\t':
×
660
                                continue
×
661
                        default:
1,160,980✔
662
                                c.state = SUB_ARG
1,160,980✔
663
                                c.as = i
1,160,980✔
664
                        }
665
                case SUB_ARG:
43,502,582✔
666
                        switch b {
43,502,582✔
667
                        case '\r':
1,160,935✔
668
                                c.drop = 1
1,160,935✔
669
                        case '\n':
1,160,935✔
670
                                var arg []byte
1,160,935✔
671
                                if c.argBuf != nil {
1,187,658✔
672
                                        arg = c.argBuf
26,723✔
673
                                        c.argBuf = nil
26,723✔
674
                                } else {
1,160,935✔
675
                                        arg = buf[c.as : i-c.drop]
1,134,212✔
676
                                }
1,134,212✔
677
                                if err := c.overMaxControlLineLimit(arg, mcl); err != nil {
1,160,935✔
678
                                        return err
×
679
                                }
×
680
                                var err error
1,160,935✔
681

1,160,935✔
682
                                switch c.kind {
1,160,935✔
683
                                case CLIENT:
130,611✔
684
                                        if trace {
141,340✔
685
                                                c.traceInOp("SUB", arg)
10,729✔
686
                                        }
10,729✔
687
                                        err = c.parseSub(arg, false)
130,611✔
688
                                case ROUTER:
856,706✔
689
                                        switch c.op {
856,706✔
690
                                        case 'R', 'r':
847,648✔
691
                                                if trace {
847,737✔
692
                                                        c.traceInOp("RS+", arg)
89✔
693
                                                }
89✔
694
                                                err = c.processRemoteSub(arg, false)
847,648✔
695
                                        case 'L', 'l':
9,058✔
696
                                                if trace {
9,058✔
697
                                                        c.traceInOp("LS+", arg)
×
698
                                                }
×
699
                                                err = c.processRemoteSub(arg, true)
9,058✔
700
                                        }
701
                                case GATEWAY:
148,956✔
702
                                        if trace {
149,245✔
703
                                                c.traceInOp("RS+", arg)
289✔
704
                                        }
289✔
705
                                        err = c.processGatewayRSub(arg)
148,956✔
706
                                case LEAF:
24,662✔
707
                                        if trace {
24,668✔
708
                                                c.traceInOp("LS+", arg)
6✔
709
                                        }
6✔
710
                                        err = c.processLeafSub(arg)
24,662✔
711
                                }
712
                                if err != nil {
1,160,935✔
713
                                        return err
×
714
                                }
×
715
                                c.drop, c.as, c.state = 0, i+1, OP_START
1,160,935✔
716
                        default:
41,180,712✔
717
                                if c.argBuf != nil {
41,884,474✔
718
                                        c.argBuf = append(c.argBuf, b)
703,762✔
719
                                }
703,762✔
720
                        }
721
                case OP_L:
57,124✔
722
                        switch b {
57,124✔
723
                        case 'S', 's':
44,315✔
724
                                c.state = OP_LS
44,315✔
725
                        case 'M', 'm':
12,809✔
726
                                c.state = OP_M
12,809✔
727
                        default:
×
728
                                goto parseErr
×
729
                        }
730
                case OP_LS:
44,315✔
731
                        switch b {
44,315✔
732
                        case '+':
33,720✔
733
                                c.state = OP_SUB
33,720✔
734
                        case '-':
10,595✔
735
                                c.state = OP_UNSUB
10,595✔
736
                        default:
×
737
                                goto parseErr
×
738
                        }
739
                case OP_R:
9,677,403✔
740
                        switch b {
9,677,403✔
741
                        case 'S', 's':
1,198,983✔
742
                                c.state = OP_RS
1,198,983✔
743
                        case 'M', 'm':
8,478,420✔
744
                                c.state = OP_M
8,478,420✔
745
                        default:
×
746
                                goto parseErr
×
747
                        }
748
                case OP_RS:
1,198,982✔
749
                        switch b {
1,198,982✔
750
                        case '+':
996,649✔
751
                                c.state = OP_SUB
996,649✔
752
                        case '-':
202,333✔
753
                                c.state = OP_UNSUB
202,333✔
754
                        default:
×
755
                                goto parseErr
×
756
                        }
757
                case OP_U:
12,725✔
758
                        switch b {
12,725✔
759
                        case 'N', 'n':
12,725✔
760
                                c.state = OP_UN
12,725✔
761
                        default:
×
762
                                goto parseErr
×
763
                        }
764
                case OP_UN:
12,725✔
765
                        switch b {
12,725✔
766
                        case 'S', 's':
12,725✔
767
                                c.state = OP_UNS
12,725✔
768
                        default:
×
769
                                goto parseErr
×
770
                        }
771
                case OP_UNS:
12,725✔
772
                        switch b {
12,725✔
773
                        case 'U', 'u':
12,725✔
774
                                c.state = OP_UNSU
12,725✔
775
                        default:
×
776
                                goto parseErr
×
777
                        }
778
                case OP_UNSU:
12,725✔
779
                        switch b {
12,725✔
780
                        case 'B', 'b':
12,725✔
781
                                c.state = OP_UNSUB
12,725✔
782
                        default:
×
783
                                goto parseErr
×
784
                        }
785
                case OP_UNSUB:
225,653✔
786
                        switch b {
225,653✔
787
                        case ' ', '\t':
225,653✔
788
                                c.state = OP_UNSUB_SPC
225,653✔
789
                        default:
×
790
                                goto parseErr
×
791
                        }
792
                case OP_UNSUB_SPC:
225,653✔
793
                        switch b {
225,653✔
794
                        case ' ', '\t':
×
795
                                continue
×
796
                        default:
225,653✔
797
                                c.state = UNSUB_ARG
225,653✔
798
                                c.as = i
225,653✔
799
                        }
800
                case UNSUB_ARG:
6,582,659✔
801
                        switch b {
6,582,659✔
802
                        case '\r':
225,647✔
803
                                c.drop = 1
225,647✔
804
                        case '\n':
225,645✔
805
                                var arg []byte
225,645✔
806
                                if c.argBuf != nil {
233,148✔
807
                                        arg = c.argBuf
7,503✔
808
                                        c.argBuf = nil
7,503✔
809
                                } else {
225,645✔
810
                                        arg = buf[c.as : i-c.drop]
218,142✔
811
                                }
218,142✔
812
                                if err := c.overMaxControlLineLimit(arg, mcl); err != nil {
225,645✔
813
                                        return err
×
814
                                }
×
815
                                var err error
225,645✔
816

225,645✔
817
                                switch c.kind {
225,645✔
818
                                case CLIENT:
12,725✔
819
                                        if trace {
23,338✔
820
                                                c.traceInOp("UNSUB", arg)
10,613✔
821
                                        }
10,613✔
822
                                        err = c.processUnsub(arg)
12,725✔
823
                                case ROUTER:
172,035✔
824
                                        if trace && c.srv != nil {
172,060✔
825
                                                switch c.op {
25✔
826
                                                case 'R', 'r':
25✔
827
                                                        c.traceInOp("RS-", arg)
25✔
828
                                                case 'L', 'l':
×
829
                                                        c.traceInOp("LS-", arg)
×
830
                                                }
831
                                        }
832
                                        leafUnsub := c.op == 'L' || c.op == 'l'
172,035✔
833
                                        err = c.processRemoteUnsub(arg, leafUnsub)
172,035✔
834
                                case GATEWAY:
38,731✔
835
                                        if trace {
38,891✔
836
                                                c.traceInOp("RS-", arg)
160✔
837
                                        }
160✔
838
                                        err = c.processGatewayRUnsub(arg)
38,731✔
839
                                case LEAF:
2,154✔
840
                                        if trace {
2,155✔
841
                                                c.traceInOp("LS-", arg)
1✔
842
                                        }
1✔
843
                                        err = c.processLeafUnsub(arg)
2,154✔
844
                                }
845
                                if err != nil {
225,645✔
846
                                        return err
×
847
                                }
×
848
                                c.drop, c.as, c.state = 0, i+1, OP_START
225,645✔
849
                        default:
6,131,367✔
850
                                if c.argBuf != nil {
6,299,381✔
851
                                        c.argBuf = append(c.argBuf, b)
168,014✔
852
                                }
168,014✔
853
                        }
854
                case OP_PI:
39,825✔
855
                        switch b {
39,825✔
856
                        case 'N', 'n':
39,825✔
857
                                c.state = OP_PIN
39,825✔
858
                        default:
×
859
                                goto parseErr
×
860
                        }
861
                case OP_PIN:
39,825✔
862
                        switch b {
39,825✔
863
                        case 'G', 'g':
39,825✔
864
                                c.state = OP_PING
39,825✔
865
                        default:
×
866
                                goto parseErr
×
867
                        }
868
                case OP_PING:
79,650✔
869
                        switch b {
79,650✔
870
                        case '\n':
39,825✔
871
                                if trace {
40,250✔
872
                                        c.traceInOp("PING", nil)
425✔
873
                                }
425✔
874
                                c.processPing()
39,825✔
875
                                c.drop, c.state = 0, OP_START
39,825✔
876
                        }
877
                case OP_PO:
31,307✔
878
                        switch b {
31,307✔
879
                        case 'N', 'n':
31,307✔
880
                                c.state = OP_PON
31,307✔
881
                        default:
×
882
                                goto parseErr
×
883
                        }
884
                case OP_PON:
31,307✔
885
                        switch b {
31,307✔
886
                        case 'G', 'g':
31,307✔
887
                                c.state = OP_PONG
31,307✔
888
                        default:
×
889
                                goto parseErr
×
890
                        }
891
                case OP_PONG:
62,614✔
892
                        switch b {
62,614✔
893
                        case '\n':
31,307✔
894
                                if trace {
31,315✔
895
                                        c.traceInOp("PONG", nil)
8✔
896
                                }
8✔
897
                                c.processPong()
31,307✔
898
                                c.drop, c.state = 0, OP_START
31,307✔
899
                        }
900
                case OP_C:
42,565✔
901
                        switch b {
42,565✔
902
                        case 'O', 'o':
42,565✔
903
                                c.state = OP_CO
42,565✔
904
                        default:
×
905
                                goto parseErr
×
906
                        }
907
                case OP_CO:
42,565✔
908
                        switch b {
42,565✔
909
                        case 'N', 'n':
42,565✔
910
                                c.state = OP_CON
42,565✔
911
                        default:
×
912
                                goto parseErr
×
913
                        }
914
                case OP_CON:
42,565✔
915
                        switch b {
42,565✔
916
                        case 'N', 'n':
42,565✔
917
                                c.state = OP_CONN
42,565✔
918
                        default:
×
919
                                goto parseErr
×
920
                        }
921
                case OP_CONN:
42,565✔
922
                        switch b {
42,565✔
923
                        case 'E', 'e':
42,565✔
924
                                c.state = OP_CONNE
42,565✔
925
                        default:
×
926
                                goto parseErr
×
927
                        }
928
                case OP_CONNE:
42,565✔
929
                        switch b {
42,565✔
930
                        case 'C', 'c':
42,565✔
931
                                c.state = OP_CONNEC
42,565✔
932
                        default:
×
933
                                goto parseErr
×
934
                        }
935
                case OP_CONNEC:
42,565✔
936
                        switch b {
42,565✔
937
                        case 'T', 't':
42,565✔
938
                                c.state = OP_CONNECT
42,565✔
939
                        default:
×
940
                                goto parseErr
×
941
                        }
942
                case OP_CONNECT:
85,130✔
943
                        switch b {
85,130✔
944
                        case ' ', '\t':
42,565✔
945
                                continue
42,565✔
946
                        default:
42,565✔
947
                                c.state = CONNECT_ARG
42,565✔
948
                                c.as = i
42,565✔
949
                        }
950
                case CONNECT_ARG:
7,767,743✔
951
                        switch b {
7,767,743✔
952
                        case '\r':
42,565✔
953
                                c.drop = 1
42,565✔
954
                        case '\n':
42,565✔
955
                                var arg []byte
42,565✔
956
                                if c.argBuf != nil {
43,056✔
957
                                        arg = c.argBuf
491✔
958
                                        c.argBuf = nil
491✔
959
                                } else {
42,565✔
960
                                        arg = buf[c.as : i-c.drop]
42,074✔
961
                                }
42,074✔
962
                                if err := c.overMaxControlLineLimit(arg, mcl); err != nil {
42,565✔
963
                                        return err
×
964
                                }
×
965
                                if trace {
42,992✔
966
                                        c.traceInOp("CONNECT", removeSecretsFromTrace(arg))
427✔
967
                                }
427✔
968
                                if err := c.processConnect(arg); err != nil {
42,818✔
969
                                        return err
253✔
970
                                }
253✔
971
                                c.drop, c.state = 0, OP_START
42,312✔
972
                                // Reset notion on authSet
42,312✔
973
                                c.mu.Lock()
42,312✔
974
                                authSet = c.awaitingAuth()
42,312✔
975
                                c.mu.Unlock()
42,312✔
976
                        default:
7,682,613✔
977
                                if c.argBuf != nil {
7,828,466✔
978
                                        c.argBuf = append(c.argBuf, b)
145,853✔
979
                                }
145,853✔
980
                        }
981
                case OP_M:
8,491,229✔
982
                        switch b {
8,491,229✔
983
                        case 'S', 's':
8,491,229✔
984
                                c.state = OP_MS
8,491,229✔
985
                        default:
×
986
                                goto parseErr
×
987
                        }
988
                case OP_MS:
8,491,229✔
989
                        switch b {
8,491,229✔
990
                        case 'G', 'g':
8,491,229✔
991
                                c.state = OP_MSG
8,491,229✔
992
                        default:
×
993
                                goto parseErr
×
994
                        }
995
                case OP_MSG:
8,491,229✔
996
                        switch b {
8,491,229✔
997
                        case ' ', '\t':
8,491,229✔
998
                                c.state = OP_MSG_SPC
8,491,229✔
999
                        default:
×
1000
                                goto parseErr
×
1001
                        }
1002
                case OP_MSG_SPC:
8,491,229✔
1003
                        switch b {
8,491,229✔
1004
                        case ' ', '\t':
×
1005
                                continue
×
1006
                        default:
8,491,229✔
1007
                                c.pa.hdr = -1
8,491,229✔
1008
                                c.state = MSG_ARG
8,491,229✔
1009
                                c.as = i
8,491,229✔
1010
                        }
1011
                case MSG_ARG:
293,764,516✔
1012
                        switch b {
293,764,516✔
1013
                        case '\r':
8,491,227✔
1014
                                c.drop = 1
8,491,227✔
1015
                        case '\n':
8,491,227✔
1016
                                var arg []byte
8,491,227✔
1017
                                if c.argBuf != nil {
8,791,716✔
1018
                                        arg = c.argBuf
300,489✔
1019
                                        c.argBuf = nil
300,489✔
1020
                                } else {
8,491,227✔
1021
                                        arg = buf[c.as : i-c.drop]
8,190,738✔
1022
                                }
8,190,738✔
1023
                                if err := c.overMaxControlLineLimit(arg, mcl); err != nil {
8,491,227✔
1024
                                        return err
×
1025
                                }
×
1026
                                var err error
8,491,227✔
1027
                                if c.kind == ROUTER || c.kind == GATEWAY {
16,971,459✔
1028
                                        switch c.op {
8,480,232✔
1029
                                        case 'R', 'r':
8,478,418✔
1030
                                                if trace {
8,482,642✔
1031
                                                        c.traceInOp("RMSG", arg)
4,224✔
1032
                                                }
4,224✔
1033
                                                err = c.processRoutedMsgArgs(arg)
8,478,418✔
1034
                                        case 'L', 'l':
1,814✔
1035
                                                if trace {
1,814✔
1036
                                                        c.traceInOp("LMSG", arg)
×
1037
                                                }
×
1038
                                                lmsg = true
1,814✔
1039
                                                err = c.processRoutedOriginClusterMsgArgs(arg)
1,814✔
1040
                                        }
1041
                                } else if c.kind == LEAF {
21,990✔
1042
                                        if trace {
10,995✔
1043
                                                c.traceInOp("LMSG", arg)
×
1044
                                        }
×
1045
                                        err = c.processLeafMsgArgs(arg)
10,995✔
1046
                                }
1047
                                if err != nil {
8,491,228✔
1048
                                        return err
1✔
1049
                                }
1✔
1050
                                c.drop, c.as, c.state = 0, i+1, MSG_PAYLOAD
8,491,226✔
1051

8,491,226✔
1052
                                // jump ahead with the index. If this overruns
8,491,226✔
1053
                                // what is left we fall out and process split
8,491,226✔
1054
                                // buffer.
8,491,226✔
1055
                                i = c.as + c.pa.size - LEN_CR_LF
8,491,226✔
1056
                        default:
276,782,062✔
1057
                                if c.argBuf != nil {
280,097,593✔
1058
                                        c.argBuf = append(c.argBuf, b)
3,315,531✔
1059
                                }
3,315,531✔
1060
                        }
1061
                case OP_I:
87,696✔
1062
                        switch b {
87,696✔
1063
                        case 'N', 'n':
87,696✔
1064
                                c.state = OP_IN
87,696✔
1065
                        default:
×
1066
                                goto parseErr
×
1067
                        }
1068
                case OP_IN:
87,696✔
1069
                        switch b {
87,696✔
1070
                        case 'F', 'f':
87,696✔
1071
                                c.state = OP_INF
87,696✔
1072
                        default:
×
1073
                                goto parseErr
×
1074
                        }
1075
                case OP_INF:
87,696✔
1076
                        switch b {
87,696✔
1077
                        case 'O', 'o':
87,696✔
1078
                                c.state = OP_INFO
87,696✔
1079
                        default:
×
1080
                                goto parseErr
×
1081
                        }
1082
                case OP_INFO:
175,392✔
1083
                        switch b {
175,392✔
1084
                        case ' ', '\t':
87,696✔
1085
                                continue
87,696✔
1086
                        default:
87,696✔
1087
                                c.state = INFO_ARG
87,696✔
1088
                                c.as = i
87,696✔
1089
                        }
1090
                case INFO_ARG:
33,604,951✔
1091
                        switch b {
33,604,951✔
1092
                        case '\r':
87,690✔
1093
                                c.drop = 1
87,690✔
1094
                        case '\n':
87,690✔
1095
                                var arg []byte
87,690✔
1096
                                if c.argBuf != nil {
97,534✔
1097
                                        arg = c.argBuf
9,844✔
1098
                                        c.argBuf = nil
9,844✔
1099
                                } else {
87,690✔
1100
                                        arg = buf[c.as : i-c.drop]
77,846✔
1101
                                }
77,846✔
1102
                                if err := c.overMaxControlLineLimit(arg, mcl); err != nil {
87,690✔
1103
                                        return err
×
1104
                                }
×
1105
                                if err := c.processInfo(arg); err != nil {
87,690✔
1106
                                        return err
×
1107
                                }
×
1108
                                c.drop, c.as, c.state = 0, i+1, OP_START
87,690✔
1109
                        default:
33,429,571✔
1110
                                if c.argBuf != nil {
34,581,060✔
1111
                                        c.argBuf = append(c.argBuf, b)
1,151,489✔
1112
                                }
1,151,489✔
1113
                        }
1114
                case OP_PLUS:
×
1115
                        switch b {
×
1116
                        case 'O', 'o':
×
1117
                                c.state = OP_PLUS_O
×
1118
                        default:
×
1119
                                goto parseErr
×
1120
                        }
1121
                case OP_PLUS_O:
×
1122
                        switch b {
×
1123
                        case 'K', 'k':
×
1124
                                c.state = OP_PLUS_OK
×
1125
                        default:
×
1126
                                goto parseErr
×
1127
                        }
1128
                case OP_PLUS_OK:
×
1129
                        switch b {
×
1130
                        case '\n':
×
1131
                                c.drop, c.state = 0, OP_START
×
1132
                        }
1133
                case OP_MINUS:
141✔
1134
                        switch b {
141✔
1135
                        case 'E', 'e':
141✔
1136
                                c.state = OP_MINUS_E
141✔
1137
                        default:
×
1138
                                goto parseErr
×
1139
                        }
1140
                case OP_MINUS_E:
141✔
1141
                        switch b {
141✔
1142
                        case 'R', 'r':
141✔
1143
                                c.state = OP_MINUS_ER
141✔
1144
                        default:
×
1145
                                goto parseErr
×
1146
                        }
1147
                case OP_MINUS_ER:
141✔
1148
                        switch b {
141✔
1149
                        case 'R', 'r':
141✔
1150
                                c.state = OP_MINUS_ERR
141✔
1151
                        default:
×
1152
                                goto parseErr
×
1153
                        }
1154
                case OP_MINUS_ERR:
141✔
1155
                        switch b {
141✔
1156
                        case ' ', '\t':
141✔
1157
                                c.state = OP_MINUS_ERR_SPC
141✔
1158
                        default:
×
1159
                                goto parseErr
×
1160
                        }
1161
                case OP_MINUS_ERR_SPC:
141✔
1162
                        switch b {
141✔
1163
                        case ' ', '\t':
×
1164
                                continue
×
1165
                        default:
141✔
1166
                                c.state = MINUS_ERR_ARG
141✔
1167
                                c.as = i
141✔
1168
                        }
1169
                case MINUS_ERR_ARG:
5,141✔
1170
                        switch b {
5,141✔
1171
                        case '\r':
141✔
1172
                                c.drop = 1
141✔
1173
                        case '\n':
141✔
1174
                                var arg []byte
141✔
1175
                                if c.argBuf != nil {
142✔
1176
                                        arg = c.argBuf
1✔
1177
                                        c.argBuf = nil
1✔
1178
                                } else {
141✔
1179
                                        arg = buf[c.as : i-c.drop]
140✔
1180
                                }
140✔
1181
                                if err := c.overMaxControlLineLimit(arg, mcl); err != nil {
141✔
1182
                                        return err
×
1183
                                }
×
1184
                                c.processErr(string(arg))
141✔
1185
                                c.drop, c.as, c.state = 0, i+1, OP_START
141✔
1186
                        default:
4,859✔
1187
                                if c.argBuf != nil {
4,887✔
1188
                                        c.argBuf = append(c.argBuf, b)
28✔
1189
                                }
28✔
1190
                        }
1191
                default:
×
1192
                        goto parseErr
×
1193
                }
1194
        }
1195

1196
        // Check for split buffer scenarios for any ARG state.
1197
        if c.state == SUB_ARG || c.state == UNSUB_ARG ||
10,535,576✔
1198
                c.state == PUB_ARG || c.state == HPUB_ARG ||
10,535,576✔
1199
                c.state == ASUB_ARG || c.state == AUSUB_ARG ||
10,535,576✔
1200
                c.state == MSG_ARG || c.state == HMSG_ARG ||
10,535,576✔
1201
                c.state == MINUS_ERR_ARG || c.state == CONNECT_ARG || c.state == INFO_ARG {
10,909,013✔
1202

373,437✔
1203
                // Setup a holder buffer to deal with split buffer scenario.
373,437✔
1204
                if c.argBuf == nil {
746,528✔
1205
                        c.argBuf = c.scratch[:0]
373,091✔
1206
                        c.argBuf = append(c.argBuf, buf[c.as:i-c.drop]...)
373,091✔
1207
                }
373,091✔
1208
                // Check for violations of control line length here. Note that this is not
1209
                // exact at all but the performance hit is too great to be precise, and
1210
                // catching here should prevent memory exhaustion attacks.
1211
                if err := c.overMaxControlLineLimit(c.argBuf, mcl); err != nil {
373,438✔
1212
                        return err
1✔
1213
                }
1✔
1214
        }
1215

1216
        // Check for split msg
1217
        if (c.state == MSG_PAYLOAD || c.state == MSG_END_R || c.state == MSG_END_N) && c.msgBuf == nil {
11,692,315✔
1218
                // We need to clone the pubArg if it is still referencing the
1,156,740✔
1219
                // read buffer and we are not able to process the msg.
1,156,740✔
1220

1,156,740✔
1221
                if c.argBuf == nil {
2,313,480✔
1222
                        // Works also for MSG_ARG, when message comes from ROUTE or GATEWAY.
1,156,740✔
1223
                        if err := c.clonePubArg(lmsg); err != nil {
1,156,740✔
1224
                                goto parseErr
×
1225
                        }
1226
                }
1227

1228
                // If we will overflow the scratch buffer, just create a
1229
                // new buffer to hold the split message.
1230
                if c.pa.size > cap(c.scratch)-len(c.argBuf) {
1,191,619✔
1231
                        lrem := len(buf[c.as:])
34,879✔
1232
                        // Consider it a protocol error when the remaining payload
34,879✔
1233
                        // is larger than the reported size for PUB. It can happen
34,879✔
1234
                        // when processing incomplete messages from rogue clients.
34,879✔
1235
                        if lrem > c.pa.size+LEN_CR_LF {
34,879✔
1236
                                goto parseErr
×
1237
                        }
1238
                        c.msgBuf = make([]byte, lrem, c.pa.size+LEN_CR_LF)
34,879✔
1239
                        copy(c.msgBuf, buf[c.as:])
34,879✔
1240
                } else {
1,121,861✔
1241
                        c.msgBuf = c.scratch[len(c.argBuf):len(c.argBuf)]
1,121,861✔
1242
                        c.msgBuf = append(c.msgBuf, (buf[c.as:])...)
1,121,861✔
1243
                }
1,121,861✔
1244
        }
1245

1246
        return nil
10,535,575✔
1247

10,535,575✔
1248
authErr:
10,535,575✔
1249
        c.authViolation()
23✔
1250
        return ErrAuthentication
23✔
1251

23✔
1252
parseErr:
23✔
1253
        c.sendErr("Unknown Protocol Operation")
4✔
1254
        snip := protoSnippet(i, PROTO_SNIPPET_SIZE, buf)
4✔
1255
        err := fmt.Errorf("%s parser ERROR, state=%d, i=%d: proto='%s...'", c.kindString(), c.state, i, snip)
4✔
1256
        return err
4✔
1257
}
1258

1259
func protoSnippet(start, max int, buf []byte) string {
5✔
1260
        stop := start + max
5✔
1261
        bufSize := len(buf)
5✔
1262
        if start >= bufSize {
5✔
1263
                return `""`
×
1264
        }
×
1265
        if stop > bufSize {
8✔
1266
                stop = bufSize - 1
3✔
1267
        }
3✔
1268
        return fmt.Sprintf("%q", buf[start:stop])
5✔
1269
}
1270

1271
// Check if the length of buffer `arg` is over the max control line limit `mcl`.
1272
// If so, an error is sent to the client and the connection is closed.
1273
// The error ErrMaxControlLine is returned.
1274
func (c *client) overMaxControlLineLimit(arg []byte, mcl int32) error {
15,941,865✔
1275
        // Widen to int64 so mcl*16 cannot overflow for large configured values.
15,941,865✔
1276
        effective := int64(mcl)
15,941,865✔
1277
        if c.kind != CLIENT {
26,773,080✔
1278
                // This is the upper bound on argBuf length for LEAF, ROUTER, and GATEWAY connections.
10,831,215✔
1279
                // These kinds need longer arg lines than CLIENT (which is capped at mcl=4096 by default)
10,831,215✔
1280
                // because cluster/leaf frames encode origin, account, reply, and queue groups.
10,831,215✔
1281
                // By default, this is 64 KB, which matches maxBufSize so a single oversized read
10,831,215✔
1282
                // is caught on the very next parse call.
10,831,215✔
1283
                effective *= 16
10,831,215✔
1284
        }
10,831,215✔
1285
        if int64(len(arg)) > effective {
15,941,866✔
1286
                err := NewErrorCtx(ErrMaxControlLine, "State %d, max_control_line %d, Buffer len %d (snip: %s...)",
1✔
1287
                        c.state, int(mcl), len(c.argBuf), protoSnippet(0, MAX_CONTROL_LINE_SNIPPET_SIZE, arg))
1✔
1288
                c.sendErr(err.Error())
1✔
1289
                c.closeConnection(MaxControlLineExceeded)
1✔
1290
                return err
1✔
1291
        }
1✔
1292
        return nil
15,941,864✔
1293
}
1294

1295
// clonePubArg is used when the split buffer scenario has the pubArg in the existing read buffer, but
1296
// we need to hold onto it into the next read.
1297
func (c *client) clonePubArg(lmsg bool) error {
1,156,740✔
1298
        // Just copy and re-process original arg buffer.
1,156,740✔
1299
        c.argBuf = c.scratch[:0]
1,156,740✔
1300
        c.argBuf = append(c.argBuf, c.pa.arg...)
1,156,740✔
1301

1,156,740✔
1302
        switch c.kind {
1,156,740✔
1303
        case ROUTER, GATEWAY:
1,065,836✔
1304
                if lmsg {
1,066,314✔
1305
                        return c.processRoutedOriginClusterMsgArgs(c.argBuf)
478✔
1306
                }
478✔
1307
                if c.pa.hdr < 0 {
1,956,110✔
1308
                        return c.processRoutedMsgArgs(c.argBuf)
890,752✔
1309
                } else {
1,065,358✔
1310
                        return c.processRoutedHeaderMsgArgs(c.argBuf)
174,606✔
1311
                }
174,606✔
1312
        case LEAF:
987✔
1313
                if c.pa.hdr < 0 {
1,910✔
1314
                        return c.processLeafMsgArgs(c.argBuf)
923✔
1315
                } else {
987✔
1316
                        return c.processLeafHeaderMsgArgs(c.argBuf)
64✔
1317
                }
64✔
1318
        default:
89,917✔
1319
                if c.pa.hdr < 0 {
131,564✔
1320
                        return c.processPub(c.argBuf)
41,647✔
1321
                } else {
89,917✔
1322
                        return c.processHeaderPub(c.argBuf, nil)
48,270✔
1323
                }
48,270✔
1324
        }
1325
}
1326

1327
func (ps *parseState) getHeader() http.Header {
821✔
1328
        if ps.header == nil {
1,642✔
1329
                if hdr := ps.pa.hdr; hdr > 0 {
892✔
1330
                        reader := bufio.NewReader(bytes.NewReader(ps.msgBuf[0:hdr]))
71✔
1331
                        tp := textproto.NewReader(reader)
71✔
1332
                        tp.ReadLine() // skip over first line, contains version
71✔
1333
                        if mimeHeader, err := tp.ReadMIMEHeader(); err == nil {
142✔
1334
                                ps.header = http.Header(mimeHeader)
71✔
1335
                        }
71✔
1336
                }
1337
        }
1338
        return ps.header
821✔
1339
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc