Browse Source

fix(sse): preserve empty data lines in SSE formatting

pull/15618/head
Matias Formoso 1 week ago
parent
commit
4a9561aff7
  1. 9
      fastapi/sse.py
  2. 14
      tests/test_sse.py

9
fastapi/sse.py

@ -88,7 +88,8 @@ class ServerSentEvent(BaseModel):
Use this when you need to send pre-formatted text, HTML fragments,
CSV lines, or any non-JSON payload. The string is placed directly
into the `data:` field as-is.
into the `data:` field as-is. An empty string still emits a single
empty `data:` line.
Mutually exclusive with `data`.
"""
@ -213,7 +214,11 @@ def format_sse_event(
lines.append(f"event: {event}")
if data_str is not None:
for line in data_str.splitlines():
# Normalize line endings and preserve empty data lines.
# This keeps explicit empty payloads (`data_str=""`) and trailing
# newlines represented as `data:` lines in SSE wire format.
normalized_data = data_str.replace("\r\n", "\n").replace("\r", "\n")
for line in normalized_data.split("\n"):
lines.append(f"data: {line}")
if id is not None:

14
tests/test_sse.py

@ -6,7 +6,7 @@ import fastapi.routing
import pytest
from fastapi import APIRouter, FastAPI
from fastapi.responses import EventSourceResponse
from fastapi.sse import ServerSentEvent
from fastapi.sse import ServerSentEvent, format_sse_event
from fastapi.testclient import TestClient
from pydantic import BaseModel
@ -264,6 +264,18 @@ def test_data_and_raw_data_mutually_exclusive():
ServerSentEvent(data="json", raw_data="raw")
def test_format_sse_event_keeps_empty_data_line():
"""An explicit empty payload should emit one `data:` line."""
payload = format_sse_event(data_str="")
assert payload == b"data: \n\n"
def test_format_sse_event_normalizes_crlf_and_keeps_trailing_empty_line():
"""CRLF and trailing newline should produce valid SSE data lines."""
payload = format_sse_event(data_str="first\r\nsecond\r\n")
assert payload == b"data: first\ndata: second\ndata: \n\n"
def test_sse_on_router_included_in_app(client: TestClient):
response = client.get("/api/events")
assert response.status_code == 200

Loading…
Cancel
Save