@@ -32,9 +32,11 @@ suspend fun ByteReadChannel.readUntilDelimiter(delimiter: ByteBuffer, dst: ByteB
32
32
} while (dst.hasRemaining() && ! endFound)
33
33
}
34
34
35
- if (! dst.hasRemaining() || endFound) return copied
36
-
37
- return readUntilDelimiterSuspend(delimiter, dst, copied)
35
+ return when {
36
+ copied == 0 && isClosedForRead -> - 1
37
+ ! dst.hasRemaining() || endFound -> copied
38
+ else -> readUntilDelimiterSuspend(delimiter, dst, copied)
39
+ }
38
40
}
39
41
40
42
suspend fun ByteReadChannel.skipDelimiter (delimiter : ByteBuffer ) {
@@ -62,18 +64,21 @@ private suspend fun ByteReadChannel.readUntilDelimiterSuspend(delimiter: ByteBuf
62
64
require(delimiter != = dst)
63
65
require(copied0 >= 0 )
64
66
65
- return lookAheadSuspend {
66
- var endFound = false
67
+ var endFound = false
68
+ val copied = lookAheadSuspend {
67
69
var copied = copied0
68
70
69
71
do {
70
72
awaitAtLeast(1 )
71
73
val rc = tryCopyUntilDelimiter(delimiter, dst)
72
74
if (rc == 0 ) {
73
- if (request(0 , delimiter.remaining())?.startsWith(delimiter, 0 ) == true ) {
75
+ if (startsWithDelimiter(delimiter) == delimiter.remaining()) {
76
+ endFound = true
74
77
break
75
78
}
76
- if (! isClosedForRead) {
79
+ if (isClosedForWrite) {
80
+ break
81
+ } else {
77
82
awaitAtLeast(delimiter.remaining())
78
83
continue
79
84
}
@@ -88,6 +93,12 @@ private suspend fun ByteReadChannel.readUntilDelimiterSuspend(delimiter: ByteBuf
88
93
89
94
copied
90
95
}
96
+
97
+ return when {
98
+ copied > 0 && isClosedForWrite && ! endFound -> copied + readAvailable(dst).coerceAtLeast(0 )
99
+ copied == 0 && isClosedForRead -> - 1
100
+ else -> copied
101
+ }
91
102
}
92
103
93
104
/* *
@@ -102,17 +113,24 @@ private fun LookAheadSession.tryCopyUntilDelimiter(delimiter: ByteBuffer, dst: B
102
113
val found = minOf(buffer.remaining() - index, delimiter.remaining())
103
114
val notKnown = delimiter.remaining() - found
104
115
105
- val next = if (notKnown > 0 ) request(index + found, notKnown) else null
106
- if (next != null ) {
107
- if (next.startsWith(delimiter, found)) {
108
- endFound = true
109
- dst.putLimited(buffer, buffer.position() + index)
116
+ if (notKnown == 0 ) {
117
+ endFound = true
118
+ dst.putLimited(buffer, buffer.position() + index)
119
+ } else {
120
+ val remembered = buffer.duplicate()
121
+ val next = request(index + found, 1 )
122
+ if (next == null ) {
123
+ dst.putLimited(remembered, remembered.position() + index)
124
+ } else if (next.startsWith(delimiter, found)) {
125
+ if (next.remaining() >= notKnown) {
126
+ endFound = true
127
+ dst.putLimited(remembered, remembered.position() + index)
128
+ } else {
129
+ dst.putLimited(remembered, remembered.position() + index)
130
+ }
110
131
} else {
111
- dst.putLimited(buffer, buffer .position() + index + 1 )
132
+ dst.putLimited(remembered, remembered .position() + index + 1 )
112
133
}
113
- } else {
114
- endFound = notKnown == 0
115
- dst.putLimited(buffer, buffer.position() + index)
116
134
}
117
135
} else {
118
136
dst.putAtMost(buffer)
@@ -123,18 +141,29 @@ private fun LookAheadSession.tryCopyUntilDelimiter(delimiter: ByteBuffer, dst: B
123
141
}
124
142
125
143
private fun LookAheadSession.tryEnsureDelimiter (delimiter : ByteBuffer ): Int {
144
+ val found = startsWithDelimiter(delimiter)
145
+ if (found == - 1 ) throw IOException (" Failed to skip delimiter: actual bytes differ from delimiter bytes" )
146
+ if (found < delimiter.remaining()) return found
147
+
148
+ consumed(delimiter.remaining())
149
+ return delimiter.remaining()
150
+ }
151
+
152
+ /* *
153
+ * @return Number of bytes of the delimiter found (possibly 0 if no bytes available yet) or -1 if it doesn't start
154
+ */
155
+ private fun LookAheadSession.startsWithDelimiter (delimiter : ByteBuffer ): Int {
126
156
val buffer = request(0 , 1 ) ? : return 0
127
157
val index = buffer.indexOfPartial(delimiter)
128
- if (index != 0 ) throw IOException ( " Failed to skip delimiter: actual bytes differ from delimiter bytes " )
158
+ if (index != 0 ) return - 1
129
159
130
160
val found = minOf(buffer.remaining() - index, delimiter.remaining())
131
161
val notKnown = delimiter.remaining() - found
132
162
133
163
if (notKnown > 0 ) {
134
164
val next = request(index + found, notKnown) ? : return found
135
- if (! next.startsWith(delimiter, found)) throw IOException ( " Failed to skip delimiter: actual bytes differ from delimiter bytes " )
165
+ if (! next.startsWith(delimiter, found)) return - 1
136
166
}
137
167
138
- consumed(delimiter.remaining())
139
168
return delimiter.remaining()
140
169
}
0 commit comments