decode.go (4892B)
1 package eventstream 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "encoding/hex" 7 "encoding/json" 8 "fmt" 9 "hash" 10 "hash/crc32" 11 "io" 12 13 "github.com/aws/smithy-go/logging" 14 ) 15 16 // DecoderOptions is the Decoder configuration options. 17 type DecoderOptions struct { 18 Logger logging.Logger 19 LogMessages bool 20 } 21 22 // Decoder provides decoding of an Event Stream messages. 23 type Decoder struct { 24 options DecoderOptions 25 } 26 27 // NewDecoder initializes and returns a Decoder for decoding event 28 // stream messages from the reader provided. 29 func NewDecoder(optFns ...func(*DecoderOptions)) *Decoder { 30 options := DecoderOptions{} 31 32 for _, fn := range optFns { 33 fn(&options) 34 } 35 36 return &Decoder{ 37 options: options, 38 } 39 } 40 41 // Decode attempts to decode a single message from the event stream reader. 42 // Will return the event stream message, or error if decodeMessage fails to read 43 // the message from the stream. 44 // 45 // payloadBuf is a byte slice that will be used in the returned Message.Payload. Callers 46 // must ensure that the Message.Payload from a previous decode has been consumed before passing in the same underlying 47 // payloadBuf byte slice. 48 func (d *Decoder) Decode(reader io.Reader, payloadBuf []byte) (m Message, err error) { 49 if d.options.Logger != nil && d.options.LogMessages { 50 debugMsgBuf := bytes.NewBuffer(nil) 51 reader = io.TeeReader(reader, debugMsgBuf) 52 defer func() { 53 logMessageDecode(d.options.Logger, debugMsgBuf, m, err) 54 }() 55 } 56 57 m, err = decodeMessage(reader, payloadBuf) 58 59 return m, err 60 } 61 62 // decodeMessage attempts to decode a single message from the event stream reader. 63 // Will return the event stream message, or error if decodeMessage fails to read 64 // the message from the reader. 65 func decodeMessage(reader io.Reader, payloadBuf []byte) (m Message, err error) { 66 crc := crc32.New(crc32IEEETable) 67 hashReader := io.TeeReader(reader, crc) 68 69 prelude, err := decodePrelude(hashReader, crc) 70 if err != nil { 71 return Message{}, err 72 } 73 74 if prelude.HeadersLen > 0 { 75 lr := io.LimitReader(hashReader, int64(prelude.HeadersLen)) 76 m.Headers, err = decodeHeaders(lr) 77 if err != nil { 78 return Message{}, err 79 } 80 } 81 82 if payloadLen := prelude.PayloadLen(); payloadLen > 0 { 83 buf, err := decodePayload(payloadBuf, io.LimitReader(hashReader, int64(payloadLen))) 84 if err != nil { 85 return Message{}, err 86 } 87 m.Payload = buf 88 } 89 90 msgCRC := crc.Sum32() 91 if err := validateCRC(reader, msgCRC); err != nil { 92 return Message{}, err 93 } 94 95 return m, nil 96 } 97 98 func logMessageDecode(logger logging.Logger, msgBuf *bytes.Buffer, msg Message, decodeErr error) { 99 w := bytes.NewBuffer(nil) 100 defer func() { logger.Logf(logging.Debug, w.String()) }() 101 102 fmt.Fprintf(w, "Raw message:\n%s\n", 103 hex.Dump(msgBuf.Bytes())) 104 105 if decodeErr != nil { 106 fmt.Fprintf(w, "decodeMessage error: %v\n", decodeErr) 107 return 108 } 109 110 rawMsg, err := msg.rawMessage() 111 if err != nil { 112 fmt.Fprintf(w, "failed to create raw message, %v\n", err) 113 return 114 } 115 116 decodedMsg := decodedMessage{ 117 rawMessage: rawMsg, 118 Headers: decodedHeaders(msg.Headers), 119 } 120 121 fmt.Fprintf(w, "Decoded message:\n") 122 encoder := json.NewEncoder(w) 123 if err := encoder.Encode(decodedMsg); err != nil { 124 fmt.Fprintf(w, "failed to generate decoded message, %v\n", err) 125 } 126 } 127 128 func decodePrelude(r io.Reader, crc hash.Hash32) (messagePrelude, error) { 129 var p messagePrelude 130 131 var err error 132 p.Length, err = decodeUint32(r) 133 if err != nil { 134 return messagePrelude{}, err 135 } 136 137 p.HeadersLen, err = decodeUint32(r) 138 if err != nil { 139 return messagePrelude{}, err 140 } 141 142 if err := p.ValidateLens(); err != nil { 143 return messagePrelude{}, err 144 } 145 146 preludeCRC := crc.Sum32() 147 if err := validateCRC(r, preludeCRC); err != nil { 148 return messagePrelude{}, err 149 } 150 151 p.PreludeCRC = preludeCRC 152 153 return p, nil 154 } 155 156 func decodePayload(buf []byte, r io.Reader) ([]byte, error) { 157 w := bytes.NewBuffer(buf[0:0]) 158 159 _, err := io.Copy(w, r) 160 return w.Bytes(), err 161 } 162 163 func decodeUint8(r io.Reader) (uint8, error) { 164 type byteReader interface { 165 ReadByte() (byte, error) 166 } 167 168 if br, ok := r.(byteReader); ok { 169 v, err := br.ReadByte() 170 return v, err 171 } 172 173 var b [1]byte 174 _, err := io.ReadFull(r, b[:]) 175 return b[0], err 176 } 177 178 func decodeUint16(r io.Reader) (uint16, error) { 179 var b [2]byte 180 bs := b[:] 181 _, err := io.ReadFull(r, bs) 182 if err != nil { 183 return 0, err 184 } 185 return binary.BigEndian.Uint16(bs), nil 186 } 187 188 func decodeUint32(r io.Reader) (uint32, error) { 189 var b [4]byte 190 bs := b[:] 191 _, err := io.ReadFull(r, bs) 192 if err != nil { 193 return 0, err 194 } 195 return binary.BigEndian.Uint32(bs), nil 196 } 197 198 func decodeUint64(r io.Reader) (uint64, error) { 199 var b [8]byte 200 bs := b[:] 201 _, err := io.ReadFull(r, bs) 202 if err != nil { 203 return 0, err 204 } 205 return binary.BigEndian.Uint64(bs), nil 206 } 207 208 func validateCRC(r io.Reader, expect uint32) error { 209 msgCRC, err := decodeUint32(r) 210 if err != nil { 211 return err 212 } 213 214 if msgCRC != expect { 215 return ChecksumError{} 216 } 217 218 return nil 219 }