Skip to content

Commit 9278ccf

Browse files
committed
Initial commit
0 parents  commit 9278ccf

31 files changed

+2004
-0
lines changed

.github/workflows/go.yml

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# This workflow will build a golang project
2+
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go
3+
4+
name: Go
5+
6+
on:
7+
push:
8+
branches: [ "master" ]
9+
pull_request:
10+
branches: [ "master" ]
11+
12+
jobs:
13+
lint:
14+
runs-on: ubuntu-latest
15+
steps:
16+
- uses: actions/checkout@v3
17+
- uses: dominikh/staticcheck-action@v1.3.0
18+
19+
build:
20+
runs-on: ubuntu-latest
21+
steps:
22+
- uses: actions/checkout@v3
23+
24+
- name: Set up Go
25+
uses: actions/setup-go@v4
26+
with:
27+
go-version: '1.20'
28+
29+
- name: Build
30+
run: go build -v ./...
31+
32+
test:
33+
runs-on: ubuntu-latest
34+
steps:
35+
- uses: actions/checkout@v3
36+
37+
- name: Set up Go
38+
uses: actions/setup-go@v4
39+
with:
40+
go-version: '1.20'
41+
42+
- name: Test
43+
run: go test -v ./...
44+
45+
e2e:
46+
runs-on: ubuntu-latest
47+
steps:
48+
- uses: actions/checkout@v3
49+
50+
- name: Set up Go
51+
uses: actions/setup-go@v4
52+
with:
53+
go-version: '1.20'
54+
55+
- name: setup environment
56+
run: |
57+
sudo apt-get install -y software-properties-common
58+
sudo add-apt-repository -y ppa:vbernat/haproxy-2.8
59+
sudo apt-get update
60+
sudo apt-get install -y haproxy
61+
haproxy -vv
62+
63+
- name: Test E2E
64+
run: go test -v ./... --tags=e2e

.gitignore

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Created by https://www.toptal.com/developers/gitignore/api/go,direnv
2+
# Edit at https://www.toptal.com/developers/gitignore?templates=go,direnv
3+
4+
### direnv ###
5+
.direnv
6+
.envrc
7+
8+
### Go ###
9+
# If you prefer the allow list template instead of the deny list, see community template:
10+
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
11+
#
12+
# Binaries for programs and plugins
13+
*.exe
14+
*.exe~
15+
*.dll
16+
*.so
17+
*.dylib
18+
19+
# Test binary, built with `go test -c`
20+
*.test
21+
22+
# Output of the go coverage tool, specifically when used with LiteIDE
23+
*.out
24+
25+
# Dependency directories (remove the comment below to include it)
26+
# vendor/
27+
28+
# Go workspace file
29+
go.work
30+
31+
### Go Patch ###
32+
/vendor/
33+
/Godeps/
34+
35+
# End of https://www.toptal.com/developers/gitignore/api/go,direnv
36+
37+
### Intellij ###
38+
39+
.idea
40+
*.iml

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# HAProxy Protocols in Go
2+

go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module github.com/fionera/haproxy-go
2+
3+
go 1.20

go.sum

Whitespace-only changes.

pkg/buffer/slicebuf.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package buffer
2+
3+
type SliceBuffer struct {
4+
readOffset int
5+
writeOffset int
6+
buf []byte
7+
}
8+
9+
func NewSliceBuffer(size int) *SliceBuffer {
10+
return &SliceBuffer{
11+
buf: make([]byte, size),
12+
}
13+
}
14+
15+
func (s *SliceBuffer) Reset() {
16+
s.readOffset = 0
17+
s.writeOffset = 0
18+
}
19+
20+
func (s *SliceBuffer) ReadBytes() []byte {
21+
return s.buf[s.readOffset:s.writeOffset]
22+
}
23+
24+
func (s *SliceBuffer) WriteBytes() []byte {
25+
return s.buf[s.writeOffset:]
26+
}
27+
28+
func (s *SliceBuffer) AdvanceR(n int) {
29+
s.readOffset += n
30+
}
31+
32+
func (s *SliceBuffer) AdvanceW(n int) {
33+
s.writeOffset += n
34+
}
35+
36+
func (s *SliceBuffer) WriteNBytes(n int) []byte {
37+
s.writeOffset += n
38+
return s.buf[s.writeOffset-n : s.writeOffset]
39+
}
40+
41+
func (s *SliceBuffer) ReadNBytes(n int) []byte {
42+
s.readOffset += n
43+
return s.buf[s.readOffset-n : s.readOffset]
44+
}
45+
46+
func (s *SliceBuffer) Len() int {
47+
return s.writeOffset - s.readOffset
48+
}

