WebSocket extensions API

    The API is production ready, but may be slightly modified in a minor release. This is why it’s marked with the annotation. If you want to use this API you need to OptIn:

    If you want to leave your feedback or subscribe on updates, check KTOR-688 design issue.

    To install and configure the extensions we provide two methods: extensions and install which can be used in the following way:

    1. install(WebSockets) {
    2. extensions { /* WebSocketExtensionConfig.() -> Unit */
    3. install(MyWebSocketExtension) { /* MyWebSocketExtensionConfig.() -> Unit */
    4. /* Optional extension configuration. */
    5. }
    6. }
    7. }

    All installed extensions go through the negotiation process, and those that are successfully negotiated are used during the request. You can use WebSocketSession.extensions: : List<WebSocketExtension<*>> property with list of all extensions used by for the current session.

    There are two methods to check if the extension is in use: WebSocketSession.extension and WebSocketSession.extensionOrNull:

    There are two interfaces for implementing a new extension: WebSocketExtension<ConfigType: Any> and . A single implementation can work for both clients and servers.

    1. class FrameLoggerExtension(val logger: Logger) : WebSocketExtension<FrameLogger.Config> {

    The feature has two groups of fields and methods. The first group is for extension negotiation:

    The second group is the place for actual frame processing. Methods will take a frame and produce a new processed frame if necessary:

    1. logger.log("Process outgoing frame: $frame")
    2. return frame
    3. }
    4. override fun processIncomingFrame(frame: Frame): Frame {
    5. logger.log("Process incoming frame: $frame")
    6. return frame
    7. }

    There are also some implementation details: the feature has Config and reference to the origin factory.

    1. companion object : WebSocketExtensionFactory<Config, FrameLogger> {
    2. /* Key to discover installed extension instance */
    3. /** List of occupied rsv bits.
    4. * If the extension occupy a bit, it can't be used in other installed extensions. We use that bits to prevent feature conflicts(prevent to install multiple compression features). If you implementing feature using some RFC, rsv occupied bits should be referenced there.
    5. */
    6. override val rsv1: Boolean = false
    7. override val rsv2: Boolean = false
    8. override val rsv3: Boolean = false
    9. /** Create feature instance. Will be called for each WebSocket session **/
    10. override fun install(config: Config.() -> Unit): FrameLogger {
    11. return FrameLogger(Config().apply(config).logger)
    12. }
    13. }