Browse Source

Fix handling of long lines.

If we multiple long lines in succession the start index got
miscalculated and part of the latter lines discarded.
tags/v0.10.2
Chris Smith 5 years ago
parent
commit
eacdf03763

+ 3
- 0
CHANGELOG View File

@@ -1,5 +1,8 @@
1 1
 vNEXT (in development)
2 2
 
3
+ * Fix handling of multiple long lines sometimes dropping part of the line
4
+ * Support lines with 8191 bytes of tags, as allowed by the message-tags spec
5
+
3 6
 v0.10.1
4 7
 
5 8
  * Added NickChangeFailed event for when nicknames are in use, banned, etc

+ 10
- 10
src/main/kotlin/com/dmdirc/ktirc/io/LineBufferedSocket.kt View File

@@ -80,23 +80,23 @@ internal class KtorLineBufferedSocket(coroutineScope: CoroutineScope, private va
80 80
 
81 81
     override val receiveChannel
82 82
         get() = produce {
83
-            val lineBuffer = ByteArray(4096)
84
-            var index = 0
83
+            val lineBuffer = ByteArray(16384)
84
+            var nextByteOffset = 0
85 85
             while (!readChannel.isClosedForRead) {
86
-                var start = index
87
-                val count = readChannel.readAvailable(lineBuffer, index, lineBuffer.size - index)
88
-                for (i in index until index + count) {
86
+                var lineStart = 0
87
+                val bytesRead = readChannel.readAvailable(lineBuffer, nextByteOffset, lineBuffer.size - nextByteOffset)
88
+                for (i in nextByteOffset until nextByteOffset + bytesRead) {
89 89
                     if (lineBuffer[i] == CARRIAGE_RETURN || lineBuffer[i] == LINE_FEED) {
90
-                        if (start < i) {
91
-                            val line = lineBuffer.sliceArray(start until i)
90
+                        if (lineStart < i) {
91
+                            val line = lineBuffer.sliceArray(lineStart until i)
92 92
                             log.fine { "<<< ${String(line)}" }
93 93
                             send(line)
94 94
                         }
95
-                        start = i + 1
95
+                        lineStart = i + 1
96 96
                     }
97 97
                 }
98
-                lineBuffer.copyInto(lineBuffer, 0, start)
99
-                index = count + index - start
98
+                lineBuffer.copyInto(lineBuffer, 0, lineStart)
99
+                nextByteOffset += bytesRead - lineStart
100 100
             }
101 101
         }
102 102
 

+ 19
- 0
src/test/kotlin/com/dmdirc/ktirc/io/KtorLineBufferedSocketTest.kt View File

@@ -113,6 +113,25 @@ internal class KtorLineBufferedSocketTest {
113 113
         }
114 114
     }
115 115
 
116
+    @Test
117
+    fun `KtorLineBufferedSocket can receive multiple long lines of text`() = runBlocking {
118
+        ServerSocket(12321).use { serverSocket ->
119
+            val socket = KtorLineBufferedSocket(GlobalScope, "localhost", 12321)
120
+            val line1 = "abcdefghijklmnopqrstuvwxyz".repeat(500)
121
+            val line2 = "1234567890987654321[];'#,.".repeat(500)
122
+            val line3 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".repeat(500)
123
+            GlobalScope.launch {
124
+                serverSocket.accept().getOutputStream().write("$line1\r\n$line2\r$line3\n".toByteArray())
125
+            }
126
+
127
+            socket.connect()
128
+            val lineProducer = socket.receiveChannel
129
+            assertEquals(line1, String(lineProducer.receive()))
130
+            assertEquals(line2, String(lineProducer.receive()))
131
+            assertEquals(line3, String(lineProducer.receive()))
132
+        }
133
+    }
134
+
116 135
     @Test
117 136
     fun `KtorLineBufferedSocket can receive one line of text over multiple packets`() = runBlocking {
118 137
         ServerSocket(12321).use { serverSocket ->

Loading…
Cancel
Save