pkg/encoding/other.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package encoding
2+
3+
import (
4+
"net/netip"
5+
)
6+
7+
func PutBytes(b []byte, v []byte) (int, error) {
8+
l := len(v)
9+
n, err := PutVarint(b, int64(l))
10+
if err != nil {
11+
return 0, err
12+
}
13+
14+
if l+n > len(b) {
15+
return 0, ErrInsufficientSpace
16+
}
17+
18+
copy(b[n:], v)
19+
return n + l, nil
20+
}
21+
22+
func PutAddr(b []byte, ip netip.Addr) (int, error) {
23+
s := ip.AsSlice()
24+
if len(b) < len(s) {
25+
return 0, ErrInsufficientSpace
26+
}
27+
28+
copy(b, s)
29+
return len(s), nil
30+
}

pkg/encoding/varint.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package encoding
2+
3+
import (
4+
"fmt"
5+
)
6+
7+
var (
8+
ErrUnterminatedSequence = fmt.Errorf("unterminated sequence")
9+
ErrInsufficientSpace = fmt.Errorf("insufficient space in buffer")
10+
)
11+
12+
// Source: https://github.com/criteo/haproxy-spoe-go/blob/master/encoding.go
13+
func PutVarint(b []byte, i int64) (int, error) {
14+
if len(b) == 0 {
15+
return 0, ErrInsufficientSpace
16+
}
17+
18+
if i < 240 {
19+
b[0] = byte(i)
20+
return 1, nil
21+
}
22+
23+
n := 0
24+
b[n] = byte(i) | 240
25+
n++
26+
i = (i - 240) >> 4
27+
for i >= 128 {
28+
if n > len(b)-1 {
29+
return 0, ErrInsufficientSpace
30+
}
31+
32+
b[n] = byte(i) | 128
33+
n++
34+
i = (i - 128) >> 7
35+
}
36+
37+
if n > len(b)-1 {
38+
return 0, ErrInsufficientSpace
39+
}
40+
41+
b[n] = byte(i)
42+
n++
43+
44+
return n, nil
45+
}
46+
47+
// Source: https://github.com/criteo/haproxy-spoe-go/blob/master/encoding.go
48+
func Varint(b []byte) (int64, int, error) {
49+
if len(b) == 0 {
50+
return 0, 0, ErrUnterminatedSequence
51+
}
52+
val := int64(b[0])
53+
off := 1
54+
55+
if val < 240 {
56+
return val, 1, nil
57+
}
58+
59+
r := uint(4)
60+
for {
61+
if off > len(b)-1 {
62+
return 0, 0, ErrUnterminatedSequence
63+
}
64+
65+
v := int64(b[off])
66+
val += v << r
67+
off++
68+
r += 7
69+
70+
if v < 128 {
71+
break
72+
}
73+
}
74+
75+
return val, off, nil
76+
}

pkg/encoding/varint_test.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package encoding
2+
3+
import (
4+
"reflect"
5+
"testing"
6+
)
7+
8+
func Test_encode(t *testing.T) {
9+
type args struct {
10+
val int64
11+
}
12+
tests := []struct {
13+
name string
14+
args args
15+
want []byte
16+
}{
17+
{
18+
name: "",
19+
args: args{
20+
val: 0x1234,
21+
},
22+
want: []byte{0xf4, 0x94, 0x01},
23+
},
24+
}
25+
for _, tt := range tests {
26+
t.Run(tt.name, func(t *testing.T) {
27+
b := make([]byte, 4)
28+
if n, _ := PutVarint(b, tt.args.val); !reflect.DeepEqual(b[:n], tt.want) {
29+
t.Errorf("encode() = %v, want %v", b[:n], tt.want)
30+
}
31+
32+
if got, _, _ := Varint(tt.want); !reflect.DeepEqual(got, tt.args.val) {
33+
t.Errorf("decode() = %v, want %v", got, tt.args.val)
34+
}
35+
})
36+
}
37+
}

0 commit comments

Comments
 (0)