Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

secure Websocket client failed #560

Closed
coolemza opened this issue Sep 4, 2018 · 17 comments
Closed

secure Websocket client failed #560

coolemza opened this issue Sep 4, 2018 · 17 comments
Assignees
Labels
Milestone

Comments

@coolemza
Copy link

coolemza commented Sep 4, 2018

this code works:

    val client = HttpClient(CIO).config { install(WebSockets) }

    client.ws(host = "echo.websocket.org") {
        send(Frame.Text("Hello World"))

        for (message in incoming.map { it as? Frame.Text }.filterNotNull()) {
            println(message.readText())
        }
    }

this one freezes on connection:

    val client = HttpClient(CIO).config { install(WebSockets) }

    client.wss(host = "echo.websocket.org") {
        send(Frame.Text("Hello World"))

        for (message in incoming.map { it as? Frame.Text }.filterNotNull()) {
            println(message.readText())
        }
    }
@e5l e5l self-assigned this Sep 5, 2018
@e5l e5l added the bug label Oct 10, 2018
@ghost
Copy link

ghost commented Nov 10, 2018

Any work around until fixed?

@e5l
Copy link
Member

e5l commented Dec 26, 2018

The fix is complete and would be available in 1.1.2

@e5l e5l closed this as completed Dec 26, 2018
@e5l e5l added this to the 1.1.2 milestone Dec 26, 2018
@coolemza
Copy link
Author

coolemza commented Feb 13, 2019

still not work, you cant test it by code in first post

@e5l
Copy link
Member

e5l commented Feb 15, 2019

Could you provide the details?
We have the same test and it passed

  @Test
    fun testSecureRemotePingPong() = clientsTest(skipMissingPlatforms = true) {
        val remote = "echo.websocket.org"

        config {
            install(WebSockets)
        }

        test { client ->
            client.wss(host = remote) {
                repeat(10) {
                    ping(it.toString())
                }
            }
        }
    }

@coolemza
Copy link
Author

as i see sometimes it works for 1st try, but then no success, i test it on Ubuntu 18.04, jvm 8/11 using this test https://github.com/coolemza/WSTest

@e5l
Copy link
Member

e5l commented Feb 18, 2019

The problem of hanging is in map:

for (message in incoming.map { it as? Frame.Text }.filterNotNull()) 
  1. server doesn't automatically close connection
  2. client closes the connection after the client block.
  3. map wait for WebSocket close.

Also, you could send a close frame after hello message
Could you check the code without the map(send and consume a fixed number of messages)?

@coolemza
Copy link
Author

ok, ill check, but why it works in non secure case?

@coolemza
Copy link
Author

tested with

suspend fun main() = try {
    println("start")

    val client = HttpClient(CIO).config { install(WebSockets) }

    client.wss(host = "echo.websocket.org") {
        repeat(10) { send(Frame.Text("Hello World $it")) }

        GlobalScope.launch(Dispatchers.IO) {
            repeat(10) {
                println((incoming.receive() as Frame.Text).readText())
            }
        }.join()
    }

    println("start finished")

} catch (e: Exception) {
    e.printStackTrace()
    println("stopped abnormal")
}

same results, ws() works fine and wss() freezes without any message received, and when started testing first 2 times wss() receives messages, then stopped, seems like it depends on some kind of caching or timeouts issue

@e5l
Copy link
Member

e5l commented Feb 19, 2019

It shouldn't work without close with the ws builder too, and I can't reproduce on develop with ws and wss.

@coolemza
Copy link
Author

slightly modified test

suspend fun main() = try {
    println("start")

    repeat(10) { cnt ->
        println("try #$cnt")
        val client = HttpClient( CIO).config { install(WebSockets) }
        client.wss(host = "echo.websocket.org") {
            repeat(10) { send(Frame.Text("Hello World $it")) }

            GlobalScope.launch(Dispatchers.IO) {
                repeat(10) {
                    println((incoming.receive() as Frame.Text).readText())
                }
            }.join()
        }
        client.close()
    }

    println("start finished")

} catch (e: Exception) {
    e.printStackTrace()
    println("stopped abnormal")
}

and tested it in various ubuntu environments, same result it works for 1-3 iteration then freezes, you can reproduce it with

git clone https://github.com/coolemza/WSTest.git
./gradlew build
java -jar build/libs/WSTest.jar

@e5l
Copy link
Member

e5l commented Feb 19, 2019

Could you try to call close on the WebSocketSession instead?

@coolemza
Copy link
Author

tried

suspend fun main() = try {
    println("start")

    repeat(10) { cnt ->
        println("try #$cnt")
        val client = HttpClient( CIO).config { install(WebSockets) }
        client.wss(host = "echo.websocket.org") {
            repeat(10) { send(Frame.Text("Hello World $it")) }

            GlobalScope.launch(Dispatchers.IO) {
                repeat(10) {
                    println((incoming.receive() as Frame.Text).readText())
                }
            }.join()

            close(CloseReason(1000, "stop"))
        }
    }

    println("start finished")

} catch (e: Exception) {
    e.printStackTrace()
    println("stopped abnormal")
}

