Repository: envoyproxy/envoy
File: source/common/http/sse/sse_parser.cc (C++)

Code before:
    }
  }

  return parsed_event;
}

std::tuple<size_t, size_t, size_t> SseParser::findEventEnd(absl::string_view buffer,
                                                           bool end_stream) {
  size_t consumed = 0;
  size_t event_start = 0;
  absl::string_view remaining = buffer;

  // Per SSE spec: Strip UTF-8 BOM (0xEF 0xBB 0xBF) if present at stream start.
  if (consumed == 0 && remaining.size() >= 3 && static_cast<uint8_t>(remaining[0]) == 0xEF &&
      static_cast<uint8_t>(remaining[1]) == 0xBB && static_cast<uint8_t>(remaining[2]) == 0xBF) {
    remaining = remaining.substr(3);
    consumed = 3;
    event_start = 3; // Event content starts after BOM
  }

  while (!remaining.empty()) {
    auto [line_end, next_line] = findLineEnd(remaining, end_stream);

    if (line_end == absl::string_view::npos) {
      return {absl::string_view::npos, absl::string_view::npos, absl::string_view::npos};
    }

    if (line_end == 0) {
      // Found blank line so this is the end of event
      return {event_start, consumed, consumed + next_line};
    }

    consumed += next_line;
    remaining = remaining.substr(next_line);
  }

  // Per SSE spec: Once the end of the file is reached, any pending data must be discarded.
  // (i.e., incomplete events without a closing blank line are dropped)
  return {absl::string_view::npos, absl::string_view::npos, absl::string_view::npos};
}

std::pair<absl::string_view, absl::string_view> SseParser::parseFieldLine(absl::string_view line) {
  if (line.empty()) {
    return {"", ""};
  }

  // Per SSE spec, lines starting with ':' are comments and should be ignored.
  if (line[0] == ':') {
    return {"", ""};
  }


Review comment (bug):
We are now preventing overflow at uint64? uint32_t is already roughly 49 days. but i don't feel strong either way.

Code after:
      }
      parsed_event.data->append(field_value.data(), field_value.size());
    } else if (field_name == "id") {
      // Per SSE spec, if the field value contains U+0000 NULL, the field is ignored.
      // Otherwise, set the last event ID to the field value. If multiple id fields exist,
      // the last one wins.
      if (field_value.find('\0') == absl::string_view::npos) {
        parsed_event.id = std::string(field_value);
      }
    } else if (field_name == "event") {
      // Per SSE spec, the event field sets the event type. If multiple event fields exist,
      // the last one wins.
      parsed_event.event_type = std::string(field_value);
    } else if (field_name == "retry") {
      // Per SSE spec, the retry field must consist of only ASCII digits.
      // If it contains any other character, the field is ignored.
      if (!field_value.empty()) {
        uint64_t value = 0;
        bool valid = true;
        for (char c : field_value) {
          if (!absl::ascii_isdigit(c)) {
            valid = false;
            break;
          }
          uint64_t new_value = value * 10 + static_cast<uint64_t>(c - '0');
          if (new_value < value) {
            valid = false;
            break;
          }
          value = new_value;
        }
        if (valid) {
          parsed_event.retry = value;
        }
      }
    }
  }

  return parsed_event;
}

std::tuple<size_t, size_t, size_t> SseParser::findEventEnd(absl::string_view buffer,
                                                           bool end_stream) {
  size_t consumed = 0;
  size_t event_start = 0;
  absl::string_view remaining = buffer;

  // Per SSE spec: Strip UTF-8 BOM (0xEF 0xBB 0xBF) if present at stream start.
  if (consumed == 0 && remaining.size() >= 3 && static_cast<uint8_t>(remaining[0]) == 0xEF &&
      static_cast<uint8_t>(remaining[1]) == 0xBB && static_cast<uint8_t>(remaining[2]) == 0xBF) {
    remaining = remaining.substr(3);