Skip to content

Commit 378d44d

Browse files
committed
Update EventParser.swift
1 parent 35603e4 commit 378d44d

File tree

1 file changed

+41
-17
lines changed

1 file changed

+41
-17
lines changed

Sources/EventSource/EventParser.swift

Lines changed: 41 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -39,30 +39,54 @@ struct ServerEventParser: EventParser {
3939
}
4040

4141
private func splitBuffer(for data: Data) -> (completeData: [Data], remainingData: Data) {
42-
let separator: [UInt8] = [Self.lf, Self.lf]
43-
var rawMessages = [Data]()
44-
45-
// now replace CR LF with LF LF for processing mixed content
46-
var data = data
47-
while let crlfRange = data.lastRange(of: [Self.cr, Self.lf]) {
48-
data.replaceSubrange(crlfRange, with: [Self.lf])
49-
}
50-
51-
// If event separator is not present do not parse any unfinished messages
52-
guard let lastSeparator = data.lastRange(of: separator) else {
42+
let separators: [[UInt8]] = [[Self.lf, Self.lf], [Self.cr, Self.lf, Self.cr, Self.lf]]
43+
44+
// find last range of our separator, most likely to be fast enough
45+
let (chosenSeparator, lastSeparatorRange) = findLastSeparator(in: data, separators: separators)
46+
guard let separator = chosenSeparator, let lastSeparator = lastSeparatorRange else {
5347
return ([], data)
5448
}
55-
49+
50+
// chop everything before the last separator, going forward, O(n) complexity
5651
let bufferRange = data.startIndex ..< lastSeparator.upperBound
5752
let remainingRange = lastSeparator.upperBound ..< data.endIndex
58-
59-
if #available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, visionOS 1.0, *) {
60-
rawMessages = data[bufferRange].split(separator: separator)
53+
let rawMessages: [Data] = if #available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, visionOS 1.0, *) {
54+
data[bufferRange].split(separator: separator)
6155
} else {
62-
rawMessages = data[bufferRange].split(by: separator)
56+
data[bufferRange].split(by: separator)
6357
}
58+
59+
// now clean up the messages and return
60+
let cleanedMessages = rawMessages.map { cleanMessageData($0) }
61+
return (cleanedMessages, data[remainingRange])
62+
}
6463

65-
return (rawMessages, data[remainingRange])
64+
private func findLastSeparator(in data: Data, separators: [[UInt8]]) -> ([UInt8]?, Range<Data.Index>?) {
65+
var chosenSeparator: [UInt8]?
66+
var lastSeparatorRange: Range<Data.Index>?
67+
for separator in separators {
68+
if let range = data.lastRange(of: separator) {
69+
if lastSeparatorRange == nil || range.upperBound > lastSeparatorRange!.upperBound {
70+
chosenSeparator = separator
71+
lastSeparatorRange = range
72+
}
73+
}
74+
}
75+
return (chosenSeparator, lastSeparatorRange)
76+
}
77+
78+
private func cleanMessageData(_ messageData: Data) -> Data {
79+
var cleanData = messageData
80+
// remove trailing CR/LF characters from the end
81+
while !cleanData.isEmpty, cleanData.last == Self.cr || cleanData.last == Self.lf {
82+
cleanData = cleanData.dropLast()
83+
}
84+
guard let messageString = String(data: cleanData, encoding: .utf8) else { return cleanData }
85+
// also clean internal lines within each message to remove trailing \r
86+
let cleanedLines = messageString.components(separatedBy: .newlines)
87+
.map { $0.trimmingCharacters(in: CharacterSet(charactersIn: "\r")) }
88+
let cleanedMessage = cleanedLines.joined(separator: "\n")
89+
return Data(cleanedMessage.utf8)
6690
}
6791
}
6892

0 commit comments

Comments
 (0)