-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathnative_body_codec.go
More file actions
56 lines (46 loc) · 1.66 KB
/
Copy pathnative_body_codec.go
File metadata and controls
56 lines (46 loc) · 1.66 KB
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
package main
import (
"bytes"
"encoding/base64"
"errors"
"fmt"
)
const qoderBodyAlphabet = "_doRTgHZBKcGVjlvpC,@aFSx#DPuNJme&i*MzLOEn)sUrthbf%Y^w.(kIQyXqWA!"
var qoderBodyBase64 = base64.NewEncoding(qoderBodyAlphabet).WithPadding('$').Strict()
type nativeBodyCodec struct{}
func (nativeBodyCodec) Encode(raw []byte) ([]byte, error) {
encoded := make([]byte, qoderBodyBase64.EncodedLen(len(raw)))
qoderBodyBase64.Encode(encoded, raw)
return swapOuterThirds(encoded), nil
}
func (nativeBodyCodec) Decode(encoded []byte) ([]byte, error) {
if bytes.IndexByte(encoded, '\r') >= 0 || bytes.IndexByte(encoded, '\n') >= 0 {
return nil, invalidNativeBodyError(errors.New("encoded body contains a line break"))
}
base64Body := swapOuterThirds(encoded)
decoded := make([]byte, qoderBodyBase64.DecodedLen(len(base64Body)))
decodedLen, err := qoderBodyBase64.Decode(decoded, base64Body)
if err != nil {
return nil, invalidNativeBodyError(fmt.Errorf("strict base64 decode: %w", err))
}
decoded = decoded[:decodedLen]
canonical, err := (nativeBodyCodec{}).Encode(decoded)
if err != nil {
return nil, invalidNativeBodyError(fmt.Errorf("canonical body encode: %w", err))
}
if !bytes.Equal(canonical, encoded) {
return nil, invalidNativeBodyError(errors.New("encoded body is not canonical"))
}
return decoded, nil
}
func invalidNativeBodyError(internal error) error {
return newProtocolError(protocolInvalidInput, "protocol body is invalid", internal)
}
func swapOuterThirds(src []byte) []byte {
q := len(src) / 3
out := make([]byte, 0, len(src))
out = append(out, src[len(src)-q:]...)
out = append(out, src[q:len(src)-q]...)
out = append(out, src[:q]...)
return out
}