home

Does HTTP 1.1 Support Full Duplex Communication?

Surprisingly enough, I think the answer is Yes. Chunked transfer encoding allows a client to upload chunks of data to the server. It also allows a server to download chunks of data to the client. I think it is valid for them to do this at the same time. The client has to initiate the connection, but the server can begin sending chunks of data while still reading chunks from the client. Even though HTTP is traditionally thought of as a request-response protocol, you can actually get bi-directional full-duplex communication.

demo

I discuss some aspects of sending and receiving streamed data over http in my previous article about pipeto.me. For clarification, I am talking only about HTTP 1.1. I believe HTTP 2 supports this much more explicitly, but I haven’t explored it in depth.

Even though this behavior is technically valid, support for it among HTTP clients and servers seems shoddy at best:

Go: I was able to able to add server side support for this in pipeto.me using only Go’s http package.

C# .Net: I also tried to use .Net’s HttpClient class. It seems, however, to close it’s input stream after it starts reading the response.

Javascript (Chrome): The javascript ReadableStream API, when combined with fetch, seems like it should support bidirectional streaming. It does work today on the recieve side. There is an open chrome issue (here) to support the sending side. However, there is discussion (here) that seems to indicate that bidirectional streaming is not on the table.

Node: The http module in node seems to work really well in this way. If you’d like to try out HTTP 1.1 full duplex communication, go over to https://pipeto.me and grab a random pipe address. With node installed, paste the following code into two different terminals.

node -e "
const http = require('https');
var req = http.request(process.argv[1], {
    method: 'PUT',
    headers: { 'Expect': '100-continue' }
}, resp => resp.pipe(process.stdout));
process.stdin.pipe(req);
" https://pipeto.me/<random_key>

You should now be able to chat back and forth between your terminals, each one sending and receiving over a single http connection.

Curl: I was blocked testing curl due to a known issue related to how it handled stdin. I actually submitted a pull request to fix the issue. In the next release of curl (7.68) you should be able to do following in two separate terminals and chat between them.

curl -T. https://pipeto.me/<random_key>

Should I use this in Production?

Probably not. You are probably better served by either websockets or server sent events. Server sent events are similar in spirit, but both these methods allow message framing and browser javascript support. It is, however, certainly an interesting academic exercise.

Further Reading:

2019-10-31