Skip to content

Preserve SSE events when CRLF separators span response chunks - #1036

Open
PeterDaveHello wants to merge 1 commit into
masterfrom
fix/sse-crlf-chunk-boundaries
Open

Preserve SSE events when CRLF separators span response chunks#1036
PeterDaveHello wants to merge 1 commit into
masterfrom
fix/sse-crlf-chunk-boundaries

Conversation

@PeterDaveHello

@PeterDaveHello PeterDaveHello commented Aug 6, 2026

Copy link
Copy Markdown
Member

Problem

Response chunk boundaries are independent of SSE line boundaries. When a CRLF sequence is split after the \r, the parser must remember that the next \n belongs to the same line ending instead of treating it as an empty event delimiter.

Persisting that state alone is not sufficient if the scanner restarts from the beginning of the buffer after consuming a line. Re-reading an earlier \r can recreate stale pending-CR state and swallow a real blank line from the next chunk.

Changes

  • Keep pending CRLF state across feed() calls and clear it on reset().
  • Resume line scanning from the current unconsumed position instead of re-reading consumed delimiters.
  • Cover split CRLF pairs, complete CRLF followed by an LF delimiter, mixed line endings, and empty chunks.
  • Verify that a representative SSE stream produces identical events at every possible single chunk boundary.

Validation

  • node --test tests/unit/utils/eventsource-parser.test.mjs — 19 tests passed.
  • An additional data-event enumeration covered 103,464 line-ending and chunking cases with no mismatches against the reference behavior.
  • node --check passed for the changed JavaScript modules.

Summary by CodeRabbit

  • Bug Fixes

    • Improved streaming event parsing when line breaks are split across incoming data chunks.
    • Preserved correct handling of CRLF and LF delimiters, including empty chunks and multiline event data.
  • Tests

    • Added coverage for all chunk-splitting scenarios to ensure consistent event output.

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The parser now preserves trailing-newline state and partial-line offsets across feed() calls. Tests cover CRLF and LF delimiters across chunk boundaries, empty chunks, and multiline event data.

Changes

EventSource parser chunk handling

Layer / File(s) Summary
Persistent CRLF state and partial-line scanning
src/utils/eventsource-parser.mjs
The parser stores discardTrailingNewline in parser state and resets it with the parser. Line scanning now includes the current buffer position when continuing partial-line parsing.
Chunk-boundary validation
tests/unit/utils/eventsource-parser.test.mjs
Tests feed multiple chunks and verify split CRLF separators, mixed delimiters, empty chunks, every single-boundary split, and multiline event data.

Estimated code review effort: 2 (Simple) | ~10 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main fix for preserving SSE events when CRLF separators span response chunks.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/sse-crlf-chunk-boundaries

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@qodo-code-review

Copy link
Copy Markdown
Contributor

PR Summary by Qodo

Preserve SSE events when CRLF separators span response chunks

🐞 Bug fix 🧪 Tests 🕐 10-20 Minutes

Grey Divider

AI Description

• Persist pending CRLF state across parser.feed() calls to avoid premature event dispatch.
• Reset the pending-CRLF state on explicit parser reset.
• Add regression coverage for CRLF pairs split across streamed chunks.
Diagram

graph TD
  A["HTTP response chunks"] --> B["parser.feed(bytes)"] --> C[("parser buffer + CRLF state")] --> D["SSE line/event parsing"] --> E["onParse(event) callback"]
  R["parser.reset()"]; --> C
Loading
High-Level Assessment

Persisting the pending-CRLF flag in parser state is the minimal, correct fix for chunk-boundary-induced delimiter splits. Larger alternatives (e.g., reworking parsing around full line tokenization or using a third-party SSE parser) would add complexity without improving correctness for this specific issue.

Files changed (2) +15 / -1

Bug fix (1) +2 / -1
eventsource-parser.mjsPersist pending CRLF state across feed() calls +2/-1

Persist pending CRLF state across feed() calls

• Moves the pending-CRLF (discard trailing newline) flag out of the per-feed local scope into parser state so a '\r' at the end of one chunk correctly pairs with a leading '\n' in the next chunk. Also ensures the flag is cleared when reset() is called.

src/utils/eventsource-parser.mjs

Tests (1) +13 / -0
eventsource-parser.test.mjsAdd regression test for CRLF split across chunk boundaries +13/-0

