@@ -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