RawHTTP Duplex

Javadocs

The rawhttp-duplex module can be used to create a duplex communication channel as either a client or a server.

The entry point of the library is the com.athaydes.rawhttp.duplex.RawHttpDuplex class.

Its connect methods are used from a client to connect to a server, while the accept methods should be used within a HTTP server to handle requests from a client.

Example Kotlin code on the server:

import rawhttp.core.*
import com.athaydes.rawhttp.duplex.*
import rawhttp.core.server.TcpRawHttpServer;

val http = RawHttp()
val duplex = RawHttpDuplex()
val server = TcpRawHttpServer(8082)

server.start { request ->
    // TODO check the request is a POST to the /connect path!
    // call duplex.accept() to return a response that can initiate duplex communication
    Optional.of(duplex.accept(request, { sender ->
        object : MessageHandler {
            override fun onTextMessage(message: String) {
                // handle text message 
                sender.sendTextMessage("Hi there! You sent this: $message")
            }      
            override fun onBinaryMessage(message: ByteArray, headers: RawHttpHeaders) { /* handle binary message */ }
            override fun onClose() { /* handle closed connection */ }
        }
    }))
}

Example Kotlin code on the client:

import rawhttp.core.*
import com.athaydes.rawhttp.duplex.*
import rawhttp.core.server.TcpRawHttpServer;

val http = RawHttp()
val duplex = RawHttpDuplex()

duplex.connect(http.parseRequest("POST http://localhost:8082/connect"), { sender ->
    object : MessageHandler { /* same API as on the server */ }
}

How duplex works

The way duplex communication is achieved uses only HTTP/1.1 standard mechanisms and can be described as follows:

In other words, a single request/response is used to bootstrap communications. Both the request and the response have effectively infinite chunked bodies where each chunk represents a message.

RawHttpDuplex sends a single extension parameter to idenfity text messages: Content-Type: text/plain (notice that each chunk may contain “extensions”).

If the chunk does not contain this extension, then it is considered to be a binary message.

Text messages may also contain the Charset: <charset> (e.g. Charset: US-ASCII) extension parameter to provide a charset for the message. By default, UTF-8 is used.

Each side of a connection pings the other every 5 seconds, by default, to avoid the TCP socket timing out. To use a different ping period, use the {@link RawHttpDuplex#RawHttpDuplex(TcpRawHttpClient, Duration)} constructor.

Demo

As is mandatory for duplex communication implementations, a Chat Demo application was written in Kotlin to demonstrate usage of this library.

The video below shows it in action: