ktor icon indicating copy to clipboard operation
ktor copied to clipboard

Fix websocket of browser received array buffer size is 0

Open myfreax opened this issue 3 years ago • 2 comments
trafficstars

Subsystem Server

Motivation websocket of browser received array buffer size is 0

Solution Use ByteBuffer.array() return ByteArray can work well

myfreax avatar Apr 28 '22 11:04 myfreax

Hi @myfreax Can you please explain the problem and write test for your fix?

rsinukov avatar Apr 28 '22 12:04 rsinukov

@rsinukov I try to find the reason, but I don't know why it is happening, the following code will not work correctly. But use ByteBuffer.array() return ByteArray can work well.

fun moveToByteArray(byteBuffer: ByteBuffer): ByteArray {
    val array = ByteArray(byteBuffer.remaining())
    byteBuffer.get(array)
    return array
}
fun Application.configureSockets() {
     var tcpReadChannel: ByteReadChannel? = null
     var tcpWriteChannel: ByteWriteChannel? = null
    install(WebSockets) {
        pingPeriod = Duration.ofSeconds(15)
        timeout = Duration.ofSeconds(15)
        maxFrameSize = Long.MAX_VALUE
        masking = false
    }
    CoroutineScope(Dispatchers.IO).launch {
        val socket = aSocket(ActorSelectorManager(Dispatchers.IO)).tcp().connect("127.0.0.1", port = 9002){
            this.noDelay = false
        }
        tcpReadChannel = socket.openReadChannel()
        tcpWriteChannel = socket.openWriteChannel(autoFlush = true)
    }
    routing {
        webSocket("/") {
            launch(Dispatchers.IO) {
                while (true) {
                    val byteBuffer = ByteBuffer.allocate(tcpReadChannel?.availableForRead!!)
                    val len = tcpReadChannel?.readFully(byteBuffer)
                    if (len != 0) {
                        launch {
                            val byteArray = moveToByteArray(byteBuffer)
                            outgoing.send(Frame.Binary(true, byteArray)) //byteArray.size is 0
                            //println("TCP Client Send Data To Websocket Server: ${StandardCharsets.UTF_8.decode(byteBuffer)}") //print empty string""
                        }
                    }
                }
            }
            for (frame in incoming) {
                tcpWriteChannel?.writeFully(appendCRLF(frame.buffer))
                ///println("WebSocket Server Received Data From Browser Client: ${StandardCharsets.UTF_8.decode(frame.buffer)}")
            }
        }
    }
}

Trying the following test code also works fine, but in the above scenario it works. For unknown reasons, I'm having a hard time writing tests for the above scenarios.

val byteBuffer = ByteBuffer.wrap("aa".toByteArray())
val array = ByteArray(byteBuffer.remaining())
byteBuffer.get(array)
println(array.size)

myfreax avatar Apr 29 '22 01:04 myfreax

I'm closing this PR because we can't accept this change. array() function will return the backing array of ByteBuffer which will have all the future changes in the ByteBuffer.

rsinukov avatar Aug 12 '22 13:08 rsinukov