Is there a way to set response headers for a webso...
# ktor
a
Is there a way to set response headers for a websocket route?
h
You can intercept the application send pipeline transformation and check if it's WebSocketUpgrade then append a header if that's what you asked sendPipeline.intercept(ApplicationSendPipelne.Transform) { body -> if (body is WebSocketUpgrade) { call.response.headers. } } Sorry for format it's from phone Otherwise if you're trying to set a one that's predefined there's client.websocket(request lambda then you can add headers here) client.webSocket(host, route, method, request = { header() }
a
> You can intercept the application send pipeline transformation and check if it's WebSocketUpgrade then append a header if that's what you asked That might work but i have a library module that just provides custom route type on top of websockets so i dont think i have an access for pipline transformation. That route needs to add a Set-Cookie header for every websocket upgrade. There might be other websocket routes that have or have not to set this header. I'm not sure if it even possible to include cookies to the protocol upgrades > client.webSocket( request = { header() } I only need it for a ktor server responces
h
Maybe something like this fun Route.customWebSocket( path: String, protocol: String, handler: suspend DefaultWebScketServerSession.() -> Unit ) { route(path) { get { call.response.cookies.append( Cookie( name = value = httpOnly = Etc.) call.respondWebSocketUpgrade(protocol, handler) } } } I'm still from phone so this is top of my head
Then you can use it as route { customWebSocket("/ws") { handler }
a
You can use the following method to create a WebSockets route with the provided headers in the response for the upgrade request:
Copy code
fun Route.webSocketWithHeaders(path: String, headers: Headers, block: suspend WebSocketServerSession.() -> Unit) {
    route(path) {
        header(HttpHeaders.Connection, "Upgrade") {
            header(HttpHeaders.Upgrade, "websocket") {
                get {
                    headers.forEach { name, values ->
                        call.response.headers.appendIfAbsent(name, values.joinToString(separator = ", "))
                    }

                    call.respond(WebSocketUpgrade(call, null, installExtensions = true, {
                        val session = toServerSession(call)
                        session.block()
                    }))
                }
            }
        }
    }
}

private fun WebSocketSession.toServerSession(call: ApplicationCall): WebSocketServerSession =
    DelegatedWebSocketServerSession(call, this)

private fun DefaultWebSocketSession.toServerSession(call: ApplicationCall): DefaultWebSocketServerSession =
    DelegatedDefaultWebSocketServerSession(call, this)

private class DelegatedWebSocketServerSession(
    override val call: ApplicationCall,
    val delegate: WebSocketSession
) : WebSocketServerSession, WebSocketSession by delegate

private class DelegatedDefaultWebSocketServerSession(
    override val call: ApplicationCall,
    val delegate: DefaultWebSocketSession
) : DefaultWebSocketServerSession, DefaultWebSocketSession by delegate
Here is how it can be used:
Copy code
routing {
    webSocketWithHeaders("/ws", Headers.build {
        append(HttpHeaders.SetCookie, "name=value; path=/")
    }) {
        outgoing.send(Frame.Text("Hello World!"))
    }
}
a
Thanks. This one worked for me, a bit simpler:
Copy code
fun Route.customRoute(path : String){

    route(path, HttpMethod.Get) {
        header(HttpHeaders.Connection, "Upgrade") {
            header(HttpHeaders.Upgrade, "websocket") {
                handle {
                    call.response.headers.append()
                }
            }
        }
    }

    webSocket(path) {
        // ...
    }
}
K 1