Add regression test for CRLF split across chunk boundaries

• Adds a unit test that feeds the parser chunks where both data-line and event-delimiter CRLF sequences are split across calls, asserting only a single complete event is emitted with the expected joined data.

tests/unit/utils/eventsource-parser.test.mjs

@qodo-code-review

qodo-code-review Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider

Great, no issues found!

Qodo reviewed your code and found no material issues that require review

Grey Divider

To customize comments, go to the Qodo configuration screen, or learn more in the docs.

Previous review results

Review updated until commit 532be8a ⚖️ Balanced

Results up to commit d54be0b ⚖️ Balanced


No changes from previous review

Qodo Logo

@greptile-apps

greptile-apps Bot commented Aug 6, 2026

Copy link
Copy Markdown

Greptile Summary

The PR preserves pending CRLF state across feed() calls so SSE separators split across response chunks are parsed consistently.

  • Moves trailing-newline state into the parser lifecycle and clears it on reset.
  • Corrects resumed line scanning to account for the current buffer position.
  • Adds regression coverage for split CRLF pairs, empty chunks, mixed line endings, and every single split point in a representative stream.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains in the changed parser behavior.

Important Files Changed

Filename Overview
src/utils/eventsource-parser.mjs Persists the pending CRLF state between chunks, resets it with parser state, and resumes scanning from the correct buffer-relative offset.
tests/unit/utils/eventsource-parser.test.mjs Adds focused regression and chunk-boundary equivalence tests for CRLF, LF, CR, mixed separators, and empty chunks.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[feed response chunk] --> B{Pending LF after CR?}
    B -->|Yes, next byte is LF| C[Consume LF as part of CRLF]
    B -->|No| D[Scan buffered SSE line]
    C --> D
    D --> E{Complete line found?}
    E -->|No| F[Retain partial line and parser state]
    E -->|Yes| G[Parse field or dispatch event]
    F --> A
    G --> H{More buffered input?}
    H -->|Yes| B
    H -->|No| A
Loading

Reviews (2): Last reviewed commit: "Preserve SSE events across arbitrary res..." | Re-trigger Greptile

@PeterDaveHello
PeterDaveHello requested a lite review from Copilot August 6, 2026 18:58

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

This PR fixes SSE parsing when \r\n line endings are split across multiple feed() chunks, and adds a unit test to prevent regressions.

Changes:

  • Persist discardTrailingNewline across feed() calls so a \n arriving in a later chunk is correctly discarded after a trailing \r.
  • Add a unit test that feeds CRLF boundaries across multiple chunks and asserts correct event data output.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
tests/unit/utils/eventsource-parser.test.mjs Adds a regression test covering CRLF separators split across chunks.
src/utils/eventsource-parser.mjs Moves discardTrailingNewline into parser state so CRLF handling works across feed() calls.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

Response chunks may split a CRLF pair, so pending-CR state must
survive feed() calls. The scanner must also resume at the current
unconsumed position; otherwise a consumed CR can restore stale state
and swallow a real event delimiter.

Persist the pending delimiter state, scan only unconsumed input, and
cover mixed line endings, empty chunks, and every single split point in
a representative stream.
@PeterDaveHello
PeterDaveHello force-pushed the fix/sse-crlf-chunk-boundaries branch from d54be0b to 532be8a Compare August 7, 2026 17:32

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/unit/utils/eventsource-parser.test.mjs`:
- Around line 82-125: Run npm run lint and fix the reported ESLint error in
src/content-script/index.jsx before committing. Keep the parser tests unchanged,
and only leave the lint failure unresolved if the pull request documents the
reason.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: e40ad88c-3a5f-4241-a6fe-5d95f85f2847

📥 Commits

Reviewing files that changed from the base of the PR and between d54be0b and 532be8a.

📒 Files selected for processing (2)
  • src/utils/eventsource-parser.mjs
  • tests/unit/utils/eventsource-parser.test.mjs
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/utils/eventsource-parser.mjs

Comment thread tests/unit/utils/eventsource-parser.test.mjs
@chatgpt-codex-connector

Copy link
Copy Markdown

Security review completed. No security issues were found in this pull request.

Reviewed commit: 532be8a154

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

@qodo-code-review

Copy link
Copy Markdown
Contributor

Code review by qodo was updated up to the latest commit 532be8a

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants