-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnetstring.go
116 lines (94 loc) · 1.89 KB
/
netstring.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
package netstring
import (
"bufio"
"bytes"
"errors"
"fmt"
"io"
"strconv"
)
// We use Semantic Versioning v2.0.0
// More information: http://semver.org/
const Version = "2.0.0"
const (
// Prefix that comes after total string size
prefixCh = ':'
// Suffix that denotes end of netstring
suffixCh = ','
)
func Parse(r *bufio.Reader) ([]byte, error) {
strLen, err := parseLen(r)
if err != nil {
return []byte{}, err
}
b, err := parseStr(r, strLen)
if err != nil {
return []byte{}, err
}
if err = stripSuffix(r); err != nil {
return []byte{}, err
}
return b, nil
}
func parseLen(r *bufio.Reader) (int, error) {
var b byte
var err error
var strLen int
var bytesRead int
for {
b, err = r.ReadByte()
if err != nil {
return 0, err
}
bytesRead++
if b == '0' && bytesRead == 1 {
if !assertPrefixAhead(r) {
return 0, errors.New("leading zeros at the front of length are prohibited")
}
} else if b == prefixCh {
break
} else if b < '0' || b > '9' {
return 0, fmt.Errorf(
"length number %d is not in the range of 0-9",
int(b-'0'),
)
}
strLen = strLen*10 + int(b-'0')
}
return strLen, err
}
func assertPrefixAhead(r *bufio.Reader) bool {
peek, err := r.Peek(1)
if err != nil {
return false
}
return peek[0] == prefixCh
}
func parseStr(r *bufio.Reader, len int) ([]byte, error) {
b, err := io.ReadAll(io.LimitReader(r, int64(len)))
if err != nil {
return []byte{}, err
}
return b, nil
}
func stripSuffix(r *bufio.Reader) error {
suffix, err := r.ReadByte()
if err != nil {
return err
}
if suffix != suffixCh {
return fmt.Errorf(
"unexpected suffix %c, wanted %c",
suffix, suffixCh,
)
}
return nil
}
func Pack(str []byte) ([]byte, error) {
var buf bytes.Buffer
buf.Write([]byte(strconv.FormatInt(int64(len(str)), 10)))
buf.WriteByte(prefixCh)
buf.Write([]byte(str))
buf.WriteByte(suffixCh)
return buf.Bytes(), nil
}