Transparent Proxy for Broadway ( Gtk3 / HTML5 backend )

I’m a big fan of Gtk+. One of the interesting additions since version 3 is the ‘broadway’ backend. Broadway is a rendering backend that lets you distribute your Gtk+ app via a browser. It does this by serving up a simple page with an HTML5 canvas and some Javascript, and then pushes GUI updates over web sockets. It’s an intriguing approach, and very useful if you need to distribute to a bunch of people without installing dependencies ( which is still painful on Windows ).

There are some shortfalls of the broadway component. It only supports a single client per broadway process. If a 2nd client connects to the port broadway is listening on, the 1st client gets disconnected. There is only very simple authentication offered, which is set on a per-user ( ie Linux user ) basis. These 2 issues make it difficult to use broadway in a production environment.

While I hope Gtk+ people will flesh out broadway functionality further, I’ve managed to bring up a proof-of-concept transparent proxy for broadway that goes a long way to addressing the above issues. Here’s how I currently have things working:

  • A simple authentication page at /auth does application logins. I’ve implemented this in PHP, just to remind myself how much I hate it 🙂 Successful logins result in:
    • A new broadwayd process being launched on an available port
    • A new instance of my Gtk+ app being launched, and directed to use the new broadway process we just launched
    • A new random string ( $random_string ) being generated ( eg 20 characters )
    • A cookie being set, auth_key=$random_string
    • A database entry being created that maps the auth_key values to broadway ports – this is timestamped and gets culled regularly
    • Finally, the web client is redirected to /app
  • An nginx reverse proxy that adds https termination, and forwards requests to /app to the port that the transparent proxy is listening on ( I use 10666 )

Next … the proxy code:

This code is originally by Peteris Krumins ( details in the code ). I’ve modified it slightly, adding the concept of a ‘ConnectionFuture’, which doesn’t need to know ‘in advance’ where a connection is being proxied to.

All the magic happens in the syswrite() method. I pass the incoming buffer to HTTP::Request, so I can parse out the cookie ( if one exists ). You’ll see in the code I then look for a cookie named ‘port’:

if ( $cookies =~ /port=(\w*)/ ) {
    $port = $1;
} elsif ( $cookies = 'cookie1=test' ) {
    $port = 10000;

This is obviously a simplification that is looking for the port number directly in the cookie. There is also a check for a cookie named ‘cookie1’, which is hard-coded to port 10000. I’ve done this in the example code so you can quickly verify that the general approach will work for you. You should remove this whole block, and replace with some logic that looks for the auth_key cookie, checks in the database that it exists, fetches the correct port, and sets $port accordingly. As this will depend a lot on your particular environment, I’ve left it as an exercise for the viewer 🙂 You should also add some cleanup code in disconnect() to kill the app process, broadway process, and delete the database entry for the auth_key and port.

There are most likely bugs ( eg we should explicitly disconnect clients that don’t have our cookie, or redirect them to /auth ).

I wondered what performance would be like, with the proxying code having to inspect each incoming request to determine where to redirect it. It’s actually extremely efficient. As luck would have it, there are only a couple of ‘requests’ for the entire duration of a Gtk+ / broadway application. The 1st couple of requests fetch the html and javascript. After that, as the connection is ‘upgraded’ to websockets, all subsequent traffic exists as a part of the same ‘request’, so interacting with the application once it’s started performs as well as a direct broadway connection ( ie no proxy ). There is very low CPU usage for me.

Hopefully this is useful to someone who likes Gtk+ and is looking for a secure way of deploying apps via broadway. Hopefully it also inspires someone more handy in C that I am to implement something like the above in the broadway component itself.