first run

rut@dev-bot:~/test/WSTest$ java -jar build/libs/WSTest.jar
start
try #0
Hello World 0
Hello World 1
Hello World 2
Hello World 3
Hello World 4
Hello World 5
Hello World 6
Hello World 7
Hello World 8
Hello World 9
kotlinx.coroutines.channels.ClosedSendChannelException: Channel was closed
        at kotlinx.coroutines.channels.Closed.getSendException(AbstractChannel.kt:1080)
        at kotlinx.coroutines.channels.AbstractSendChannel.offer(AbstractChannel.kt:186)
        at kotlinx.coroutines.channels.AbstractSendChannel.send(AbstractChannel.kt:174)
        at kotlinx.coroutines.channels.ChannelCoroutine.send$suspendImpl(ChannelCoroutine.kt)
        at kotlinx.coroutines.channels.ChannelCoroutine.send(ChannelCoroutine.kt)
        at kotlinx.coroutines.channels.LazyActorCoroutine.send(Actor.kt:151)
        at io.ktor.http.cio.websocket.WebSocketSession$DefaultImpls.send(WebSocketSession.kt:60)
        at io.ktor.http.cio.websocket.RawWebSocket.send(RawWebSocket.kt:18)
        at io.ktor.client.features.websocket.WebSockets$Feature$install$2$session$1.send(WebSockets.kt)
        at io.ktor.http.cio.websocket.DefaultWebSocketSessionImpl.send(DefaultWebSocketSessionImpl.kt)
        at io.ktor.http.cio.websocket.DefaultWebSocketSessionImpl.sendCloseSequence(DefaultWebSocketSessionImpl.kt:143
)
        at io.ktor.http.cio.websocket.DefaultWebSocketSessionImpl.close(DefaultWebSocketSessionImpl.kt:67)
        at io.ktor.client.features.websocket.DefaultClientWebSocketSession.close(ClientSessions.kt)
        at io.ktor.http.cio.websocket.WebSocketSession$DefaultImpls.close$default(WebSocketSession.kt:72)
        at io.ktor.client.features.websocket.BuildersKt.webSocket(builders.kt:70)
        at io.ktor.client.features.websocket.BuildersKt$webSocket$1.invokeSuspend(builders.kt)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:32)
        at kotlinx.coroutines.DispatchedKt.resumeCancellable(Dispatched.kt:185)
        at kotlinx.coroutines.ResumeModeKt.resumeMode(ResumeMode.kt:22)
        at kotlinx.coroutines.DispatchedKt.resume(Dispatched.kt:272)
        at kotlinx.coroutines.DispatchedKt.dispatch(Dispatched.kt:261)
        at kotlinx.coroutines.CancellableContinuationImpl.dispatchResume(CancellableContinuationImpl.kt:218)
        at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl(CancellableContinuationImpl.kt:227)
        at kotlinx.coroutines.CancellableContinuationImpl.resumeWith(CancellableContinuationImpl.kt:168)
        at kotlinx.coroutines.ResumeOnCompletion.invoke(JobSupport.kt:1245)
        at kotlinx.coroutines.JobSupport.notifyCompletion(JobSupport.kt:1373)
        at kotlinx.coroutines.JobSupport.completeStateFinalization(JobSupport.kt:298)
        at kotlinx.coroutines.JobSupport.tryFinalizeFinishingState(JobSupport.kt:230)
        at kotlinx.coroutines.JobSupport.tryMakeCompleting(JobSupport.kt:799)
        at kotlinx.coroutines.JobSupport.makeCompletingOnce$kotlinx_coroutines_core(JobSupport.kt:742)
        at kotlinx.coroutines.AbstractCoroutine.resumeWith(AbstractCoroutine.kt:117)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:45)
        at kotlinx.coroutines.DispatchedTask.run(Dispatched.kt:233)
        at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:594)
        at kotlinx.coroutines.scheduling.CoroutineScheduler.access$runSafely(CoroutineScheduler.kt:60)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:742)
stopped abnormal

second run freezes

rut@dev-bot:~/test/WSTest$ java -jar build/libs/WSTest.jar
start
try #0

@e5l
Copy link
Member

e5l commented Feb 20, 2019

The exception related to double close call and fixed in e5l/develop.

Generally, it looks like we try to reuse the connection in case of an exception. Trying to reproduce it without WebSockets.

Great thanks for the investigation.

@e5l
Copy link
Member

e5l commented Mar 19, 2019

Could you reproduce it with 1.2.0-alpha-2?

@coolemza
Copy link
Author

1.1.4 still freezes

@e5l
Copy link
Member

e5l commented May 27, 2019

We fix close process with 1.2.0. Could you still reproduce it?

@e5l
Copy link
Member

e5l commented Jun 5, 2019

Closed. Please reopen if the problem is active.

@e5l e5l closed this as completed Jun 5, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants