diff --git a/Sources/OpenAPIRuntime/EventStreams/ServerSentEventsEncoding.swift b/Sources/OpenAPIRuntime/EventStreams/ServerSentEventsEncoding.swift index 99fe9590..eca89e6e 100644 --- a/Sources/OpenAPIRuntime/EventStreams/ServerSentEventsEncoding.swift +++ b/Sources/OpenAPIRuntime/EventStreams/ServerSentEventsEncoding.swift @@ -167,8 +167,14 @@ extension ServerSentEventsSerializationSequence.Iterator { buffer.append(contentsOf: value.utf8) buffer.append(ASCII.lf) } - if let id = value.id { encodeField(name: "id", value: id) } - if let event = value.event { encodeField(name: "event", value: event) } + // `id` and `event` values must not contain any newline characters, as they're used to + // delimit fields and events, so strip any that are present. + func removingNewlines(_ value: some StringProtocol) -> String { + value.replacingOccurrences(of: "\r\n", with: "").replacingOccurrences(of: "\r", with: "") + .replacingOccurrences(of: "\n", with: "") + } + if let id = value.id { encodeField(name: "id", value: removingNewlines(id)) } + if let event = value.event { encodeField(name: "event", value: removingNewlines(event)) } if let retry = value.retry { encodeField(name: "retry", value: String(retry)) } if let data = value.data { // Normalize the data section by replacing CRLF and CR with just LF. diff --git a/Tests/OpenAPIRuntimeTests/EventStreams/Test_ServerSentEventsEncoding.swift b/Tests/OpenAPIRuntimeTests/EventStreams/Test_ServerSentEventsEncoding.swift index 03f4bf6a..75569978 100644 --- a/Tests/OpenAPIRuntimeTests/EventStreams/Test_ServerSentEventsEncoding.swift +++ b/Tests/OpenAPIRuntimeTests/EventStreams/Test_ServerSentEventsEncoding.swift @@ -74,6 +74,20 @@ final class Test_ServerSentEventsEncoding: Test_Runtime { data: This is a message with an ID. + """# + ) + } + func testIdAndEventStripNewlines() async throws { + // The id and event fields must not contain newlines, as they would otherwise be + // misinterpreted as the start of another field. + try await _test( + input: [.init(id: "123\r\n456", event: "custom\nEvent\r", data: "hello")], + output: #""" + id: 123456 + event: customEvent + data: hello + + """# ) }