xref: /aosp_15_r20/external/golang-protobuf/encoding/protodelim/protodelim.go (revision 1c12ee1efe575feb122dbf939ff15148a3b3e8f2)
1*1c12ee1eSDan Willemsen// Copyright 2022 The Go Authors. All rights reserved.
2*1c12ee1eSDan Willemsen// Use of this source code is governed by a BSD-style
3*1c12ee1eSDan Willemsen// license that can be found in the LICENSE file.
4*1c12ee1eSDan Willemsen
5*1c12ee1eSDan Willemsen// Package protodelim marshals and unmarshals varint size-delimited messages.
6*1c12ee1eSDan Willemsenpackage protodelim
7*1c12ee1eSDan Willemsen
8*1c12ee1eSDan Willemsenimport (
9*1c12ee1eSDan Willemsen	"encoding/binary"
10*1c12ee1eSDan Willemsen	"fmt"
11*1c12ee1eSDan Willemsen	"io"
12*1c12ee1eSDan Willemsen
13*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/encoding/protowire"
14*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/internal/errors"
15*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/proto"
16*1c12ee1eSDan Willemsen)
17*1c12ee1eSDan Willemsen
18*1c12ee1eSDan Willemsen// MarshalOptions is a configurable varint size-delimited marshaler.
19*1c12ee1eSDan Willemsentype MarshalOptions struct{ proto.MarshalOptions }
20*1c12ee1eSDan Willemsen
21*1c12ee1eSDan Willemsen// MarshalTo writes a varint size-delimited wire-format message to w.
22*1c12ee1eSDan Willemsen// If w returns an error, MarshalTo returns it unchanged.
23*1c12ee1eSDan Willemsenfunc (o MarshalOptions) MarshalTo(w io.Writer, m proto.Message) (int, error) {
24*1c12ee1eSDan Willemsen	msgBytes, err := o.MarshalOptions.Marshal(m)
25*1c12ee1eSDan Willemsen	if err != nil {
26*1c12ee1eSDan Willemsen		return 0, err
27*1c12ee1eSDan Willemsen	}
28*1c12ee1eSDan Willemsen
29*1c12ee1eSDan Willemsen	sizeBytes := protowire.AppendVarint(nil, uint64(len(msgBytes)))
30*1c12ee1eSDan Willemsen	sizeWritten, err := w.Write(sizeBytes)
31*1c12ee1eSDan Willemsen	if err != nil {
32*1c12ee1eSDan Willemsen		return sizeWritten, err
33*1c12ee1eSDan Willemsen	}
34*1c12ee1eSDan Willemsen	msgWritten, err := w.Write(msgBytes)
35*1c12ee1eSDan Willemsen	if err != nil {
36*1c12ee1eSDan Willemsen		return sizeWritten + msgWritten, err
37*1c12ee1eSDan Willemsen	}
38*1c12ee1eSDan Willemsen	return sizeWritten + msgWritten, nil
39*1c12ee1eSDan Willemsen}
40*1c12ee1eSDan Willemsen
41*1c12ee1eSDan Willemsen// MarshalTo writes a varint size-delimited wire-format message to w
42*1c12ee1eSDan Willemsen// with the default options.
43*1c12ee1eSDan Willemsen//
44*1c12ee1eSDan Willemsen// See the documentation for MarshalOptions.MarshalTo.
45*1c12ee1eSDan Willemsenfunc MarshalTo(w io.Writer, m proto.Message) (int, error) {
46*1c12ee1eSDan Willemsen	return MarshalOptions{}.MarshalTo(w, m)
47*1c12ee1eSDan Willemsen}
48*1c12ee1eSDan Willemsen
49*1c12ee1eSDan Willemsen// UnmarshalOptions is a configurable varint size-delimited unmarshaler.
50*1c12ee1eSDan Willemsentype UnmarshalOptions struct {
51*1c12ee1eSDan Willemsen	proto.UnmarshalOptions
52*1c12ee1eSDan Willemsen
53*1c12ee1eSDan Willemsen	// MaxSize is the maximum size in wire-format bytes of a single message.
54*1c12ee1eSDan Willemsen	// Unmarshaling a message larger than MaxSize will return an error.
55*1c12ee1eSDan Willemsen	// A zero MaxSize will default to 4 MiB.
56*1c12ee1eSDan Willemsen	// Setting MaxSize to -1 disables the limit.
57*1c12ee1eSDan Willemsen	MaxSize int64
58*1c12ee1eSDan Willemsen}
59*1c12ee1eSDan Willemsen
60*1c12ee1eSDan Willemsenconst defaultMaxSize = 4 << 20 // 4 MiB, corresponds to the default gRPC max request/response size
61*1c12ee1eSDan Willemsen
62*1c12ee1eSDan Willemsen// SizeTooLargeError is an error that is returned when the unmarshaler encounters a message size
63*1c12ee1eSDan Willemsen// that is larger than its configured MaxSize.
64*1c12ee1eSDan Willemsentype SizeTooLargeError struct {
65*1c12ee1eSDan Willemsen	// Size is the varint size of the message encountered
66*1c12ee1eSDan Willemsen	// that was larger than the provided MaxSize.
67*1c12ee1eSDan Willemsen	Size uint64
68*1c12ee1eSDan Willemsen
69*1c12ee1eSDan Willemsen	// MaxSize is the MaxSize limit configured in UnmarshalOptions, which Size exceeded.
70*1c12ee1eSDan Willemsen	MaxSize uint64
71*1c12ee1eSDan Willemsen}
72*1c12ee1eSDan Willemsen
73*1c12ee1eSDan Willemsenfunc (e *SizeTooLargeError) Error() string {
74*1c12ee1eSDan Willemsen	return fmt.Sprintf("message size %d exceeded unmarshaler's maximum configured size %d", e.Size, e.MaxSize)
75*1c12ee1eSDan Willemsen}
76*1c12ee1eSDan Willemsen
77*1c12ee1eSDan Willemsen// Reader is the interface expected by UnmarshalFrom.
78*1c12ee1eSDan Willemsen// It is implemented by *bufio.Reader.
79*1c12ee1eSDan Willemsentype Reader interface {
80*1c12ee1eSDan Willemsen	io.Reader
81*1c12ee1eSDan Willemsen	io.ByteReader
82*1c12ee1eSDan Willemsen}
83*1c12ee1eSDan Willemsen
84*1c12ee1eSDan Willemsen// UnmarshalFrom parses and consumes a varint size-delimited wire-format message
85*1c12ee1eSDan Willemsen// from r.
86*1c12ee1eSDan Willemsen// The provided message must be mutable (e.g., a non-nil pointer to a message).
87*1c12ee1eSDan Willemsen//
88*1c12ee1eSDan Willemsen// The error is io.EOF error only if no bytes are read.
89*1c12ee1eSDan Willemsen// If an EOF happens after reading some but not all the bytes,
90*1c12ee1eSDan Willemsen// UnmarshalFrom returns a non-io.EOF error.
91*1c12ee1eSDan Willemsen// In particular if r returns a non-io.EOF error, UnmarshalFrom returns it unchanged,
92*1c12ee1eSDan Willemsen// and if only a size is read with no subsequent message, io.ErrUnexpectedEOF is returned.
93*1c12ee1eSDan Willemsenfunc (o UnmarshalOptions) UnmarshalFrom(r Reader, m proto.Message) error {
94*1c12ee1eSDan Willemsen	var sizeArr [binary.MaxVarintLen64]byte
95*1c12ee1eSDan Willemsen	sizeBuf := sizeArr[:0]
96*1c12ee1eSDan Willemsen	for i := range sizeArr {
97*1c12ee1eSDan Willemsen		b, err := r.ReadByte()
98*1c12ee1eSDan Willemsen		if err != nil && (err != io.EOF || i == 0) {
99*1c12ee1eSDan Willemsen			return err
100*1c12ee1eSDan Willemsen		}
101*1c12ee1eSDan Willemsen		sizeBuf = append(sizeBuf, b)
102*1c12ee1eSDan Willemsen		if b < 0x80 {
103*1c12ee1eSDan Willemsen			break
104*1c12ee1eSDan Willemsen		}
105*1c12ee1eSDan Willemsen	}
106*1c12ee1eSDan Willemsen	size, n := protowire.ConsumeVarint(sizeBuf)
107*1c12ee1eSDan Willemsen	if n < 0 {
108*1c12ee1eSDan Willemsen		return protowire.ParseError(n)
109*1c12ee1eSDan Willemsen	}
110*1c12ee1eSDan Willemsen
111*1c12ee1eSDan Willemsen	maxSize := o.MaxSize
112*1c12ee1eSDan Willemsen	if maxSize == 0 {
113*1c12ee1eSDan Willemsen		maxSize = defaultMaxSize
114*1c12ee1eSDan Willemsen	}
115*1c12ee1eSDan Willemsen	if maxSize != -1 && size > uint64(maxSize) {
116*1c12ee1eSDan Willemsen		return errors.Wrap(&SizeTooLargeError{Size: size, MaxSize: uint64(maxSize)}, "")
117*1c12ee1eSDan Willemsen	}
118*1c12ee1eSDan Willemsen
119*1c12ee1eSDan Willemsen	b := make([]byte, size)
120*1c12ee1eSDan Willemsen	_, err := io.ReadFull(r, b)
121*1c12ee1eSDan Willemsen	if err == io.EOF {
122*1c12ee1eSDan Willemsen		return io.ErrUnexpectedEOF
123*1c12ee1eSDan Willemsen	}
124*1c12ee1eSDan Willemsen	if err != nil {
125*1c12ee1eSDan Willemsen		return err
126*1c12ee1eSDan Willemsen	}
127*1c12ee1eSDan Willemsen	if err := o.Unmarshal(b, m); err != nil {
128*1c12ee1eSDan Willemsen		return err
129*1c12ee1eSDan Willemsen	}
130*1c12ee1eSDan Willemsen	return nil
131*1c12ee1eSDan Willemsen}
132*1c12ee1eSDan Willemsen
133*1c12ee1eSDan Willemsen// UnmarshalFrom parses and consumes a varint size-delimited wire-format message
134*1c12ee1eSDan Willemsen// from r with the default options.
135*1c12ee1eSDan Willemsen// The provided message must be mutable (e.g., a non-nil pointer to a message).
136*1c12ee1eSDan Willemsen//
137*1c12ee1eSDan Willemsen// See the documentation for UnmarshalOptions.UnmarshalFrom.
138*1c12ee1eSDan Willemsenfunc UnmarshalFrom(r Reader, m proto.Message) error {
139*1c12ee1eSDan Willemsen	return UnmarshalOptions{}.UnmarshalFrom(r, m)
140*1c12ee1eSDan Willemsen}
141