parseEnvelopeItems parses a Sentry envelope body into individual items. Envelope format (https://develop.sentry.dev/sdk/envelopes/): header_json\n (item_header_json\n payload\n)* Item payloads may legitimately contain literal newlines when the item header declares a `length` (bytes); we honor t
(body []byte)
| 16 | // declares a `length` (bytes); we honor that. When length is absent we fall |
| 17 | // back to newline-delimited payloads. |
| 18 | func parseEnvelopeItems(body []byte) (EnvelopeHeader, []EnvelopeItem, error) { |
| 19 | var envHeader EnvelopeHeader |
| 20 | var items []EnvelopeItem |
| 21 | |
| 22 | // First line: envelope header. |
| 23 | nl := bytes.IndexByte(body, '\n') |
| 24 | if nl < 0 { |
| 25 | // Single line — try to parse as the header but no items follow. |
| 26 | _ = json.Unmarshal(body, &envHeader) |
| 27 | return envHeader, nil, nil |
| 28 | } |
| 29 | if err := json.Unmarshal(body[:nl], &envHeader); err != nil { |
| 30 | envHeader = EnvelopeHeader{} |
| 31 | } |
| 32 | pos := nl + 1 |
| 33 | |
| 34 | for pos < len(body) { |
| 35 | // Skip any blank line separators between items. |
| 36 | for pos < len(body) && body[pos] == '\n' { |
| 37 | pos++ |
| 38 | } |
| 39 | if pos >= len(body) { |
| 40 | break |
| 41 | } |
| 42 | |
| 43 | // Item header is one line. |
| 44 | nl := bytes.IndexByte(body[pos:], '\n') |
| 45 | var headerLine []byte |
| 46 | if nl < 0 { |
| 47 | headerLine = body[pos:] |
| 48 | pos = len(body) |
| 49 | } else { |
| 50 | headerLine = body[pos : pos+nl] |
| 51 | pos = pos + nl + 1 |
| 52 | } |
| 53 | |
| 54 | var ih ItemHeader |
| 55 | if err := json.Unmarshal(headerLine, &ih); err != nil { |
| 56 | continue |
| 57 | } |
| 58 | if ih.Type == "" { |
| 59 | continue |
| 60 | } |
| 61 | |
| 62 | // Item payload: prefer the explicit length when present, otherwise read |
| 63 | // up to the next newline. |
| 64 | // |
| 65 | // The bound check uses subtraction (len(body)-pos) rather than addition |
| 66 | // (pos+ih.Length) to avoid signed-int overflow on a crafted envelope: |
| 67 | // a huge ih.Length combined with pos could wrap to a small (even |
| 68 | // negative) result, pass an additive bound, then panic when slicing. |
| 69 | var payload []byte |
| 70 | if ih.Length > 0 && ih.Length <= len(body)-pos { |
| 71 | payload = body[pos : pos+ih.Length] |
| 72 | pos += ih.Length |
| 73 | // Skip the trailing newline (envelope spec allows but doesn't require it). |
| 74 | if pos < len(body) && body[pos] == '\n' { |
| 75 | pos++ |
no outgoing calls