private bool ProcessLine()

in src/Utility/System.Net.ServerSentEvents.cs [396:519]


        private bool ProcessLine(out SseItem<T> sseItem, out int advance)
        {
            ReadOnlySpan<byte> line = _lineBuffer.AsSpan(_lineOffset, _newlineIndex - _lineOffset);

            // Spec: "If the line is empty (a blank line) Dispatch the event"
            if (line.IsEmpty)
            {
                advance = GetNewLineLength();

                if (_dataAppended)
                {
                    sseItem = new SseItem<T>(_itemParser(_eventType, _dataBuffer.AsSpan(0, _dataLength)), _eventType);
                    _eventType = SseParser.EventTypeDefault;
                    _dataLength = 0;
                    _dataAppended = false;
                    return true;
                }

                sseItem = default;
                return false;
            }

            // Find the colon separating the field name and value.
            int colonPos = line.IndexOf((byte)':');
            ReadOnlySpan<byte> fieldName;
            ReadOnlySpan<byte> fieldValue;
            if (colonPos >= 0)
            {
                // Spec: "Collect the characters on the line before the first U+003A COLON character (:), and let field be that string."
                fieldName = line.Slice(0, colonPos);

                // Spec: "Collect the characters on the line after the first U+003A COLON character (:), and let value be that string.
                // If value starts with a U+0020 SPACE character, remove it from value."
                fieldValue = line.Slice(colonPos + 1);
                if (!fieldValue.IsEmpty && fieldValue[0] == (byte)' ')
                {
                    fieldValue = fieldValue.Slice(1);
                }
            }
            else
            {
                // Spec: "using the whole line as the field name, and the empty string as the field value."
                fieldName = line;
                fieldValue = [];
            }

            if (fieldName.SequenceEqual("data"u8))
            {
                // Spec: "Append the field value to the data buffer, then append a single U+000A LINE FEED (LF) character to the data buffer."
                // Spec: "If the data buffer's last character is a U+000A LINE FEED (LF) character, then remove the last character from the data buffer."

                // If there's nothing currently in the data buffer and we can easily detect that this line is immediately followed by
                // an empty line, we can optimize it to just handle the data directly from the line buffer, rather than first copying
                // into the data buffer and dispatching from there.
                if (!_dataAppended)
                {
                    int newlineLength = GetNewLineLength();
                    ReadOnlySpan<byte> remainder = _lineBuffer.AsSpan(_newlineIndex + newlineLength, _lineLength - line.Length - newlineLength);
                    if (!remainder.IsEmpty &&
                        (remainder[0] is LF || (remainder[0] is CR && remainder.Length > 1)))
                    {
                        advance = line.Length + newlineLength + (remainder.StartsWith(CRLF) ? 2 : 1);
                        sseItem = new SseItem<T>(_itemParser(_eventType, fieldValue), _eventType);
                        _eventType = SseParser.EventTypeDefault;
                        return true;
                    }
                }

                // We need to copy the data from the data buffer to the line buffer. Make sure there's enough room.
                if (_dataBuffer is null || _dataLength + _lineLength + 1 > _dataBuffer.Length)
                {
                    GrowBuffer(ref _dataBuffer, _dataLength + _lineLength + 1);
                }

                // Append a newline if there's already content in the buffer.
                // Then copy the field value to the data buffer
                if (_dataAppended)
                {
                    _dataBuffer![_dataLength++] = LF;
                }
                fieldValue.CopyTo(_dataBuffer.AsSpan(_dataLength));
                _dataLength += fieldValue.Length;
                _dataAppended = true;
            }
            else if (fieldName.SequenceEqual("event"u8))
            {
                // Spec: "Set the event type buffer to field value."
                _eventType = SseParser.Utf8GetString(fieldValue);
            }
            else if (fieldName.SequenceEqual("id"u8))
            {
                // Spec: "If the field value does not contain U+0000 NULL, then set the last event ID buffer to the field value. Otherwise, ignore the field."
                if (fieldValue.IndexOf((byte)'\0') < 0)
                {
                    // Note that fieldValue might be empty, in which case LastEventId will naturally be reset to the empty string. This is per spec.
                    LastEventId = SseParser.Utf8GetString(fieldValue);
                }
            }
            else if (fieldName.SequenceEqual("retry"u8))
            {
                // Spec: "If the field value consists of only ASCII digits, then interpret the field value as an integer in base ten,
                // and set the event stream's reconnection time to that integer. Otherwise, ignore the field."
                if (long.TryParse(
#if NET7_0_OR_GREATER
                    fieldValue,
#else
                    SseParser.Utf8GetString(fieldValue),
#endif
                    NumberStyles.None, CultureInfo.InvariantCulture, out long milliseconds))
                {
                    ReconnectionInterval = TimeSpan.FromMilliseconds(milliseconds);
                }
            }
            else
            {
                // We'll end up here if the line starts with a colon, producing an empty field name, or if the field name is otherwise unrecognized.
                // Spec: "If the line starts with a U+003A COLON character (:) Ignore the line."
                // Spec: "Otherwise, The field is ignored"
            }

            advance = line.Length + GetNewLineLength();
            sseItem = default;
            return false;
        }