github.com/rootless-containers/rootlesskit/v2@v2.3.4/pkg/lowlevelmsgutil/lowlevelmsgutil.go (about) 1 // Package lowlevelmsgutil provides utility for JSON message with uint32le header 2 package lowlevelmsgutil 3 4 import ( 5 "bytes" 6 "encoding/binary" 7 "encoding/json" 8 "fmt" 9 "io" 10 ) 11 12 const ( 13 maxLength = 1 << 16 14 ) 15 16 func MarshalToWriter(w io.Writer, x interface{}) (int, error) { 17 b, err := json.Marshal(x) 18 if err != nil { 19 return 0, err 20 } 21 if len(b) > maxLength { 22 return 0, fmt.Errorf("bad message length: %d (max: %d)", len(b), maxLength) 23 } 24 h := make([]byte, 4) 25 binary.LittleEndian.PutUint32(h, uint32(len(b))) 26 return w.Write(append(h, b...)) 27 } 28 29 func UnmarshalFromReader(r io.Reader, x interface{}) (int, error) { 30 hdr := make([]byte, 4) 31 n, err := r.Read(hdr) 32 if err != nil { 33 return n, err 34 } 35 if n != 4 { 36 return n, fmt.Errorf("read %d bytes, expected 4 bytes", n) 37 } 38 bLen := binary.LittleEndian.Uint32(hdr) 39 if bLen > maxLength || bLen < 1 { 40 return n, fmt.Errorf("bad message length: %d (max: %d)", bLen, maxLength) 41 } 42 b := make([]byte, bLen) 43 n, err = r.Read(b) 44 if err != nil { 45 return 4 + n, err 46 } 47 if n != int(bLen) { 48 return 4 + n, fmt.Errorf("read %d bytes, expected %d bytes", n, bLen) 49 } 50 return 4 + n, json.Unmarshal(b, x) 51 } 52 53 func Marshal(x interface{}) ([]byte, error) { 54 var b bytes.Buffer 55 _, err := MarshalToWriter(&b, x) 56 return b.Bytes(), err 57 } 58 59 func Unmarshal(b []byte, x interface{}) error { 60 n, err := UnmarshalFromReader(bytes.NewReader(b), x) 61 if n != len(b) { 62 return fmt.Errorf("read %d bytes, expected %d bytes", n, len(b)) 63 } 64 return err 65 }